From 9926b33276cb3a349952d8d47a5d8b17bbb3cbdf Mon Sep 17 00:00:00 2001 From: Caleb Jones Date: Wed, 20 Jul 2016 18:23:52 -0400 Subject: [PATCH 001/443] Fix overflow checking in unsigned pow() The pow() method for unsigned integers produced 0 instead of trapping overflow for certain inputs. Calls such as 2u32.pow(1024) produced 0 when they should trap an overflow. This also adds tests for the correctly handling overflow in unsigned pow(). For issue number #34913 --- src/libcore/num/mod.rs | 26 ++++++++----------- ...owing-pow.rs => overflowing-pow-signed.rs} | 0 src/test/run-fail/overflowing-pow-unsigned.rs | 16 ++++++++++++ 3 files changed, 27 insertions(+), 15 deletions(-) rename src/test/run-fail/{overflowing-pow.rs => overflowing-pow-signed.rs} (100%) create mode 100644 src/test/run-fail/overflowing-pow-unsigned.rs diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 4636811aa46d..1032826a0935 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -2217,25 +2217,21 @@ macro_rules! uint_impl { let mut base = self; let mut acc = 1; - let mut prev_base = self; - let mut base_oflo = false; - while exp > 0 { + while exp > 1 { if (exp & 1) == 1 { - if base_oflo { - // ensure overflow occurs in the same manner it - // would have otherwise (i.e. signal any exception - // it would have otherwise). - acc = acc * (prev_base * prev_base); - } else { - acc = acc * base; - } + acc = acc * base; } - prev_base = base; - let (new_base, new_base_oflo) = base.overflowing_mul(base); - base = new_base; - base_oflo = new_base_oflo; exp /= 2; + base = base * base; } + + // Deal with the final bit of the exponent separately, since + // squaring the base afterwards is not necessary and may cause a + // needless overflow. + if exp == 1 { + acc = acc * base; + } + acc } diff --git a/src/test/run-fail/overflowing-pow.rs b/src/test/run-fail/overflowing-pow-signed.rs similarity index 100% rename from src/test/run-fail/overflowing-pow.rs rename to src/test/run-fail/overflowing-pow-signed.rs diff --git a/src/test/run-fail/overflowing-pow-unsigned.rs b/src/test/run-fail/overflowing-pow-unsigned.rs new file mode 100644 index 000000000000..5dca7795462e --- /dev/null +++ b/src/test/run-fail/overflowing-pow-unsigned.rs @@ -0,0 +1,16 @@ +// 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. + +// error-pattern:thread 'main' panicked at 'attempted to multiply with overflow' +// compile-flags: -C debug-assertions + +fn main() { + let _x = 2u32.pow(1024); +} From b8c4e9c235db5f67129abdae8f336e06bf2bc8ba Mon Sep 17 00:00:00 2001 From: Caleb Jones Date: Sat, 6 Aug 2016 23:58:16 -0400 Subject: [PATCH 002/443] Change the expected panic message for unsigned --- src/test/run-fail/overflowing-pow-unsigned.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/run-fail/overflowing-pow-unsigned.rs b/src/test/run-fail/overflowing-pow-unsigned.rs index 5dca7795462e..d3e7035279fb 100644 --- a/src/test/run-fail/overflowing-pow-unsigned.rs +++ b/src/test/run-fail/overflowing-pow-unsigned.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern:thread 'main' panicked at 'attempted to multiply with overflow' +// error-pattern:thread 'main' panicked at 'attempt to multiply with overflow' // compile-flags: -C debug-assertions fn main() { From 5be8df95c74514ade77c81a7afff1f4df3208bbd Mon Sep 17 00:00:00 2001 From: Mark-Simulacrum Date: Thu, 11 Aug 2016 15:42:41 -0600 Subject: [PATCH 003/443] Fix language in documentation comment. --- src/librustc_bitflags/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_bitflags/lib.rs b/src/librustc_bitflags/lib.rs index afc2e04d446a..7e96adfc4bdb 100644 --- a/src/librustc_bitflags/lib.rs +++ b/src/librustc_bitflags/lib.rs @@ -201,7 +201,7 @@ macro_rules! bitflags { !(*self & other).is_empty() } - /// Returns `true` all of the flags in `other` are contained within `self`. + /// Returns `true` if all of the flags in `other` are contained within `self`. #[inline] pub fn contains(&self, other: $BitFlags) -> bool { (*self & other) == other From 0384722357d4a6dcc2a1e79b41cf9f0df50cb577 Mon Sep 17 00:00:00 2001 From: QuietMisdreavus Date: Wed, 17 Aug 2016 11:49:28 -0500 Subject: [PATCH 004/443] Add `must_use` to the Reference --- src/doc/reference.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/doc/reference.md b/src/doc/reference.md index f0ab1488d401..d14322a0655c 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -2070,6 +2070,9 @@ macro scope. trait of the same name. `{Self}` will be replaced with the type that is supposed to implement the trait but doesn't. To use this, the `on_unimplemented` feature gate must be enabled. +- `must_use` - on structs and enums, will warn if a value of this type isn't used or + assigned to a variable. You may also include an optional message by using + `#[must_use = "message"]` which will be given alongside the warning. ### Conditional compilation From 4b87c7e3b419345e2d0fd35987a2e012b1e95a5e Mon Sep 17 00:00:00 2001 From: philipp Date: Sat, 20 Aug 2016 15:12:50 +0200 Subject: [PATCH 005/443] Introduce max_by/min_by on iterators --- src/libcore/iter/iterator.rs | 51 ++++++++++++++++++++++++++++++++++++ src/libcoretest/iter.rs | 12 +++++++++ src/libcoretest/lib.rs | 2 ++ 3 files changed, 65 insertions(+) diff --git a/src/libcore/iter/iterator.rs b/src/libcore/iter/iterator.rs index 6b01ccaceea2..e25920fae074 100644 --- a/src/libcore/iter/iterator.rs +++ b/src/libcore/iter/iterator.rs @@ -1664,6 +1664,31 @@ pub trait Iterator { .map(|(_, x)| x) } + /// Returns the element that gives the maximum value with respect to the + /// specified comparison function. + /// + /// Returns the rightmost element if the comparison determines two elements + /// to be equally maximum. + /// + /// # Examples + /// + /// ``` + /// let a = [-3_i32, 0, 1, 5, -10]; + /// assert_eq!(*a.iter().max_by(|x, y| x.cmp(y)).unwrap(), 5); + /// ``` + #[inline] + #[unstable(feature = "iter_max_by", issue="1722")] + fn max_by(self, mut compare: F) -> Option + where Self: Sized, F: FnMut(&Self::Item, &Self::Item) -> Ordering, + { + select_fold1(self, + |_| (), + // switch to y even if it is only equal, to preserve + // stability. + |_, x, _, y| Ordering::Greater != compare(x, y)) + .map(|(_, x)| x) + } + /// Returns the element that gives the minimum value from the /// specified function. /// @@ -1688,6 +1713,32 @@ pub trait Iterator { .map(|(_, x)| x) } + /// Returns the element that gives the minimum value with respect to the + /// specified comparison function. + /// + /// Returns the latest element if the comparison determines two elements + /// to be equally minimum. + /// + /// # Examples + /// + /// ``` + /// let a = [-3_i32, 0, 1, 5, -10]; + /// assert_eq!(*a.iter().min_by(|x, y| x.cmp(y)).unwrap(), -10); + /// ``` + #[inline] + #[unstable(feature = "iter_min_by", issue="1722")] + fn min_by(self, mut compare: F) -> Option + where Self: Sized, F: FnMut(&Self::Item, &Self::Item) -> Ordering, + { + select_fold1(self, + |_| (), + // switch to y even if it is strictly smaller, to + // preserve stability. + |_, x, _, y| Ordering::Greater == compare(x, y)) + .map(|(_, x)| x) + } + + /// Reverses an iterator's direction. /// /// Usually, iterators iterate from left to right. After using `rev()`, diff --git a/src/libcoretest/iter.rs b/src/libcoretest/iter.rs index a2848faa105e..27eb25537f31 100644 --- a/src/libcoretest/iter.rs +++ b/src/libcoretest/iter.rs @@ -664,12 +664,24 @@ fn test_max_by_key() { assert_eq!(*xs.iter().max_by_key(|x| x.abs()).unwrap(), -10); } +#[test] +fn test_max_by() { + let xs: &[isize] = &[-3, 0, 1, 5, -10]; + assert_eq!(*xs.iter().max_by(|x, y| x.abs().cmp(&y.abs())).unwrap(), -10); +} + #[test] fn test_min_by_key() { let xs: &[isize] = &[-3, 0, 1, 5, -10]; assert_eq!(*xs.iter().min_by_key(|x| x.abs()).unwrap(), 0); } +#[test] +fn test_min_by() { + let xs: &[isize] = &[-3, 0, 1, 5, -10]; + assert_eq!(*xs.iter().min_by(|x, y| x.abs().cmp(&y.abs())).unwrap(), 0); +} + #[test] fn test_by_ref() { let mut xs = 0..10; diff --git a/src/libcoretest/lib.rs b/src/libcoretest/lib.rs index 9428b4096bfe..b4c94509477a 100644 --- a/src/libcoretest/lib.rs +++ b/src/libcoretest/lib.rs @@ -33,6 +33,8 @@ #![feature(try_from)] #![feature(unicode)] #![feature(unique)] +#![feature(iter_max_by)] +#![feature(iter_min_by)] extern crate core; extern crate test; From dfeb20ce60b288d62796e17831f4d5cadf6afadf Mon Sep 17 00:00:00 2001 From: philipp Date: Sun, 21 Aug 2016 13:23:39 +0200 Subject: [PATCH 006/443] Added #![feature] declarations --- src/libcore/iter/iterator.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libcore/iter/iterator.rs b/src/libcore/iter/iterator.rs index e25920fae074..48ea306ce5fd 100644 --- a/src/libcore/iter/iterator.rs +++ b/src/libcore/iter/iterator.rs @@ -1673,6 +1673,7 @@ pub trait Iterator { /// # Examples /// /// ``` + /// #![feature(iter_max_by)] /// let a = [-3_i32, 0, 1, 5, -10]; /// assert_eq!(*a.iter().max_by(|x, y| x.cmp(y)).unwrap(), 5); /// ``` @@ -1722,6 +1723,7 @@ pub trait Iterator { /// # Examples /// /// ``` + /// #![feature(iter_min_by)] /// let a = [-3_i32, 0, 1, 5, -10]; /// assert_eq!(*a.iter().min_by(|x, y| x.cmp(y)).unwrap(), -10); /// ``` From cfce351ad39ae0f5e35006ad11fabb4ec866d725 Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Tue, 23 Aug 2016 07:40:51 +0200 Subject: [PATCH 007/443] first attempt at implementing RFC 1623. This fixes #35897. This is a work in progress. In particular, I want to add more tests, especially the compile-fail test is very bare-bones. --- src/librustc_typeck/collect.rs | 2 +- src/test/compile-fail/rfc1623.rs | 21 +++++++++++++ src/test/run-pass/rfc1623.rs | 52 ++++++++++++++++++++++++++++++++ 3 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 src/test/compile-fail/rfc1623.rs create mode 100644 src/test/run-pass/rfc1623.rs diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 7e1fb32881d6..0f48b7ca67e6 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1554,7 +1554,7 @@ fn type_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, NodeItem(item) => { match item.node { ItemStatic(ref t, _, _) | ItemConst(ref t, _) => { - ccx.icx(&()).to_ty(&ExplicitRscope, &t) + ccx.icx(&()).to_ty(&ElidableRscope::new(ty::ReStatic), &t) } ItemFn(ref decl, unsafety, _, abi, ref generics, _) => { let tofd = AstConv::ty_of_bare_fn(&ccx.icx(generics), unsafety, abi, &decl, diff --git a/src/test/compile-fail/rfc1623.rs b/src/test/compile-fail/rfc1623.rs new file mode 100644 index 000000000000..dfe58f0d94cc --- /dev/null +++ b/src/test/compile-fail/rfc1623.rs @@ -0,0 +1,21 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(dead_code)] + +fn non_elidable<'a, 'b>(a: &'a u8, b: &'b u8) -> &'a u8 { a } + +// the boundaries of elision +static NON_ELIDABLE_FN : &fn(&u8, &u8) -> &u8 = non_elidable; +//~^ERROR: missing lifetime specifier + +fn main() { + // nothing to do here +} diff --git a/src/test/run-pass/rfc1623.rs b/src/test/run-pass/rfc1623.rs new file mode 100644 index 000000000000..b702a03b481f --- /dev/null +++ b/src/test/run-pass/rfc1623.rs @@ -0,0 +1,52 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(dead_code)] + +// very simple test for a 'static static with default lifetime +static SOME_STATIC_STR : &str = "&'static str"; +const SOME_CONST_STR : &str = "&'static str"; + +// this should be the same as without default: +static SOME_EXPLICIT_STATIC_STR : &'static str = "&'static str"; +const SOME_EXPLICIT_CONST_STR : &'static str = "&'static str"; + +// a function that elides to an unbound lifetime for both in- and output +fn id_u8_slice(arg: &[u8]) -> &[u8] { arg } + +// one with a function, argument elided +static SOME_STATIC_SIMPLE_FN : &fn(&[u8]) -> &[u8] = id_u8_slice; +const SOME_CONST_SIMPLE_FN : &fn(&[u8]) -> &[u8] = id_u8_slice; + +// this should be the same as without elision +static SOME_STATIC_NON_ELIDED_fN : &fn<'a>(&'a [u8]) -> &'a [u8] = id_u8_slice; +const SOME_CONST_NON_ELIDED_fN : &fn<'a>(&'a [u8]) -> &'a [u8] = id_u8_slice; + +// another function that elides, each to a different unbound lifetime +fn multi_args(a: &u8, b: &u8, c: &u8) { } + +static SOME_STATIC_MULTI_FN : &fn(&u8, &u8, &u8) = multi_args; +const SOME_CONST_MULTI_FN : &fn(&u8, &u8, &u8) = multi_args; + + +fn main() { + // make sure that the lifetime is actually elided (and not defaulted) + let x = &[1u8, 2, 3]; + SOME_STATIC_SIMPLE_FN(x); + SOME_CONST_SIMPLE_FN(x); + + // make sure this works with different lifetimes + let a = &1; + { + let b = &2; + let c = &3; + SOME_CONST_MULTI_FN(a, b, c); + } +} From 8bdb3e10ca637033667dec25ebfff64a069c46eb Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Tue, 23 Aug 2016 12:34:28 +0200 Subject: [PATCH 008/443] fix run-pass test --- src/test/run-pass/rfc1623.rs | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/test/run-pass/rfc1623.rs b/src/test/run-pass/rfc1623.rs index b702a03b481f..81e32efe6c77 100644 --- a/src/test/run-pass/rfc1623.rs +++ b/src/test/run-pass/rfc1623.rs @@ -22,18 +22,24 @@ const SOME_EXPLICIT_CONST_STR : &'static str = "&'static str"; fn id_u8_slice(arg: &[u8]) -> &[u8] { arg } // one with a function, argument elided -static SOME_STATIC_SIMPLE_FN : &fn(&[u8]) -> &[u8] = id_u8_slice; -const SOME_CONST_SIMPLE_FN : &fn(&[u8]) -> &[u8] = id_u8_slice; +static SOME_STATIC_SIMPLE_FN : &fn(&[u8]) -> &[u8] = + &(id_u8_slice as fn(&[u8]) -> &[u8]); +const SOME_CONST_SIMPLE_FN : &fn(&[u8]) -> &[u8] = + &(id_u8_slice as fn(&[u8]) -> &[u8]); // this should be the same as without elision -static SOME_STATIC_NON_ELIDED_fN : &fn<'a>(&'a [u8]) -> &'a [u8] = id_u8_slice; -const SOME_CONST_NON_ELIDED_fN : &fn<'a>(&'a [u8]) -> &'a [u8] = id_u8_slice; +static SOME_STATIC_NON_ELIDED_fN : &for<'a> fn(&'a [u8]) -> &'a [u8] = + &(id_u8_slice as for<'a> fn(&'a [u8]) -> &'a [u8]); +const SOME_CONST_NON_ELIDED_fN : &for<'a> fn(&'a [u8]) -> &'a [u8] = + &(id_u8_slice as for<'a> fn(&'a [u8]) -> &'a [u8]); // another function that elides, each to a different unbound lifetime fn multi_args(a: &u8, b: &u8, c: &u8) { } -static SOME_STATIC_MULTI_FN : &fn(&u8, &u8, &u8) = multi_args; -const SOME_CONST_MULTI_FN : &fn(&u8, &u8, &u8) = multi_args; +static SOME_STATIC_MULTI_FN : &fn(&u8, &u8, &u8) = + &(multi_args as fn(&u8, &u8, &u8)); +const SOME_CONST_MULTI_FN : &fn(&u8, &u8, &u8) = + &(multi_args as fn(&u8, &u8, &u8)); fn main() { @@ -41,7 +47,7 @@ fn main() { let x = &[1u8, 2, 3]; SOME_STATIC_SIMPLE_FN(x); SOME_CONST_SIMPLE_FN(x); - + // make sure this works with different lifetimes let a = &1; { From a6b9fea5cd10afe9d7b81d30b2b082f727aea255 Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Tue, 23 Aug 2016 12:38:09 +0200 Subject: [PATCH 009/443] fixed compile-fail test --- src/test/compile-fail/rfc1623.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/test/compile-fail/rfc1623.rs b/src/test/compile-fail/rfc1623.rs index dfe58f0d94cc..a52b9c596aa9 100644 --- a/src/test/compile-fail/rfc1623.rs +++ b/src/test/compile-fail/rfc1623.rs @@ -13,8 +13,9 @@ fn non_elidable<'a, 'b>(a: &'a u8, b: &'b u8) -> &'a u8 { a } // the boundaries of elision -static NON_ELIDABLE_FN : &fn(&u8, &u8) -> &u8 = non_elidable; +static NON_ELIDABLE_FN : &fn(&u8, &u8) -> &u8 = //~^ERROR: missing lifetime specifier + &(non_elidable as fn(&u8, &u8) -> &u8); fn main() { // nothing to do here From e0eb1ba0db9c832a0385f31710edddd675feee14 Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Tue, 23 Aug 2016 21:36:19 +0200 Subject: [PATCH 010/443] fixed and extended tests, however... MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ...there is still one confusing thing – see the _BAZ functions, which appear to be elided in the `compile-fail` test and defaulted in the ´run-pass` test (if you uncomment line 73). --- src/test/compile-fail/rfc1623.rs | 17 +++++++++-- src/test/run-pass/rfc1623.rs | 50 +++++++++++++++++++++++--------- 2 files changed, 51 insertions(+), 16 deletions(-) diff --git a/src/test/compile-fail/rfc1623.rs b/src/test/compile-fail/rfc1623.rs index a52b9c596aa9..840307ea456e 100644 --- a/src/test/compile-fail/rfc1623.rs +++ b/src/test/compile-fail/rfc1623.rs @@ -13,10 +13,21 @@ fn non_elidable<'a, 'b>(a: &'a u8, b: &'b u8) -> &'a u8 { a } // the boundaries of elision -static NON_ELIDABLE_FN : &fn(&u8, &u8) -> &u8 = -//~^ERROR: missing lifetime specifier +static NON_ELIDABLE_FN : &fn(&u8, &u8) -> &u8 = +//^ERROR: missing lifetime specifier &(non_elidable as fn(&u8, &u8) -> &u8); +type Baz<'a> = fn(&'a [u8]) -> Option; + +fn baz(e: &[u8]) -> Option { e.first().map(|x| *x) } + +static STATIC_BAZ : &Baz<'static> = &(baz as Baz); +const CONST_BAZ : &Baz<'static> = &(baz as Baz); + fn main() { - // nothing to do here + let y = [1u8, 2, 3]; + + //surprisingly this appears to work, so lifetime < `'static` is valid + assert_eq!(Some(1), STATIC_BAZ(y)); + assert_eq!(Some(1), CONST_BAZ(y)); } diff --git a/src/test/run-pass/rfc1623.rs b/src/test/run-pass/rfc1623.rs index 81e32efe6c77..bd0420bb5067 100644 --- a/src/test/run-pass/rfc1623.rs +++ b/src/test/run-pass/rfc1623.rs @@ -11,48 +11,72 @@ #![allow(dead_code)] // very simple test for a 'static static with default lifetime -static SOME_STATIC_STR : &str = "&'static str"; -const SOME_CONST_STR : &str = "&'static str"; +static STATIC_STR : &str = "&'static str"; +const CONST_STR : &str = "&'static str"; // this should be the same as without default: -static SOME_EXPLICIT_STATIC_STR : &'static str = "&'static str"; -const SOME_EXPLICIT_CONST_STR : &'static str = "&'static str"; +static EXPLICIT_STATIC_STR : &'static str = "&'static str"; +const EXPLICIT_CONST_STR : &'static str = "&'static str"; // a function that elides to an unbound lifetime for both in- and output fn id_u8_slice(arg: &[u8]) -> &[u8] { arg } // one with a function, argument elided -static SOME_STATIC_SIMPLE_FN : &fn(&[u8]) -> &[u8] = +static STATIC_SIMPLE_FN : &fn(&[u8]) -> &[u8] = &(id_u8_slice as fn(&[u8]) -> &[u8]); -const SOME_CONST_SIMPLE_FN : &fn(&[u8]) -> &[u8] = +const CONST_SIMPLE_FN : &fn(&[u8]) -> &[u8] = &(id_u8_slice as fn(&[u8]) -> &[u8]); // this should be the same as without elision -static SOME_STATIC_NON_ELIDED_fN : &for<'a> fn(&'a [u8]) -> &'a [u8] = +static STATIC_NON_ELIDED_fN : &for<'a> fn(&'a [u8]) -> &'a [u8] = &(id_u8_slice as for<'a> fn(&'a [u8]) -> &'a [u8]); -const SOME_CONST_NON_ELIDED_fN : &for<'a> fn(&'a [u8]) -> &'a [u8] = +const CONST_NON_ELIDED_fN : &for<'a> fn(&'a [u8]) -> &'a [u8] = &(id_u8_slice as for<'a> fn(&'a [u8]) -> &'a [u8]); // another function that elides, each to a different unbound lifetime fn multi_args(a: &u8, b: &u8, c: &u8) { } -static SOME_STATIC_MULTI_FN : &fn(&u8, &u8, &u8) = +static STATIC_MULTI_FN : &fn(&u8, &u8, &u8) = &(multi_args as fn(&u8, &u8, &u8)); -const SOME_CONST_MULTI_FN : &fn(&u8, &u8, &u8) = +const CONST_MULTI_FN : &fn(&u8, &u8, &u8) = &(multi_args as fn(&u8, &u8, &u8)); +struct Foo<'a> { + bools: &'a [bool] +} + +static STATIC_FOO : Foo = Foo { bools: &[true, false] }; +const CONST_FOO : Foo = Foo { bools: &[true, false] }; + +type Bar<'a> = Foo<'a>; + +static STATIC_BAR : Bar = Bar { bools: &[true, false] }; +const CONST_BAR : Bar = Bar { bools: &[true, false] }; + +type Baz<'a> = fn(&'a [u8]) -> Option; + +fn baz(e: &[u8]) -> Option { e.first().map(|x| *x) } + +static STATIC_BAZ : &Baz = &(baz as Baz); +const CONST_BAZ : &Baz = &(baz as Baz); + +static BYTES : &[u8] = &[1, 2, 3]; fn main() { // make sure that the lifetime is actually elided (and not defaulted) let x = &[1u8, 2, 3]; - SOME_STATIC_SIMPLE_FN(x); - SOME_CONST_SIMPLE_FN(x); + STATIC_SIMPLE_FN(x); + CONST_SIMPLE_FN(x); + + let y = &[1u8, 2, 3]; + STATIC_BAZ(BYTES); + //CONST_BAZ(y); // strangely enough, this fails // make sure this works with different lifetimes let a = &1; { let b = &2; let c = &3; - SOME_CONST_MULTI_FN(a, b, c); + CONST_MULTI_FN(a, b, c); } } From 1fd85b1a80429a5d217424b2e7f51d0082713b9d Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Wed, 24 Aug 2016 21:19:39 +0200 Subject: [PATCH 011/443] fixed compile-fail test --- src/test/compile-fail/rfc1623.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/test/compile-fail/rfc1623.rs b/src/test/compile-fail/rfc1623.rs index 840307ea456e..963459b27bf1 100644 --- a/src/test/compile-fail/rfc1623.rs +++ b/src/test/compile-fail/rfc1623.rs @@ -14,7 +14,7 @@ fn non_elidable<'a, 'b>(a: &'a u8, b: &'b u8) -> &'a u8 { a } // the boundaries of elision static NON_ELIDABLE_FN : &fn(&u8, &u8) -> &u8 = -//^ERROR: missing lifetime specifier +//~^ ERROR: missing lifetime specifier &(non_elidable as fn(&u8, &u8) -> &u8); type Baz<'a> = fn(&'a [u8]) -> Option; @@ -25,7 +25,8 @@ static STATIC_BAZ : &Baz<'static> = &(baz as Baz); const CONST_BAZ : &Baz<'static> = &(baz as Baz); fn main() { - let y = [1u8, 2, 3]; + let x = &[1u8, 2, 3]; + let y = x; //surprisingly this appears to work, so lifetime < `'static` is valid assert_eq!(Some(1), STATIC_BAZ(y)); From ced1252654d9f589867a410d4c0c7328484d95c7 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Fri, 26 Aug 2016 10:59:46 -0700 Subject: [PATCH 012/443] Introduce `into_inner` method on `std::io::Take`. https://github.com/rust-lang/rust/issues/23755 --- src/libstd/io/mod.rs | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index 1053792cd439..06609cfad152 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -1501,6 +1501,33 @@ impl Take { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn limit(&self) -> u64 { self.limit } + + /// Consumes the `Take`, returning the wrapped reader. + /// + /// # Examples + /// + /// ``` + /// #![feature(io_take_into_inner)] + /// + /// use std::io; + /// use std::io::prelude::*; + /// use std::fs::File; + /// + /// # fn foo() -> io::Result<()> { + /// let mut file = try!(File::open("foo.txt")); + /// + /// let mut buffer = [0; 5]; + /// let mut handle = file.take(5); + /// try!(handle.read(&mut buffer)); + /// + /// let file = handle.into_inner(); + /// # Ok(()) + /// # } + /// ``` + #[unstable(feature = "io_take_into_inner", issue = "0")] + pub fn into_inner(self) -> T { + self.inner + } } #[stable(feature = "rust1", since = "1.0.0")] From 6a5bdb78f15b8e53fa848e31c90298edf6c48d6c Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 26 Aug 2016 17:06:13 -0500 Subject: [PATCH 013/443] add mips64-gnu and mips64el-gnu targets With this commit one can build no_core (and probably no_std as well) Rust programs for these targets. It's not yet possible to cross compile std for these targets because rust-lang/libc doesn't know about the mips64 architecture. These targets have been tested by cross compiling the "smallest hello" program (see code below) and then running it under QEMU. ``` rust #![feature(start)] #![feature(lang_items)] #![feature(no_core)] #![no_core] #[link(name = "c")] extern { fn puts(_: *const u8); } #[start] fn start(_: isize, _: *const *const u8) -> isize { unsafe { let msg = b"Hello, world!\0"; puts(msg as *const _ as *const u8); } 0 } #[lang = "copy"] trait Copy {} #[lang = "sized"] trait Sized {} ``` --- mk/cfg/mips64-unknown-linux-gnuabi64.mk | 1 + mk/cfg/mips64el-unknown-linux-gnuabi64.mk | 1 + .../target/mips64_unknown_linux_gnuabi64.rs | 31 ++++ .../target/mips64el_unknown_linux_gnuabi64.rs | 31 ++++ src/librustc_back/target/mod.rs | 2 + src/librustc_trans/abi.rs | 2 + src/librustc_trans/cabi_mips64.rs | 168 ++++++++++++++++++ src/librustc_trans/cabi_powerpc.rs | 12 +- src/librustc_trans/lib.rs | 1 + 9 files changed, 239 insertions(+), 10 deletions(-) create mode 100644 mk/cfg/mips64-unknown-linux-gnuabi64.mk create mode 100644 mk/cfg/mips64el-unknown-linux-gnuabi64.mk create mode 100644 src/librustc_back/target/mips64_unknown_linux_gnuabi64.rs create mode 100644 src/librustc_back/target/mips64el_unknown_linux_gnuabi64.rs create mode 100644 src/librustc_trans/cabi_mips64.rs diff --git a/mk/cfg/mips64-unknown-linux-gnuabi64.mk b/mk/cfg/mips64-unknown-linux-gnuabi64.mk new file mode 100644 index 000000000000..34aee77ae210 --- /dev/null +++ b/mk/cfg/mips64-unknown-linux-gnuabi64.mk @@ -0,0 +1 @@ +# rustbuild-only target diff --git a/mk/cfg/mips64el-unknown-linux-gnuabi64.mk b/mk/cfg/mips64el-unknown-linux-gnuabi64.mk new file mode 100644 index 000000000000..34aee77ae210 --- /dev/null +++ b/mk/cfg/mips64el-unknown-linux-gnuabi64.mk @@ -0,0 +1 @@ +# rustbuild-only target diff --git a/src/librustc_back/target/mips64_unknown_linux_gnuabi64.rs b/src/librustc_back/target/mips64_unknown_linux_gnuabi64.rs new file mode 100644 index 000000000000..7e45b3206536 --- /dev/null +++ b/src/librustc_back/target/mips64_unknown_linux_gnuabi64.rs @@ -0,0 +1,31 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use target::{Target, TargetOptions, TargetResult}; + +pub fn target() -> TargetResult { + Ok(Target { + llvm_target: "mips64-unknown-linux-gnuabi64".to_string(), + target_endian: "big".to_string(), + target_pointer_width: "64".to_string(), + data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".to_string(), + arch: "mips64".to_string(), + target_os: "linux".to_string(), + target_env: "gnu".to_string(), + target_vendor: "unknown".to_string(), + options: TargetOptions { + // NOTE(mips64r2) matches C toolchain + cpu: "mips64r2".to_string(), + features: "+mips64r2".to_string(), + max_atomic_width: 64, + ..super::linux_base::opts() + }, + }) +} diff --git a/src/librustc_back/target/mips64el_unknown_linux_gnuabi64.rs b/src/librustc_back/target/mips64el_unknown_linux_gnuabi64.rs new file mode 100644 index 000000000000..338a5da1e1d1 --- /dev/null +++ b/src/librustc_back/target/mips64el_unknown_linux_gnuabi64.rs @@ -0,0 +1,31 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use target::{Target, TargetOptions, TargetResult}; + +pub fn target() -> TargetResult { + Ok(Target { + llvm_target: "mips64el-unknown-linux-gnuabi64".to_string(), + target_endian: "little".to_string(), + target_pointer_width: "64".to_string(), + data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".to_string(), + arch: "mips64".to_string(), + target_os: "linux".to_string(), + target_env: "gnu".to_string(), + target_vendor: "unknown".to_string(), + options: TargetOptions { + // NOTE(mips64r2) matches C toolchain + cpu: "mips64r2".to_string(), + features: "+mips64r2".to_string(), + max_atomic_width: 64, + ..super::linux_base::opts() + }, + }) +} diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs index 86cd86d282cf..3c5ec84a8fa6 100644 --- a/src/librustc_back/target/mod.rs +++ b/src/librustc_back/target/mod.rs @@ -128,6 +128,8 @@ supported_targets! { ("i686-unknown-linux-gnu", i686_unknown_linux_gnu), ("i586-unknown-linux-gnu", i586_unknown_linux_gnu), ("mips-unknown-linux-gnu", mips_unknown_linux_gnu), + ("mips64-unknown-linux-gnuabi64", mips64_unknown_linux_gnuabi64), + ("mips64el-unknown-linux-gnuabi64", mips64el_unknown_linux_gnuabi64), ("mipsel-unknown-linux-gnu", mipsel_unknown_linux_gnu), ("powerpc-unknown-linux-gnu", powerpc_unknown_linux_gnu), ("powerpc64-unknown-linux-gnu", powerpc64_unknown_linux_gnu), diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs index 3a7fde6a36ba..5e264c80c4c1 100644 --- a/src/librustc_trans/abi.rs +++ b/src/librustc_trans/abi.rs @@ -21,6 +21,7 @@ use cabi_aarch64; use cabi_powerpc; use cabi_powerpc64; use cabi_mips; +use cabi_mips64; use cabi_asmjs; use machine::{llalign_of_min, llsize_of, llsize_of_real, llsize_of_store}; use type_::Type; @@ -498,6 +499,7 @@ impl FnType { cabi_arm::compute_abi_info(ccx, self, flavor); }, "mips" => cabi_mips::compute_abi_info(ccx, self), + "mips64" => cabi_mips64::compute_abi_info(ccx, self), "powerpc" => cabi_powerpc::compute_abi_info(ccx, self), "powerpc64" => cabi_powerpc64::compute_abi_info(ccx, self), "asmjs" => cabi_asmjs::compute_abi_info(ccx, self), diff --git a/src/librustc_trans/cabi_mips64.rs b/src/librustc_trans/cabi_mips64.rs new file mode 100644 index 000000000000..d3d3f83eac43 --- /dev/null +++ b/src/librustc_trans/cabi_mips64.rs @@ -0,0 +1,168 @@ +// 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. + +#![allow(non_upper_case_globals)] + +use libc::c_uint; +use std::cmp; +use llvm; +use llvm::{Integer, Pointer, Float, Double, Struct, Array, Vector}; +use abi::{ArgType, FnType}; +use context::CrateContext; +use type_::Type; + +fn align_up_to(off: usize, a: usize) -> usize { + return (off + a - 1) / a * a; +} + +fn align(off: usize, ty: Type) -> usize { + let a = ty_align(ty); + return align_up_to(off, a); +} + +fn ty_align(ty: Type) -> usize { + match ty.kind() { + Integer => ((ty.int_width() as usize) + 7) / 8, + Pointer => 8, + Float => 4, + Double => 8, + Struct => { + if ty.is_packed() { + 1 + } else { + let str_tys = ty.field_types(); + str_tys.iter().fold(1, |a, t| cmp::max(a, ty_align(*t))) + } + } + Array => { + let elt = ty.element_type(); + ty_align(elt) + } + Vector => { + let len = ty.vector_length(); + let elt = ty.element_type(); + ty_align(elt) * len + } + _ => bug!("ty_align: unhandled type") + } +} + +fn ty_size(ty: Type) -> usize { + match ty.kind() { + Integer => ((ty.int_width() as usize) + 7) / 8, + Pointer => 8, + Float => 4, + Double => 8, + Struct => { + if ty.is_packed() { + let str_tys = ty.field_types(); + str_tys.iter().fold(0, |s, t| s + ty_size(*t)) + } else { + let str_tys = ty.field_types(); + let size = str_tys.iter().fold(0, |s, t| align(s, *t) + ty_size(*t)); + align(size, ty) + } + } + Array => { + let len = ty.array_length(); + let elt = ty.element_type(); + let eltsz = ty_size(elt); + len * eltsz + } + Vector => { + let len = ty.vector_length(); + let elt = ty.element_type(); + let eltsz = ty_size(elt); + len * eltsz + } + _ => bug!("ty_size: unhandled type") + } +} + +fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) { + if is_reg_ty(ret.ty) { + ret.extend_integer_width_to(64); + } else { + ret.make_indirect(ccx); + } +} + +fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, offset: &mut usize) { + let orig_offset = *offset; + let size = ty_size(arg.ty) * 8; + let mut align = ty_align(arg.ty); + + align = cmp::min(cmp::max(align, 4), 8); + *offset = align_up_to(*offset, align); + *offset += align_up_to(size, align * 8) / 8; + + if !is_reg_ty(arg.ty) { + arg.cast = Some(struct_ty(ccx, arg.ty)); + arg.pad = padding_ty(ccx, align, orig_offset); + } else { + arg.extend_integer_width_to(64); + } +} + +fn is_reg_ty(ty: Type) -> bool { + return match ty.kind() { + Integer + | Pointer + | Float + | Double + | Vector => true, + _ => false + }; +} + +fn padding_ty(ccx: &CrateContext, align: usize, offset: usize) -> Option { + if ((align - 1 ) & offset) > 0 { + Some(Type::i32(ccx)) + } else { + None + } +} + +fn coerce_to_int(ccx: &CrateContext, size: usize) -> Vec { + let int_ty = Type::i32(ccx); + let mut args = Vec::new(); + + let mut n = size / 64; + while n > 0 { + args.push(int_ty); + n -= 1; + } + + let r = size % 64; + if r > 0 { + unsafe { + args.push(Type::from_ref(llvm::LLVMIntTypeInContext(ccx.llcx(), r as c_uint))); + } + } + + args +} + +fn struct_ty(ccx: &CrateContext, ty: Type) -> Type { + let size = ty_size(ty) * 8; + Type::struct_(ccx, &coerce_to_int(ccx, size), false) +} + +pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) { + if !fty.ret.is_ignore() { + classify_ret_ty(ccx, &mut fty.ret); + } + + let mut offset = if fty.ret.is_indirect() { 8 } else { 0 }; + for arg in &mut fty.args { + if arg.is_ignore() { continue; } + classify_arg_ty(ccx, arg, &mut offset); + } +} diff --git a/src/librustc_trans/cabi_powerpc.rs b/src/librustc_trans/cabi_powerpc.rs index efbdce67a8b2..e05c31b1d88c 100644 --- a/src/librustc_trans/cabi_powerpc.rs +++ b/src/librustc_trans/cabi_powerpc.rs @@ -28,11 +28,7 @@ fn align(off: usize, ty: Type) -> usize { fn ty_align(ty: Type) -> usize { match ty.kind() { - Integer => { - unsafe { - ((llvm::LLVMGetIntTypeWidth(ty.to_ref()) as usize) + 7) / 8 - } - } + Integer => ((ty.int_width() as usize) + 7) / 8, Pointer => 4, Float => 4, Double => 8, @@ -54,11 +50,7 @@ fn ty_align(ty: Type) -> usize { fn ty_size(ty: Type) -> usize { match ty.kind() { - Integer => { - unsafe { - ((llvm::LLVMGetIntTypeWidth(ty.to_ref()) as usize) + 7) / 8 - } - } + Integer => ((ty.int_width() as usize) + 7) / 8, Pointer => 4, Float => 4, Double => 8, diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index 1286df7b97e6..6ede55d5ff49 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -98,6 +98,7 @@ mod cabi_aarch64; mod cabi_arm; mod cabi_asmjs; mod cabi_mips; +mod cabi_mips64; mod cabi_powerpc; mod cabi_powerpc64; mod cabi_x86; From 1b9e9ab1dc523c4778a2510e4f9e2d470fe7a4a3 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Fri, 26 Aug 2016 20:25:59 -0500 Subject: [PATCH 014/443] update libc --- src/liblibc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/liblibc b/src/liblibc index 5066b7dcab7e..71b5d57ada32 160000 --- a/src/liblibc +++ b/src/liblibc @@ -1 +1 @@ -Subproject commit 5066b7dcab7e700844b0e2ba71b8af9dc627a59b +Subproject commit 71b5d57ada32cc5076791becc3b9019da29dffd4 From 43615a03f31d3c60c4af13a1fe17bd4cf3edad06 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 27 Aug 2016 01:39:29 -0500 Subject: [PATCH 015/443] fix cross compilation of std --- src/liballoc_jemalloc/lib.rs | 3 ++- src/liballoc_system/lib.rs | 3 ++- src/libpanic_unwind/gcc.rs | 2 +- src/libstd/env.rs | 6 ++++++ src/libstd/os/linux/raw.rs | 5 +++++ src/libunwind/libunwind.rs | 3 +++ 6 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/liballoc_jemalloc/lib.rs b/src/liballoc_jemalloc/lib.rs index 347e97e6ffc0..aae0528e42cc 100644 --- a/src/liballoc_jemalloc/lib.rs +++ b/src/liballoc_jemalloc/lib.rs @@ -77,7 +77,8 @@ const MIN_ALIGN: usize = 8; #[cfg(all(any(target_arch = "x86", target_arch = "x86_64", target_arch = "aarch64", - target_arch = "powerpc64")))] + target_arch = "powerpc64", + target_arch = "mips64")))] const MIN_ALIGN: usize = 16; // MALLOCX_ALIGN(a) macro diff --git a/src/liballoc_system/lib.rs b/src/liballoc_system/lib.rs index 9eade937bfb4..2c0c6d068caa 100644 --- a/src/liballoc_system/lib.rs +++ b/src/liballoc_system/lib.rs @@ -32,7 +32,8 @@ target_arch = "asmjs")))] const MIN_ALIGN: usize = 8; #[cfg(all(any(target_arch = "x86_64", - target_arch = "aarch64")))] + target_arch = "aarch64", + target_arch = "mips64")))] const MIN_ALIGN: usize = 16; #[no_mangle] diff --git a/src/libpanic_unwind/gcc.rs b/src/libpanic_unwind/gcc.rs index bd0c2f5126d1..c2e8eccbd22a 100644 --- a/src/libpanic_unwind/gcc.rs +++ b/src/libpanic_unwind/gcc.rs @@ -124,7 +124,7 @@ const UNWIND_DATA_REG: (i32, i32) = (0, 1); // RAX, RDX #[cfg(any(target_arch = "arm", target_arch = "aarch64"))] const UNWIND_DATA_REG: (i32, i32) = (0, 1); // R0, R1 / X0, X1 -#[cfg(any(target_arch = "mips", target_arch = "mipsel"))] +#[cfg(any(target_arch = "mips", target_arch = "mipsel", target_arch = "mips64"))] const UNWIND_DATA_REG: (i32, i32) = (4, 5); // A0, A1 #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] diff --git a/src/libstd/env.rs b/src/libstd/env.rs index 753411991abe..0380965ed205 100644 --- a/src/libstd/env.rs +++ b/src/libstd/env.rs @@ -661,6 +661,7 @@ pub mod consts { /// - arm /// - aarch64 /// - mips + /// - mips64 /// - powerpc /// - powerpc64 #[stable(feature = "env", since = "1.0.0")] @@ -928,6 +929,11 @@ mod arch { pub const ARCH: &'static str = "mips"; } +#[cfg(target_arch = "mips64")] +mod arch { + pub const ARCH: &'static str = "mips64"; +} + #[cfg(target_arch = "powerpc")] mod arch { pub const ARCH: &'static str = "powerpc"; diff --git a/src/libstd/os/linux/raw.rs b/src/libstd/os/linux/raw.rs index 1be76961fea9..0f62877500b2 100644 --- a/src/libstd/os/linux/raw.rs +++ b/src/libstd/os/linux/raw.rs @@ -155,6 +155,11 @@ mod arch { } } +#[cfg(target_arch = "mips64")] +mod arch { + pub use libc::{off_t, ino_t, nlink_t, blksize_t, blkcnt_t, stat, time_t}; +} + #[cfg(target_arch = "aarch64")] mod arch { use os::raw::{c_long, c_int}; diff --git a/src/libunwind/libunwind.rs b/src/libunwind/libunwind.rs index 680ad3ecd64a..8292a6841781 100644 --- a/src/libunwind/libunwind.rs +++ b/src/libunwind/libunwind.rs @@ -56,6 +56,9 @@ pub const unwinder_private_data_size: usize = 2; #[cfg(target_arch = "mips")] pub const unwinder_private_data_size: usize = 2; +#[cfg(target_arch = "mips64")] +pub const unwinder_private_data_size: usize = 2; + #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] pub const unwinder_private_data_size: usize = 2; From a7c671bb90ba1584d0098460ad8e417f848913f9 Mon Sep 17 00:00:00 2001 From: Oliver Middleton Date: Sat, 27 Aug 2016 17:00:36 +0100 Subject: [PATCH 016/443] rustdoc: Add missing item types to page titles Most pages include the item type in the title such as "Struct std::vec::Vec". However it is missing from the pages for foreign functions, type definitions, macros, statics and constants. This adds them so for example, instead of a title of "std::u32::MAX" it is "Constant std::u32::MAX" to match the others. --- src/librustdoc/html/render.rs | 18 +++++++++-- src/test/rustdoc/titles.rs | 59 +++++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+), 3 deletions(-) create mode 100644 src/test/rustdoc/titles.rs diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 6993f85c3d9a..3717e876d736 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -1552,12 +1552,21 @@ impl<'a> fmt::Display for Item<'a> { } else { write!(fmt, "Module ")?; }, - clean::FunctionItem(..) => write!(fmt, "Function ")?, + clean::FunctionItem(..) | clean::ForeignFunctionItem(..) => + write!(fmt, "Function ")?, clean::TraitItem(..) => write!(fmt, "Trait ")?, clean::StructItem(..) => write!(fmt, "Struct ")?, clean::EnumItem(..) => write!(fmt, "Enum ")?, + clean::TypedefItem(..) => write!(fmt, "Type Definition ")?, + clean::MacroItem(..) => write!(fmt, "Macro ")?, clean::PrimitiveItem(..) => write!(fmt, "Primitive Type ")?, - _ => {} + clean::StaticItem(..) | clean::ForeignStaticItem(..) => + write!(fmt, "Static ")?, + clean::ConstantItem(..) => write!(fmt, "Constant ")?, + _ => { + // We don't generate pages for any other type. + unreachable!(); + } } if !self.item.is_primitive() { let cur = &self.cx.current; @@ -1618,7 +1627,10 @@ impl<'a> fmt::Display for Item<'a> { clean::StaticItem(ref i) | clean::ForeignStaticItem(ref i) => item_static(fmt, self.cx, self.item, i), clean::ConstantItem(ref c) => item_constant(fmt, self.cx, self.item, c), - _ => Ok(()) + _ => { + // We don't generate pages for any other type. + unreachable!(); + } } } } diff --git a/src/test/rustdoc/titles.rs b/src/test/rustdoc/titles.rs new file mode 100644 index 000000000000..a56fa420944f --- /dev/null +++ b/src/test/rustdoc/titles.rs @@ -0,0 +1,59 @@ +// 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. + +#![crate_name = "foo"] + +// @matches 'foo/index.html' '//h1' 'Crate foo' + +// @matches 'foo/foo_mod/index.html' '//h1' 'Module foo::foo_mod' +pub mod foo_mod { + pub struct __Thing {} +} + +extern { + // @matches 'foo/fn.foo_ffn.html' '//h1' 'Function foo::foo_ffn' + pub fn foo_ffn(); +} + +// @matches 'foo/fn.foo_fn.html' '//h1' 'Function foo::foo_fn' +pub fn foo_fn() {} + +// @matches 'foo/trait.FooTrait.html' '//h1' 'Trait foo::FooTrait' +pub trait FooTrait {} + +// @matches 'foo/struct.FooStruct.html' '//h1' 'Struct foo::FooStruct' +pub struct FooStruct; + +// @matches 'foo/enum.FooEnum.html' '//h1' 'Enum foo::FooEnum' +pub enum FooEnum {} + +// @matches 'foo/type.FooType.html' '//h1' 'Type Definition foo::FooType' +pub type FooType = FooStruct; + +// @matches 'foo/macro.foo_macro.html' '//h1' 'Macro foo::foo_macro' +#[macro_export] +macro_rules! foo_macro { + () => (); +} + +// @matches 'foo/primitive.bool.html' '//h1' 'Primitive Type bool' +#[doc(primitive = "bool")] +mod bool {} + +// @matches 'foo/static.FOO_STATIC.html' '//h1' 'Static foo::FOO_STATIC' +pub static FOO_STATIC: FooStruct = FooStruct; + +extern { + // @matches 'foo/static.FOO_FSTATIC.html' '//h1' 'Static foo::FOO_FSTATIC' + pub static FOO_FSTATIC: FooStruct; +} + +// @matches 'foo/constant.FOO_CONSTANT.html' '//h1' 'Constant foo::FOO_CONSTANT' +pub const FOO_CONSTANT: FooStruct = FooStruct; From 286ae72fb7954ee51a6f4a1aeacbed6be4e6f37e Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 27 Aug 2016 21:01:27 +0200 Subject: [PATCH 017/443] Clean code a bit --- src/libstd/sys/unix/os.rs | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/src/libstd/sys/unix/os.rs b/src/libstd/sys/unix/os.rs index e61804efd50f..82606d2c728e 100644 --- a/src/libstd/sys/unix/os.rs +++ b/src/libstd/sys/unix/os.rs @@ -584,18 +584,15 @@ pub fn home_dir() -> Option { n if n < 0 => 512 as usize, n => n as usize, }; - let me = libc::getuid(); - loop { - let mut buf = Vec::with_capacity(amt); - let mut passwd: libc::passwd = mem::zeroed(); + let mut buf = Vec::with_capacity(amt); + let mut passwd: libc::passwd = mem::zeroed(); - if getpwduid_r(me, &mut passwd, &mut buf).is_some() { - let ptr = passwd.pw_dir as *const _; - let bytes = CStr::from_ptr(ptr).to_bytes().to_vec(); - return Some(OsStringExt::from_vec(bytes)) - } else { - return None; - } + if getpwduid_r(libc::getuid(), &mut passwd, &mut buf).is_some() { + let ptr = passwd.pw_dir as *const _; + let bytes = CStr::from_ptr(ptr).to_bytes().to_vec(); + Some(OsStringExt::from_vec(bytes)) + } else { + None } } } From 744312754dc3a3c36d2a609bb24889cb1b7994de Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Sun, 28 Aug 2016 20:35:48 +0200 Subject: [PATCH 018/443] fixed and extended tests once more --- src/test/compile-fail/rfc1623.rs | 70 ++++++++++++++++++++++++++++++-- src/test/run-pass/rfc1623.rs | 5 +-- 2 files changed, 69 insertions(+), 6 deletions(-) diff --git a/src/test/compile-fail/rfc1623.rs b/src/test/compile-fail/rfc1623.rs index 963459b27bf1..abdcc02de767 100644 --- a/src/test/compile-fail/rfc1623.rs +++ b/src/test/compile-fail/rfc1623.rs @@ -17,18 +17,82 @@ static NON_ELIDABLE_FN : &fn(&u8, &u8) -> &u8 = //~^ ERROR: missing lifetime specifier &(non_elidable as fn(&u8, &u8) -> &u8); +struct SomeStruct<'x, 'y, 'z: 'x> { + foo: &'x Foo<'z>, + bar: &'x Bar<'z>, + f: &'y for<'a, 'b: 'a> Fn(&'a Foo<'b>) -> &'a Bar<'b>, +} + +fn id(t: T) -> T { t } + +static SOME_STRUCT : &SomeStruct = SomeStruct { + foo: &Foo { bools: &[false, true] }, + bar: &Bar { bools: &[true, true] }, + f: &id, +}; + +// very simple test for a 'static static with default lifetime +static STATIC_STR : &'static str = "&'static str"; +const CONST_STR : &'static str = "&'static str"; + +// this should be the same as without default: +static EXPLICIT_STATIC_STR : &'static str = "&'static str"; +const EXPLICIT_CONST_STR : &'static str = "&'static str"; + +// a function that elides to an unbound lifetime for both in- and output +fn id_u8_slice(arg: &[u8]) -> &[u8] { arg } + +// one with a function, argument elided +static STATIC_SIMPLE_FN : &'static fn(&[u8]) -> &[u8] = + &(id_u8_slice as fn(&[u8]) -> &[u8]); +const CONST_SIMPLE_FN : &'static fn(&[u8]) -> &[u8] = + &(id_u8_slice as fn(&[u8]) -> &[u8]); + +// this should be the same as without elision +static STATIC_NON_ELIDED_fN : &'static for<'a> fn(&'a [u8]) -> &'a [u8] = + &(id_u8_slice as for<'a> fn(&'a [u8]) -> &'a [u8]); +const CONST_NON_ELIDED_fN : &'static for<'a> fn(&'a [u8]) -> &'a [u8] = + &(id_u8_slice as for<'a> fn(&'a [u8]) -> &'a [u8]); + +// another function that elides, each to a different unbound lifetime +fn multi_args(a: &u8, b: &u8, c: &u8) { } + +static STATIC_MULTI_FN : &'static fn(&u8, &u8, &u8) = + &(multi_args as fn(&u8, &u8, &u8)); +const CONST_MULTI_FN : &'static fn(&u8, &u8, &u8) = + &(multi_args as fn(&u8, &u8, &u8)); + +struct Foo<'a> { + bools: &'a [bool] +} + +static STATIC_FOO : Foo<'static> = Foo { bools: &[true, false] }; +const CONST_FOO : Foo<'static> = Foo { bools: &[true, false] }; + +type Bar<'a> = Foo<'a>; + +static STATIC_BAR : Bar<'static> = Bar { bools: &[true, false] }; +const CONST_BAR : Bar<'static> = Bar { bools: &[true, false] }; + type Baz<'a> = fn(&'a [u8]) -> Option; fn baz(e: &[u8]) -> Option { e.first().map(|x| *x) } -static STATIC_BAZ : &Baz<'static> = &(baz as Baz); -const CONST_BAZ : &Baz<'static> = &(baz as Baz); +static STATIC_BAZ : &'static Baz<'static> = &(baz as Baz); +const CONST_BAZ : &'static Baz<'static> = &(baz as Baz); + +static BYTES : &'static [u8] = &[1, 2, 3]; fn main() { let x = &[1u8, 2, 3]; let y = x; - //surprisingly this appears to work, so lifetime < `'static` is valid + //this works, so lifetime < `'static` is valid assert_eq!(Some(1), STATIC_BAZ(y)); assert_eq!(Some(1), CONST_BAZ(y)); + + let y = &[1u8, 2, 3]; + //^~ ERROR: borrowed values does not live long enough + STATIC_BAZ(BYTES); // BYTES has static lifetime + CONST_BAZ(y); // This forces static lifetime, which y has not } diff --git a/src/test/run-pass/rfc1623.rs b/src/test/run-pass/rfc1623.rs index bd0420bb5067..0915118ca27c 100644 --- a/src/test/run-pass/rfc1623.rs +++ b/src/test/run-pass/rfc1623.rs @@ -68,9 +68,8 @@ fn main() { STATIC_SIMPLE_FN(x); CONST_SIMPLE_FN(x); - let y = &[1u8, 2, 3]; - STATIC_BAZ(BYTES); - //CONST_BAZ(y); // strangely enough, this fails + STATIC_BAZ(BYTES); // neees static lifetime + CONST_BAZ(BYTES); // make sure this works with different lifetimes let a = &1; From ef4952e73926bda4cfdbd0e48badc3ae30e4fb58 Mon Sep 17 00:00:00 2001 From: Andrew Paseltiner Date: Sun, 28 Aug 2016 18:52:21 -0400 Subject: [PATCH 019/443] Address FIXME in libcollectionstest/btree/set.rs --- src/libcollectionstest/btree/set.rs | 30 ++++++----------------------- src/libcollectionstest/lib.rs | 1 - 2 files changed, 6 insertions(+), 25 deletions(-) diff --git a/src/libcollectionstest/btree/set.rs b/src/libcollectionstest/btree/set.rs index f7b647d7772d..a32e3f1a76ae 100644 --- a/src/libcollectionstest/btree/set.rs +++ b/src/libcollectionstest/btree/set.rs @@ -39,30 +39,8 @@ fn test_hash() { assert!(::hash(&x) == ::hash(&y)); } -struct Counter<'a, 'b> { - i: &'a mut usize, - expected: &'b [i32], -} - -impl<'a, 'b, 'c> FnMut<(&'c i32,)> for Counter<'a, 'b> { - extern "rust-call" fn call_mut(&mut self, (&x,): (&'c i32,)) -> bool { - assert_eq!(x, self.expected[*self.i]); - *self.i += 1; - true - } -} - -impl<'a, 'b, 'c> FnOnce<(&'c i32,)> for Counter<'a, 'b> { - type Output = bool; - - extern "rust-call" fn call_once(mut self, args: (&'c i32,)) -> bool { - self.call_mut(args) - } -} - fn check(a: &[i32], b: &[i32], expected: &[i32], f: F) where - // FIXME Replace Counter with `Box _>` - F: FnOnce(&BTreeSet, &BTreeSet, Counter) -> bool, + F: FnOnce(&BTreeSet, &BTreeSet, &mut FnMut(&i32) -> bool) -> bool, { let mut set_a = BTreeSet::new(); let mut set_b = BTreeSet::new(); @@ -71,7 +49,11 @@ fn check(a: &[i32], b: &[i32], expected: &[i32], f: F) where for y in b { assert!(set_b.insert(*y)) } let mut i = 0; - f(&set_a, &set_b, Counter { i: &mut i, expected: expected }); + f(&set_a, &set_b, &mut |&x| { + assert_eq!(x, expected[i]); + i += 1; + true + }); assert_eq!(i, expected.len()); } diff --git a/src/libcollectionstest/lib.rs b/src/libcollectionstest/lib.rs index f448fcf2dbf9..32a07e3e7e62 100644 --- a/src/libcollectionstest/lib.rs +++ b/src/libcollectionstest/lib.rs @@ -16,7 +16,6 @@ #![feature(collections)] #![feature(collections_bound)] #![feature(const_fn)] -#![feature(fn_traits)] #![feature(enumset)] #![feature(pattern)] #![feature(rand)] From bc288a598c018273343f29f6ad609062ce4ac2c7 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 28 Aug 2016 17:41:26 -0500 Subject: [PATCH 020/443] cabi: change some more 32s to 64s --- src/librustc_trans/cabi_mips64.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc_trans/cabi_mips64.rs b/src/librustc_trans/cabi_mips64.rs index d3d3f83eac43..e92ef1eaec8e 100644 --- a/src/librustc_trans/cabi_mips64.rs +++ b/src/librustc_trans/cabi_mips64.rs @@ -124,14 +124,14 @@ fn is_reg_ty(ty: Type) -> bool { fn padding_ty(ccx: &CrateContext, align: usize, offset: usize) -> Option { if ((align - 1 ) & offset) > 0 { - Some(Type::i32(ccx)) + Some(Type::i64(ccx)) } else { None } } fn coerce_to_int(ccx: &CrateContext, size: usize) -> Vec { - let int_ty = Type::i32(ccx); + let int_ty = Type::i64(ccx); let mut args = Vec::new(); let mut n = size / 64; From 2222d437a75dec627a21c0b68b32bee080fa1f5a Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 28 Aug 2016 21:34:04 -0500 Subject: [PATCH 021/443] fix data-layouts --- src/librustc_back/target/mips64_unknown_linux_gnuabi64.rs | 2 +- src/librustc_back/target/mips64el_unknown_linux_gnuabi64.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc_back/target/mips64_unknown_linux_gnuabi64.rs b/src/librustc_back/target/mips64_unknown_linux_gnuabi64.rs index 7e45b3206536..837856344280 100644 --- a/src/librustc_back/target/mips64_unknown_linux_gnuabi64.rs +++ b/src/librustc_back/target/mips64_unknown_linux_gnuabi64.rs @@ -15,7 +15,7 @@ pub fn target() -> TargetResult { llvm_target: "mips64-unknown-linux-gnuabi64".to_string(), target_endian: "big".to_string(), target_pointer_width: "64".to_string(), - data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".to_string(), + data_layout: "E-m:m-i8:8:32-i16:16:32-i64:64-n32:64-S128".to_string(), arch: "mips64".to_string(), target_os: "linux".to_string(), target_env: "gnu".to_string(), diff --git a/src/librustc_back/target/mips64el_unknown_linux_gnuabi64.rs b/src/librustc_back/target/mips64el_unknown_linux_gnuabi64.rs index 338a5da1e1d1..e1340e8e127b 100644 --- a/src/librustc_back/target/mips64el_unknown_linux_gnuabi64.rs +++ b/src/librustc_back/target/mips64el_unknown_linux_gnuabi64.rs @@ -15,7 +15,7 @@ pub fn target() -> TargetResult { llvm_target: "mips64el-unknown-linux-gnuabi64".to_string(), target_endian: "little".to_string(), target_pointer_width: "64".to_string(), - data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".to_string(), + data_layout: "e-m:m-i8:8:32-i16:16:32-i64:64-n32:64-S128".to_string(), arch: "mips64".to_string(), target_os: "linux".to_string(), target_env: "gnu".to_string(), From 65249a5431bbc3bf6b0f0894aefcc28c76eb17bb Mon Sep 17 00:00:00 2001 From: Gavin Baker Date: Sun, 28 Aug 2016 22:55:39 +1000 Subject: [PATCH 022/443] E0459 Update error format #35933 - Fixes #35933 - Part of #35233 r? @jonathandturner --- src/librustc_metadata/creader.rs | 5 +++-- src/test/compile-fail/E0459.rs | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 46469efea6bc..b84c3e8a5bc2 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -977,8 +977,9 @@ impl<'a> LocalCrateReader<'a> { let n = match n { Some(n) => n, None => { - span_err!(self.sess, m.span, E0459, - "#[link(...)] specified without `name = \"foo\"`"); + struct_span_err!(self.sess, m.span, E0459, + "#[link(...)] specified without `name = \"foo\"`") + .span_label(m.span, &format!("missing `name` argument")).emit(); InternedString::new("foo") } }; diff --git a/src/test/compile-fail/E0459.rs b/src/test/compile-fail/E0459.rs index dc7ac714f223..41376bd9ef5a 100644 --- a/src/test/compile-fail/E0459.rs +++ b/src/test/compile-fail/E0459.rs @@ -9,6 +9,7 @@ // except according to those terms. #[link(kind = "dylib")] extern {} //~ ERROR E0459 + //~| NOTE missing `name` argument fn main() { } From 0412fa8b8e00bebc2bb0ad17a7e558f13b8954a7 Mon Sep 17 00:00:00 2001 From: Gavin Baker Date: Sun, 28 Aug 2016 23:55:43 +1000 Subject: [PATCH 023/443] E0458 Update error format #35932 - Fixes #35932 - Part of #35233 r? @jonathandturner --- src/librustc_metadata/creader.rs | 5 +++-- src/test/compile-fail/E0458.rs | 4 +++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index b84c3e8a5bc2..8f4e9f941c60 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -965,8 +965,9 @@ impl<'a> LocalCrateReader<'a> { Some("dylib") => cstore::NativeUnknown, Some("framework") => cstore::NativeFramework, Some(k) => { - span_err!(self.sess, m.span, E0458, - "unknown kind: `{}`", k); + struct_span_err!(self.sess, m.span, E0458, + "unknown kind: `{}`", k) + .span_label(m.span, &format!("unknown kind")).emit(); cstore::NativeUnknown } None => cstore::NativeUnknown diff --git a/src/test/compile-fail/E0458.rs b/src/test/compile-fail/E0458.rs index 21bedc6b84c2..e87158ae3b03 100644 --- a/src/test/compile-fail/E0458.rs +++ b/src/test/compile-fail/E0458.rs @@ -9,7 +9,9 @@ // except according to those terms. #[link(kind = "wonderful_unicorn")] extern {} //~ ERROR E0458 - //~^ ERROR E0459 + //~| NOTE unknown kind + //~| ERROR E0459 + //~| NOTE missing `name` argument fn main() { } From e95f119d68008891193cdc10cf2ebc33e73c693c Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Mon, 29 Aug 2016 14:03:57 +0200 Subject: [PATCH 024/443] rustfmt tests --- src/test/compile-fail/rfc1623.rs | 90 ++++++++++++++++---------------- src/test/run-pass/rfc1623.rs | 72 ++++++++++++------------- 2 files changed, 82 insertions(+), 80 deletions(-) diff --git a/src/test/compile-fail/rfc1623.rs b/src/test/compile-fail/rfc1623.rs index abdcc02de767..3e9afdd5b13a 100644 --- a/src/test/compile-fail/rfc1623.rs +++ b/src/test/compile-fail/rfc1623.rs @@ -10,12 +10,12 @@ #![allow(dead_code)] -fn non_elidable<'a, 'b>(a: &'a u8, b: &'b u8) -> &'a u8 { a } +fn non_elidable<'a, 'b>(a: &'a u8, b: &'b u8) -> &'a u8 { + a +} // the boundaries of elision -static NON_ELIDABLE_FN : &fn(&u8, &u8) -> &u8 = -//~^ ERROR: missing lifetime specifier - &(non_elidable as fn(&u8, &u8) -> &u8); +static NON_ELIDABLE_FN: &fn(&u8, &u8) -> &u8 = &(non_elidable as fn(&u8, &u8) -> &u8); struct SomeStruct<'x, 'y, 'z: 'x> { foo: &'x Foo<'z>, @@ -23,76 +23,78 @@ struct SomeStruct<'x, 'y, 'z: 'x> { f: &'y for<'a, 'b: 'a> Fn(&'a Foo<'b>) -> &'a Bar<'b>, } -fn id(t: T) -> T { t } +fn id(t: T) -> T { + t +} -static SOME_STRUCT : &SomeStruct = SomeStruct { +static SOME_STRUCT: &SomeStruct = SomeStruct { foo: &Foo { bools: &[false, true] }, bar: &Bar { bools: &[true, true] }, f: &id, }; // very simple test for a 'static static with default lifetime -static STATIC_STR : &'static str = "&'static str"; -const CONST_STR : &'static str = "&'static str"; +static STATIC_STR: &'static str = "&'static str"; +const CONST_STR: &'static str = "&'static str"; // this should be the same as without default: -static EXPLICIT_STATIC_STR : &'static str = "&'static str"; -const EXPLICIT_CONST_STR : &'static str = "&'static str"; +static EXPLICIT_STATIC_STR: &'static str = "&'static str"; +const EXPLICIT_CONST_STR: &'static str = "&'static str"; // a function that elides to an unbound lifetime for both in- and output -fn id_u8_slice(arg: &[u8]) -> &[u8] { arg } - -// one with a function, argument elided -static STATIC_SIMPLE_FN : &'static fn(&[u8]) -> &[u8] = - &(id_u8_slice as fn(&[u8]) -> &[u8]); -const CONST_SIMPLE_FN : &'static fn(&[u8]) -> &[u8] = - &(id_u8_slice as fn(&[u8]) -> &[u8]); - -// this should be the same as without elision -static STATIC_NON_ELIDED_fN : &'static for<'a> fn(&'a [u8]) -> &'a [u8] = - &(id_u8_slice as for<'a> fn(&'a [u8]) -> &'a [u8]); -const CONST_NON_ELIDED_fN : &'static for<'a> fn(&'a [u8]) -> &'a [u8] = - &(id_u8_slice as for<'a> fn(&'a [u8]) -> &'a [u8]); - -// another function that elides, each to a different unbound lifetime -fn multi_args(a: &u8, b: &u8, c: &u8) { } - -static STATIC_MULTI_FN : &'static fn(&u8, &u8, &u8) = - &(multi_args as fn(&u8, &u8, &u8)); -const CONST_MULTI_FN : &'static fn(&u8, &u8, &u8) = - &(multi_args as fn(&u8, &u8, &u8)); - -struct Foo<'a> { - bools: &'a [bool] +fn id_u8_slice(arg: &[u8]) -> &[u8] { + arg } -static STATIC_FOO : Foo<'static> = Foo { bools: &[true, false] }; -const CONST_FOO : Foo<'static> = Foo { bools: &[true, false] }; +// one with a function, argument elided +static STATIC_SIMPLE_FN: &'static fn(&[u8]) -> &[u8] = &(id_u8_slice as fn(&[u8]) -> &[u8]); +const CONST_SIMPLE_FN: &'static fn(&[u8]) -> &[u8] = &(id_u8_slice as fn(&[u8]) -> &[u8]); + +// this should be the same as without elision +static STATIC_NON_ELIDED_fN: &'static for<'a> fn(&'a [u8]) -> &'a [u8] = + &(id_u8_slice as for<'a> fn(&'a [u8]) -> &'a [u8]); +const CONST_NON_ELIDED_fN: &'static for<'a> fn(&'a [u8]) -> &'a [u8] = + &(id_u8_slice as for<'a> fn(&'a [u8]) -> &'a [u8]); + +// another function that elides, each to a different unbound lifetime +fn multi_args(a: &u8, b: &u8, c: &u8) {} + +static STATIC_MULTI_FN: &'static fn(&u8, &u8, &u8) = &(multi_args as fn(&u8, &u8, &u8)); +const CONST_MULTI_FN: &'static fn(&u8, &u8, &u8) = &(multi_args as fn(&u8, &u8, &u8)); + +struct Foo<'a> { + bools: &'a [bool], +} + +static STATIC_FOO: Foo<'static> = Foo { bools: &[true, false] }; +const CONST_FOO: Foo<'static> = Foo { bools: &[true, false] }; type Bar<'a> = Foo<'a>; -static STATIC_BAR : Bar<'static> = Bar { bools: &[true, false] }; -const CONST_BAR : Bar<'static> = Bar { bools: &[true, false] }; +static STATIC_BAR: Bar<'static> = Bar { bools: &[true, false] }; +const CONST_BAR: Bar<'static> = Bar { bools: &[true, false] }; type Baz<'a> = fn(&'a [u8]) -> Option; -fn baz(e: &[u8]) -> Option { e.first().map(|x| *x) } +fn baz(e: &[u8]) -> Option { + e.first().map(|x| *x) +} -static STATIC_BAZ : &'static Baz<'static> = &(baz as Baz); -const CONST_BAZ : &'static Baz<'static> = &(baz as Baz); +static STATIC_BAZ: &'static Baz<'static> = &(baz as Baz); +const CONST_BAZ: &'static Baz<'static> = &(baz as Baz); -static BYTES : &'static [u8] = &[1, 2, 3]; +static BYTES: &'static [u8] = &[1, 2, 3]; fn main() { let x = &[1u8, 2, 3]; let y = x; - //this works, so lifetime < `'static` is valid + // this works, so lifetime < `'static` is valid assert_eq!(Some(1), STATIC_BAZ(y)); assert_eq!(Some(1), CONST_BAZ(y)); let y = &[1u8, 2, 3]; - //^~ ERROR: borrowed values does not live long enough + // ^~ ERROR: borrowed values does not live long enough STATIC_BAZ(BYTES); // BYTES has static lifetime CONST_BAZ(y); // This forces static lifetime, which y has not } diff --git a/src/test/run-pass/rfc1623.rs b/src/test/run-pass/rfc1623.rs index 0915118ca27c..17453933c8ab 100644 --- a/src/test/run-pass/rfc1623.rs +++ b/src/test/run-pass/rfc1623.rs @@ -11,56 +11,56 @@ #![allow(dead_code)] // very simple test for a 'static static with default lifetime -static STATIC_STR : &str = "&'static str"; -const CONST_STR : &str = "&'static str"; +static STATIC_STR: &str = "&'static str"; +const CONST_STR: &str = "&'static str"; // this should be the same as without default: -static EXPLICIT_STATIC_STR : &'static str = "&'static str"; -const EXPLICIT_CONST_STR : &'static str = "&'static str"; +static EXPLICIT_STATIC_STR: &'static str = "&'static str"; +const EXPLICIT_CONST_STR: &'static str = "&'static str"; // a function that elides to an unbound lifetime for both in- and output -fn id_u8_slice(arg: &[u8]) -> &[u8] { arg } - -// one with a function, argument elided -static STATIC_SIMPLE_FN : &fn(&[u8]) -> &[u8] = - &(id_u8_slice as fn(&[u8]) -> &[u8]); -const CONST_SIMPLE_FN : &fn(&[u8]) -> &[u8] = - &(id_u8_slice as fn(&[u8]) -> &[u8]); - -// this should be the same as without elision -static STATIC_NON_ELIDED_fN : &for<'a> fn(&'a [u8]) -> &'a [u8] = - &(id_u8_slice as for<'a> fn(&'a [u8]) -> &'a [u8]); -const CONST_NON_ELIDED_fN : &for<'a> fn(&'a [u8]) -> &'a [u8] = - &(id_u8_slice as for<'a> fn(&'a [u8]) -> &'a [u8]); - -// another function that elides, each to a different unbound lifetime -fn multi_args(a: &u8, b: &u8, c: &u8) { } - -static STATIC_MULTI_FN : &fn(&u8, &u8, &u8) = - &(multi_args as fn(&u8, &u8, &u8)); -const CONST_MULTI_FN : &fn(&u8, &u8, &u8) = - &(multi_args as fn(&u8, &u8, &u8)); - -struct Foo<'a> { - bools: &'a [bool] +fn id_u8_slice(arg: &[u8]) -> &[u8] { + arg } -static STATIC_FOO : Foo = Foo { bools: &[true, false] }; -const CONST_FOO : Foo = Foo { bools: &[true, false] }; +// one with a function, argument elided +static STATIC_SIMPLE_FN: &fn(&[u8]) -> &[u8] = &(id_u8_slice as fn(&[u8]) -> &[u8]); +const CONST_SIMPLE_FN: &fn(&[u8]) -> &[u8] = &(id_u8_slice as fn(&[u8]) -> &[u8]); + +// this should be the same as without elision +static STATIC_NON_ELIDED_fN: &for<'a> fn(&'a [u8]) -> &'a [u8] = + &(id_u8_slice as for<'a> fn(&'a [u8]) -> &'a [u8]); +const CONST_NON_ELIDED_fN: &for<'a> fn(&'a [u8]) -> &'a [u8] = + &(id_u8_slice as for<'a> fn(&'a [u8]) -> &'a [u8]); + +// another function that elides, each to a different unbound lifetime +fn multi_args(a: &u8, b: &u8, c: &u8) {} + +static STATIC_MULTI_FN: &fn(&u8, &u8, &u8) = &(multi_args as fn(&u8, &u8, &u8)); +const CONST_MULTI_FN: &fn(&u8, &u8, &u8) = &(multi_args as fn(&u8, &u8, &u8)); + +struct Foo<'a> { + bools: &'a [bool], +} + +static STATIC_FOO: Foo = Foo { bools: &[true, false] }; +const CONST_FOO: Foo = Foo { bools: &[true, false] }; type Bar<'a> = Foo<'a>; -static STATIC_BAR : Bar = Bar { bools: &[true, false] }; -const CONST_BAR : Bar = Bar { bools: &[true, false] }; +static STATIC_BAR: Bar = Bar { bools: &[true, false] }; +const CONST_BAR: Bar = Bar { bools: &[true, false] }; type Baz<'a> = fn(&'a [u8]) -> Option; -fn baz(e: &[u8]) -> Option { e.first().map(|x| *x) } +fn baz(e: &[u8]) -> Option { + e.first().map(|x| *x) +} -static STATIC_BAZ : &Baz = &(baz as Baz); -const CONST_BAZ : &Baz = &(baz as Baz); +static STATIC_BAZ: &Baz = &(baz as Baz); +const CONST_BAZ: &Baz = &(baz as Baz); -static BYTES : &[u8] = &[1, 2, 3]; +static BYTES: &[u8] = &[1, 2, 3]; fn main() { // make sure that the lifetime is actually elided (and not defaulted) From a87b4d88fb5c40736a5d884ac9fd3f01690d29d6 Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Mon, 29 Aug 2016 16:45:22 +0200 Subject: [PATCH 025/443] removed unneeded test, also compiletest vs. rustfmt --- src/test/compile-fail/regions-in-consts.rs | 15 ---- src/test/compile-fail/rfc1623.rs | 5 +- src/test/compile-fail/rfc1623.rs.bk | 98 ++++++++++++++++++++++ src/test/run-pass/rfc1623.rs.bk | 81 ++++++++++++++++++ 4 files changed, 182 insertions(+), 17 deletions(-) delete mode 100644 src/test/compile-fail/regions-in-consts.rs create mode 100644 src/test/compile-fail/rfc1623.rs.bk create mode 100644 src/test/run-pass/rfc1623.rs.bk diff --git a/src/test/compile-fail/regions-in-consts.rs b/src/test/compile-fail/regions-in-consts.rs deleted file mode 100644 index 8d0829a4cffc..000000000000 --- a/src/test/compile-fail/regions-in-consts.rs +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -static c_y: &isize = &22; //~ ERROR missing lifetime specifier -static c_z: &'static isize = &22; - -fn main() { -} diff --git a/src/test/compile-fail/rfc1623.rs b/src/test/compile-fail/rfc1623.rs index 3e9afdd5b13a..1d8fc7fe111c 100644 --- a/src/test/compile-fail/rfc1623.rs +++ b/src/test/compile-fail/rfc1623.rs @@ -16,6 +16,7 @@ fn non_elidable<'a, 'b>(a: &'a u8, b: &'b u8) -> &'a u8 { // the boundaries of elision static NON_ELIDABLE_FN: &fn(&u8, &u8) -> &u8 = &(non_elidable as fn(&u8, &u8) -> &u8); +//~^ ERROR missing lifetime specifier [E0106] struct SomeStruct<'x, 'y, 'z: 'x> { foo: &'x Foo<'z>, @@ -94,7 +95,7 @@ fn main() { assert_eq!(Some(1), CONST_BAZ(y)); let y = &[1u8, 2, 3]; - // ^~ ERROR: borrowed values does not live long enough + STATIC_BAZ(BYTES); // BYTES has static lifetime - CONST_BAZ(y); // This forces static lifetime, which y has not + CONST_BAZ(y); // interestingly this does not get reported } diff --git a/src/test/compile-fail/rfc1623.rs.bk b/src/test/compile-fail/rfc1623.rs.bk new file mode 100644 index 000000000000..abdcc02de767 --- /dev/null +++ b/src/test/compile-fail/rfc1623.rs.bk @@ -0,0 +1,98 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(dead_code)] + +fn non_elidable<'a, 'b>(a: &'a u8, b: &'b u8) -> &'a u8 { a } + +// the boundaries of elision +static NON_ELIDABLE_FN : &fn(&u8, &u8) -> &u8 = +//~^ ERROR: missing lifetime specifier + &(non_elidable as fn(&u8, &u8) -> &u8); + +struct SomeStruct<'x, 'y, 'z: 'x> { + foo: &'x Foo<'z>, + bar: &'x Bar<'z>, + f: &'y for<'a, 'b: 'a> Fn(&'a Foo<'b>) -> &'a Bar<'b>, +} + +fn id(t: T) -> T { t } + +static SOME_STRUCT : &SomeStruct = SomeStruct { + foo: &Foo { bools: &[false, true] }, + bar: &Bar { bools: &[true, true] }, + f: &id, +}; + +// very simple test for a 'static static with default lifetime +static STATIC_STR : &'static str = "&'static str"; +const CONST_STR : &'static str = "&'static str"; + +// this should be the same as without default: +static EXPLICIT_STATIC_STR : &'static str = "&'static str"; +const EXPLICIT_CONST_STR : &'static str = "&'static str"; + +// a function that elides to an unbound lifetime for both in- and output +fn id_u8_slice(arg: &[u8]) -> &[u8] { arg } + +// one with a function, argument elided +static STATIC_SIMPLE_FN : &'static fn(&[u8]) -> &[u8] = + &(id_u8_slice as fn(&[u8]) -> &[u8]); +const CONST_SIMPLE_FN : &'static fn(&[u8]) -> &[u8] = + &(id_u8_slice as fn(&[u8]) -> &[u8]); + +// this should be the same as without elision +static STATIC_NON_ELIDED_fN : &'static for<'a> fn(&'a [u8]) -> &'a [u8] = + &(id_u8_slice as for<'a> fn(&'a [u8]) -> &'a [u8]); +const CONST_NON_ELIDED_fN : &'static for<'a> fn(&'a [u8]) -> &'a [u8] = + &(id_u8_slice as for<'a> fn(&'a [u8]) -> &'a [u8]); + +// another function that elides, each to a different unbound lifetime +fn multi_args(a: &u8, b: &u8, c: &u8) { } + +static STATIC_MULTI_FN : &'static fn(&u8, &u8, &u8) = + &(multi_args as fn(&u8, &u8, &u8)); +const CONST_MULTI_FN : &'static fn(&u8, &u8, &u8) = + &(multi_args as fn(&u8, &u8, &u8)); + +struct Foo<'a> { + bools: &'a [bool] +} + +static STATIC_FOO : Foo<'static> = Foo { bools: &[true, false] }; +const CONST_FOO : Foo<'static> = Foo { bools: &[true, false] }; + +type Bar<'a> = Foo<'a>; + +static STATIC_BAR : Bar<'static> = Bar { bools: &[true, false] }; +const CONST_BAR : Bar<'static> = Bar { bools: &[true, false] }; + +type Baz<'a> = fn(&'a [u8]) -> Option; + +fn baz(e: &[u8]) -> Option { e.first().map(|x| *x) } + +static STATIC_BAZ : &'static Baz<'static> = &(baz as Baz); +const CONST_BAZ : &'static Baz<'static> = &(baz as Baz); + +static BYTES : &'static [u8] = &[1, 2, 3]; + +fn main() { + let x = &[1u8, 2, 3]; + let y = x; + + //this works, so lifetime < `'static` is valid + assert_eq!(Some(1), STATIC_BAZ(y)); + assert_eq!(Some(1), CONST_BAZ(y)); + + let y = &[1u8, 2, 3]; + //^~ ERROR: borrowed values does not live long enough + STATIC_BAZ(BYTES); // BYTES has static lifetime + CONST_BAZ(y); // This forces static lifetime, which y has not +} diff --git a/src/test/run-pass/rfc1623.rs.bk b/src/test/run-pass/rfc1623.rs.bk new file mode 100644 index 000000000000..0915118ca27c --- /dev/null +++ b/src/test/run-pass/rfc1623.rs.bk @@ -0,0 +1,81 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(dead_code)] + +// very simple test for a 'static static with default lifetime +static STATIC_STR : &str = "&'static str"; +const CONST_STR : &str = "&'static str"; + +// this should be the same as without default: +static EXPLICIT_STATIC_STR : &'static str = "&'static str"; +const EXPLICIT_CONST_STR : &'static str = "&'static str"; + +// a function that elides to an unbound lifetime for both in- and output +fn id_u8_slice(arg: &[u8]) -> &[u8] { arg } + +// one with a function, argument elided +static STATIC_SIMPLE_FN : &fn(&[u8]) -> &[u8] = + &(id_u8_slice as fn(&[u8]) -> &[u8]); +const CONST_SIMPLE_FN : &fn(&[u8]) -> &[u8] = + &(id_u8_slice as fn(&[u8]) -> &[u8]); + +// this should be the same as without elision +static STATIC_NON_ELIDED_fN : &for<'a> fn(&'a [u8]) -> &'a [u8] = + &(id_u8_slice as for<'a> fn(&'a [u8]) -> &'a [u8]); +const CONST_NON_ELIDED_fN : &for<'a> fn(&'a [u8]) -> &'a [u8] = + &(id_u8_slice as for<'a> fn(&'a [u8]) -> &'a [u8]); + +// another function that elides, each to a different unbound lifetime +fn multi_args(a: &u8, b: &u8, c: &u8) { } + +static STATIC_MULTI_FN : &fn(&u8, &u8, &u8) = + &(multi_args as fn(&u8, &u8, &u8)); +const CONST_MULTI_FN : &fn(&u8, &u8, &u8) = + &(multi_args as fn(&u8, &u8, &u8)); + +struct Foo<'a> { + bools: &'a [bool] +} + +static STATIC_FOO : Foo = Foo { bools: &[true, false] }; +const CONST_FOO : Foo = Foo { bools: &[true, false] }; + +type Bar<'a> = Foo<'a>; + +static STATIC_BAR : Bar = Bar { bools: &[true, false] }; +const CONST_BAR : Bar = Bar { bools: &[true, false] }; + +type Baz<'a> = fn(&'a [u8]) -> Option; + +fn baz(e: &[u8]) -> Option { e.first().map(|x| *x) } + +static STATIC_BAZ : &Baz = &(baz as Baz); +const CONST_BAZ : &Baz = &(baz as Baz); + +static BYTES : &[u8] = &[1, 2, 3]; + +fn main() { + // make sure that the lifetime is actually elided (and not defaulted) + let x = &[1u8, 2, 3]; + STATIC_SIMPLE_FN(x); + CONST_SIMPLE_FN(x); + + STATIC_BAZ(BYTES); // neees static lifetime + CONST_BAZ(BYTES); + + // make sure this works with different lifetimes + let a = &1; + { + let b = &2; + let c = &3; + CONST_MULTI_FN(a, b, c); + } +} From 89f7e9269826abf44ee39fdde06197aff15f30ff Mon Sep 17 00:00:00 2001 From: Matthew Piziak Date: Thu, 18 Aug 2016 15:10:57 -0400 Subject: [PATCH 026/443] demonstrate `RHS != Self` use cases for `Add` and `Sub` remove extra `../`s --- src/libcore/ops.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index 5d431230e974..78c8fc0ac454 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -212,6 +212,12 @@ macro_rules! forward_ref_binop { /// Point { x: 3, y: 3 }); /// } /// ``` +/// +/// Note that `RHS = Self` by default, but this is not mandatory. For example, +/// [std::time::SystemTime] implements `Add`, which permits +/// operations of the form `SystemTime = SystemTime + Duration`. +/// +/// [std::time::SystemTime]: ../time/struct.SystemTime.html #[lang = "add"] #[stable(feature = "rust1", since = "1.0.0")] pub trait Add { @@ -279,6 +285,12 @@ add_impl! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 f32 f64 } /// Point { x: 1, y: 0 }); /// } /// ``` +/// +/// Note that `RHS = Self` by default, but this is not mandatory. For example, +/// [std::time::SystemTime] implements `Sub`, which permits +/// operations of the form `SystemTime = SystemTime - Duration`. +/// +/// [std::time::SystemTime]: ../time/struct.SystemTime.html #[lang = "sub"] #[stable(feature = "rust1", since = "1.0.0")] pub trait Sub { From bbf2c3c31f3dd7703f4a13724bada979a921a65f Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Mon, 29 Aug 2016 12:25:06 -0500 Subject: [PATCH 027/443] update libc submodule --- src/liblibc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/liblibc b/src/liblibc index 71b5d57ada32..49d64cae0699 160000 --- a/src/liblibc +++ b/src/liblibc @@ -1 +1 @@ -Subproject commit 71b5d57ada32cc5076791becc3b9019da29dffd4 +Subproject commit 49d64cae0699ed9d9ed84810d737a26b0b519da8 From 899c2891e6be24100db723f2b5464969bcebe0f0 Mon Sep 17 00:00:00 2001 From: Keith Yeung Date: Sun, 28 Aug 2016 15:48:56 -0700 Subject: [PATCH 028/443] Fix illegal instruction caused by overflow in channel cloning --- src/libstd/sync/mpsc/shared.rs | 15 ++++++++++++--- src/libstd/sync/mpsc/sync.rs | 13 ++++++++++++- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/src/libstd/sync/mpsc/shared.rs b/src/libstd/sync/mpsc/shared.rs index baa4db7e5c0f..2a9618251ff5 100644 --- a/src/libstd/sync/mpsc/shared.rs +++ b/src/libstd/sync/mpsc/shared.rs @@ -21,6 +21,7 @@ pub use self::Failure::*; use core::cmp; +use core::intrinsics::abort; use core::isize; use sync::atomic::{AtomicUsize, AtomicIsize, AtomicBool, Ordering}; @@ -34,6 +35,7 @@ use time::Instant; const DISCONNECTED: isize = isize::MIN; const FUDGE: isize = 1024; +const MAX_REFCOUNT: usize = (isize::MAX) as usize; #[cfg(test)] const MAX_STEALS: isize = 5; #[cfg(not(test))] @@ -46,7 +48,7 @@ pub struct Packet { to_wake: AtomicUsize, // SignalToken for wake up // The number of channels which are currently using this packet. - channels: AtomicIsize, + channels: AtomicUsize, // See the discussion in Port::drop and the channel send methods for what // these are used for @@ -72,7 +74,7 @@ impl Packet { cnt: AtomicIsize::new(0), steals: 0, to_wake: AtomicUsize::new(0), - channels: AtomicIsize::new(2), + channels: AtomicUsize::new(2), port_dropped: AtomicBool::new(false), sender_drain: AtomicIsize::new(0), select_lock: Mutex::new(()), @@ -340,7 +342,14 @@ impl Packet { // Prepares this shared packet for a channel clone, essentially just bumping // a refcount. pub fn clone_chan(&mut self) { - self.channels.fetch_add(1, Ordering::SeqCst); + let old_count = self.channels.fetch_add(1, Ordering::SeqCst); + + // See comments on Arc::clone() on why we do this (for `mem::forget`). + if old_count > MAX_REFCOUNT { + unsafe { + abort(); + } + } } // Decrement the reference count on a channel. This is called whenever a diff --git a/src/libstd/sync/mpsc/sync.rs b/src/libstd/sync/mpsc/sync.rs index 9985daaba8f6..1d16e002a2be 100644 --- a/src/libstd/sync/mpsc/sync.rs +++ b/src/libstd/sync/mpsc/sync.rs @@ -36,6 +36,8 @@ pub use self::Failure::*; use self::Blocker::*; +use core::intrinsics::abort; +use core::isize; use core::mem; use core::ptr; @@ -45,6 +47,8 @@ use sync::mpsc::select::StartResult::{self, Installed, Abort}; use sync::{Mutex, MutexGuard}; use time::Instant; +const MAX_REFCOUNT: usize = (isize::MAX) as usize; + pub struct Packet { /// Only field outside of the mutex. Just done for kicks, but mainly because /// the other shared channel already had the code implemented @@ -350,7 +354,14 @@ impl Packet { // Prepares this shared packet for a channel clone, essentially just bumping // a refcount. pub fn clone_chan(&self) { - self.channels.fetch_add(1, Ordering::SeqCst); + let old_count = self.channels.fetch_add(1, Ordering::SeqCst); + + // See comments on Arc::clone() on why we do this (for `mem::forget`). + if old_count > MAX_REFCOUNT { + unsafe { + abort(); + } + } } pub fn drop_chan(&self) { From b56d61cfd7e1a0956406272268cb9659f384a304 Mon Sep 17 00:00:00 2001 From: Oliver Middleton Date: Sun, 28 Aug 2016 17:33:17 +0100 Subject: [PATCH 029/443] rustdoc: Fix associated consts in search results Associated consts can appear in none trait impls so need to be treated like methods when generating the search index. --- src/librustdoc/html/render.rs | 21 ++++++++++----------- src/test/rustdoc/auxiliary/issue-36031.rs | 21 +++++++++++++++++++++ src/test/rustdoc/issue-36031.rs | 19 +++++++++++++++++++ 3 files changed, 50 insertions(+), 11 deletions(-) create mode 100644 src/test/rustdoc/auxiliary/issue-36031.rs create mode 100644 src/test/rustdoc/issue-36031.rs diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 5cb5cc051870..688ee3824964 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -271,7 +271,7 @@ pub struct Cache { // then the fully qualified name of the structure isn't presented in `paths` // yet when its implementation methods are being indexed. Caches such methods // and their parent id here and indexes them at the end of crate parsing. - orphan_methods: Vec<(DefId, clean::Item)>, + orphan_impl_items: Vec<(DefId, clean::Item)>, } /// Temporary storage for data obtained during `RustdocVisitor::clean()`. @@ -528,7 +528,7 @@ pub fn run(mut krate: clean::Crate, seen_mod: false, stripped_mod: false, access_levels: krate.access_levels.clone(), - orphan_methods: Vec::new(), + orphan_impl_items: Vec::new(), traits: mem::replace(&mut krate.external_traits, FnvHashMap()), deref_trait_did: deref_trait_did, typarams: external_typarams, @@ -580,12 +580,12 @@ fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String { let mut crate_paths = Vec::::new(); let Cache { ref mut search_index, - ref orphan_methods, + ref orphan_impl_items, ref mut paths, .. } = *cache; - // Attach all orphan methods to the type's definition if the type + // Attach all orphan items to the type's definition if the type // has since been learned. - for &(did, ref item) in orphan_methods { + for &(did, ref item) in orphan_impl_items { if let Some(&(ref fqp, _)) = paths.get(&did) { search_index.push(IndexItem { ty: item_type(item), @@ -1023,7 +1023,7 @@ impl DocFolder for Cache { // Index this method for searching later on if let Some(ref s) = item.name { - let (parent, is_method) = match item.inner { + let (parent, is_inherent_impl_item) = match item.inner { clean::StrippedItem(..) => ((None, None), false), clean::AssociatedConstItem(..) | clean::TypedefItem(_, true) if self.parent_is_trait_impl => { @@ -1031,7 +1031,6 @@ impl DocFolder for Cache { ((None, None), false) } clean::AssociatedTypeItem(..) | - clean::AssociatedConstItem(..) | clean::TyMethodItem(..) | clean::StructFieldItem(..) | clean::VariantItem(..) => { @@ -1039,7 +1038,7 @@ impl DocFolder for Cache { Some(&self.stack[..self.stack.len() - 1])), false) } - clean::MethodItem(..) => { + clean::MethodItem(..) | clean::AssociatedConstItem(..) => { if self.parent_stack.is_empty() { ((None, None), false) } else { @@ -1064,7 +1063,7 @@ impl DocFolder for Cache { }; match parent { - (parent, Some(path)) if is_method || (!self.stripped_mod) => { + (parent, Some(path)) if is_inherent_impl_item || (!self.stripped_mod) => { debug_assert!(!item.is_stripped()); // A crate has a module at its root, containing all items, @@ -1082,10 +1081,10 @@ impl DocFolder for Cache { }); } } - (Some(parent), None) if is_method => { + (Some(parent), None) if is_inherent_impl_item => { // We have a parent, but we don't know where they're // defined yet. Wait for later to index this item. - self.orphan_methods.push((parent, item.clone())); + self.orphan_impl_items.push((parent, item.clone())); } _ => {} } diff --git a/src/test/rustdoc/auxiliary/issue-36031.rs b/src/test/rustdoc/auxiliary/issue-36031.rs new file mode 100644 index 000000000000..6b8a4b9f1370 --- /dev/null +++ b/src/test/rustdoc/auxiliary/issue-36031.rs @@ -0,0 +1,21 @@ +// 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. + +#![feature(associated_consts)] + +pub trait Foo { + const FOO: usize; +} + +pub struct Bar; + +impl Bar { + pub const BAR: usize = 3; +} diff --git a/src/test/rustdoc/issue-36031.rs b/src/test/rustdoc/issue-36031.rs new file mode 100644 index 000000000000..b025230f9182 --- /dev/null +++ b/src/test/rustdoc/issue-36031.rs @@ -0,0 +1,19 @@ +// 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. + +// aux-build:issue-36031.rs +// build-aux-docs +// ignore-cross-compile + +#![crate_name = "foo"] + +extern crate issue_36031; + +pub use issue_36031::Foo; From 5928be1d9bcd96ce4dd7b328fe527683a4e1621f Mon Sep 17 00:00:00 2001 From: philipp Date: Mon, 29 Aug 2016 19:43:18 +0200 Subject: [PATCH 030/443] Changed issue number to 36105 --- src/libcore/iter/iterator.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcore/iter/iterator.rs b/src/libcore/iter/iterator.rs index 48ea306ce5fd..f530009585ec 100644 --- a/src/libcore/iter/iterator.rs +++ b/src/libcore/iter/iterator.rs @@ -1678,7 +1678,7 @@ pub trait Iterator { /// assert_eq!(*a.iter().max_by(|x, y| x.cmp(y)).unwrap(), 5); /// ``` #[inline] - #[unstable(feature = "iter_max_by", issue="1722")] + #[unstable(feature = "iter_max_by", issue="36105")] fn max_by(self, mut compare: F) -> Option where Self: Sized, F: FnMut(&Self::Item, &Self::Item) -> Ordering, { @@ -1728,7 +1728,7 @@ pub trait Iterator { /// assert_eq!(*a.iter().min_by(|x, y| x.cmp(y)).unwrap(), -10); /// ``` #[inline] - #[unstable(feature = "iter_min_by", issue="1722")] + #[unstable(feature = "iter_min_by", issue="36105")] fn min_by(self, mut compare: F) -> Option where Self: Sized, F: FnMut(&Self::Item, &Self::Item) -> Ordering, { From 175d434c99a29de6bb9293a2fa3b7c94ef51c3da Mon Sep 17 00:00:00 2001 From: arthurprs Date: Mon, 29 Aug 2016 23:12:08 +0200 Subject: [PATCH 031/443] Remove BinaryHeap bounds checking --- src/libcollections/binary_heap.rs | 43 +++++++++++++++++-------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/src/libcollections/binary_heap.rs b/src/libcollections/binary_heap.rs index 5ece27372e13..0b923468c741 100644 --- a/src/libcollections/binary_heap.rs +++ b/src/libcollections/binary_heap.rs @@ -884,58 +884,61 @@ struct Hole<'a, T: 'a> { impl<'a, T> Hole<'a, T> { /// Create a new Hole at index `pos`. - fn new(data: &'a mut [T], pos: usize) -> Self { - unsafe { - let elt = ptr::read(&data[pos]); - Hole { - data: data, - elt: Some(elt), - pos: pos, - } + /// + /// Unsafe because pos must be within the data slice. + #[inline] + unsafe fn new(data: &'a mut [T], pos: usize) -> Self { + debug_assert!(pos < data.len()); + let elt = ptr::read(&data[pos]); + Hole { + data: data, + elt: Some(elt), + pos: pos, } } - #[inline(always)] + #[inline] fn pos(&self) -> usize { self.pos } /// Return a reference to the element removed - #[inline(always)] + #[inline] fn element(&self) -> &T { self.elt.as_ref().unwrap() } /// Return a reference to the element at `index`. /// - /// Panics if the index is out of bounds. - /// - /// Unsafe because index must not equal pos. - #[inline(always)] + /// Unsafe because index must be within the data slice and not equal to pos. + #[inline] unsafe fn get(&self, index: usize) -> &T { debug_assert!(index != self.pos); - &self.data[index] + debug_assert!(index < self.data.len()); + self.data.get_unchecked(index) } /// Move hole to new location /// - /// Unsafe because index must not equal pos. - #[inline(always)] + /// Unsafe because index must be within the data slice and not equal to pos. + #[inline] unsafe fn move_to(&mut self, index: usize) { debug_assert!(index != self.pos); - let index_ptr: *const _ = &self.data[index]; - let hole_ptr = &mut self.data[self.pos]; + debug_assert!(index < self.data.len()); + let index_ptr: *const _ = self.data.get_unchecked(index); + let hole_ptr = self.data.get_unchecked_mut(self.pos); ptr::copy_nonoverlapping(index_ptr, hole_ptr, 1); self.pos = index; } } impl<'a, T> Drop for Hole<'a, T> { + #[inline] fn drop(&mut self) { // fill the hole again unsafe { let pos = self.pos; - ptr::write(&mut self.data[pos], self.elt.take().unwrap()); + ptr::write(self.data.get_unchecked_mut(pos), self.elt.take().unwrap()); } } } From 516519ee9af3235d5a5ed9bb7afa5bb1a27a8ddf Mon Sep 17 00:00:00 2001 From: CensoredUsername Date: Mon, 27 Jun 2016 02:34:02 +0200 Subject: [PATCH 032/443] Allow specification of the system V AMD64 ABI constraint. This can be specified using `extern sysV64 fn` on all platforms --- src/doc/book/ffi.md | 1 + src/librustc_llvm/ffi.rs | 1 + src/librustc_trans/abi.rs | 1 + src/libsyntax/abi.rs | 2 ++ 4 files changed, 5 insertions(+) diff --git a/src/doc/book/ffi.md b/src/doc/book/ffi.md index ca104ff29ace..44cc75f8fed1 100644 --- a/src/doc/book/ffi.md +++ b/src/doc/book/ffi.md @@ -539,6 +539,7 @@ This is currently hidden behind the `abi_vectorcall` gate and is subject to chan * `system` * `C` * `win64` +* `sysV64` Most of the abis in this list are self-explanatory, but the `system` abi may seem a little odd. This constraint selects whatever the appropriate ABI is for diff --git a/src/librustc_llvm/ffi.rs b/src/librustc_llvm/ffi.rs index 754910c246d6..92fe568a72c5 100644 --- a/src/librustc_llvm/ffi.rs +++ b/src/librustc_llvm/ffi.rs @@ -42,6 +42,7 @@ pub enum CallConv { ColdCallConv = 9, X86StdcallCallConv = 64, X86FastcallCallConv = 65, + X86_64_SysV = 78, X86_64_Win64 = 79, X86_VectorCall = 80 } diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs index 3a7fde6a36ba..9f3c20a4fd09 100644 --- a/src/librustc_trans/abi.rs +++ b/src/librustc_trans/abi.rs @@ -269,6 +269,7 @@ impl FnType { Vectorcall => llvm::X86_VectorCall, C => llvm::CCallConv, Win64 => llvm::X86_64_Win64, + SysV64 => llvm::X86_64_SysV, // These API constants ought to be more specific... Cdecl => llvm::CCallConv, diff --git a/src/libsyntax/abi.rs b/src/libsyntax/abi.rs index c959e2108f5a..9fb2b539b8fe 100644 --- a/src/libsyntax/abi.rs +++ b/src/libsyntax/abi.rs @@ -39,6 +39,7 @@ pub enum Abi { Vectorcall, Aapcs, Win64, + SysV64, // Multiplatform ABIs second Rust, @@ -86,6 +87,7 @@ const AbiDatas: &'static [AbiData] = &[ AbiData {abi: Abi::Vectorcall, name: "vectorcall"}, AbiData {abi: Abi::Aapcs, name: "aapcs" }, AbiData {abi: Abi::Win64, name: "win64" }, + AbiData {abi: Abi::SysV64, name: "sysV64" }, // Cross-platform ABIs // From 30c4173cb8f942afbb1588174e5867eb780cdaa0 Mon Sep 17 00:00:00 2001 From: CensoredUsername Date: Thu, 7 Jul 2016 10:27:30 +0200 Subject: [PATCH 033/443] Change ABI string from sysV64 to sysv64 --- src/doc/book/ffi.md | 2 +- src/libsyntax/abi.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/book/ffi.md b/src/doc/book/ffi.md index 44cc75f8fed1..1dea15311ce8 100644 --- a/src/doc/book/ffi.md +++ b/src/doc/book/ffi.md @@ -539,7 +539,7 @@ This is currently hidden behind the `abi_vectorcall` gate and is subject to chan * `system` * `C` * `win64` -* `sysV64` +* `sysv64` Most of the abis in this list are self-explanatory, but the `system` abi may seem a little odd. This constraint selects whatever the appropriate ABI is for diff --git a/src/libsyntax/abi.rs b/src/libsyntax/abi.rs index 9fb2b539b8fe..64a71133a8c0 100644 --- a/src/libsyntax/abi.rs +++ b/src/libsyntax/abi.rs @@ -87,7 +87,7 @@ const AbiDatas: &'static [AbiData] = &[ AbiData {abi: Abi::Vectorcall, name: "vectorcall"}, AbiData {abi: Abi::Aapcs, name: "aapcs" }, AbiData {abi: Abi::Win64, name: "win64" }, - AbiData {abi: Abi::SysV64, name: "sysV64" }, + AbiData {abi: Abi::SysV64, name: "sysv64" }, // Cross-platform ABIs // From 0e58a5d139772404ab936b6c7679e9ff936101c4 Mon Sep 17 00:00:00 2001 From: CensoredUsername Date: Sat, 27 Aug 2016 15:14:51 +0200 Subject: [PATCH 034/443] Feature gate the sysv64 abi as feature(abi_sysv64) and add tests --- src/libsyntax/feature_gate.rs | 23 +++- src/test/codegen/abi-sysv64.rs | 24 ++++ .../compile-fail/feature-gate-abi-sysv64.rs | 19 +++ .../run-pass/abi-sysv64-register-usage.rs | 125 ++++++++++++++++++ 4 files changed, 184 insertions(+), 7 deletions(-) create mode 100644 src/test/codegen/abi-sysv64.rs create mode 100644 src/test/compile-fail/feature-gate-abi-sysv64.rs create mode 100644 src/test/run-pass/abi-sysv64-register-usage.rs diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 1e15c1563561..18924a3dc253 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -281,7 +281,11 @@ declare_features! ( (active, never_type, "1.13.0", Some(35121)), // Allows all literals in attribute lists and values of key-value pairs. - (active, attr_literals, "1.13.0", Some(34981)) + (active, attr_literals, "1.13.0", Some(34981)), + + // Allows the sysV64 ABI to be specified on all platforms + // instead of just the platforms on which it is the C ABI + (active, abi_sysv64, "1.13.0", None) ); declare_features! ( @@ -811,21 +815,26 @@ macro_rules! gate_feature_post { impl<'a> PostExpansionVisitor<'a> { fn check_abi(&self, abi: Abi, span: Span) { match abi { - Abi::RustIntrinsic => + Abi::RustIntrinsic => { gate_feature_post!(&self, intrinsics, span, - "intrinsics are subject to change"), + "intrinsics are subject to change"); + }, Abi::PlatformIntrinsic => { gate_feature_post!(&self, platform_intrinsics, span, - "platform intrinsics are experimental and possibly buggy") + "platform intrinsics are experimental and possibly buggy"); }, Abi::Vectorcall => { gate_feature_post!(&self, abi_vectorcall, span, - "vectorcall is experimental and subject to change") - } + "vectorcall is experimental and subject to change"); + }, Abi::RustCall => { gate_feature_post!(&self, unboxed_closures, span, "rust-call ABI is subject to change"); - } + }, + Abi::SysV64 => { + gate_feature_post!(&self, abi_sysv64, span, + "sysv64 ABI is experimental and subject to change"); + }, _ => {} } } diff --git a/src/test/codegen/abi-sysv64.rs b/src/test/codegen/abi-sysv64.rs new file mode 100644 index 000000000000..2b8e8a1b6b2c --- /dev/null +++ b/src/test/codegen/abi-sysv64.rs @@ -0,0 +1,24 @@ +// 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. + +// Checks if the correct annotation for the sysv64 ABI is passed to +// llvm. Also checks that the abi-sysv64 feature gate allows usage +// of the sysv64 abi. + +// compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] +#![feature(abi_sysv64)] + +// CHECK: define x86_64_sysvcc i64 @has_sysv64_abi +#[no_mangle] +pub extern "sysv64" fn has_sysv64_abi(a: i64) -> i64 { + a * 2 +} diff --git a/src/test/compile-fail/feature-gate-abi-sysv64.rs b/src/test/compile-fail/feature-gate-abi-sysv64.rs new file mode 100644 index 000000000000..2a4aae8c06bb --- /dev/null +++ b/src/test/compile-fail/feature-gate-abi-sysv64.rs @@ -0,0 +1,19 @@ +// 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. + +// Test that the sysv64 ABI cannot be used when abi-sysv64 feature +// gate is not used. + +extern "sysv64" fn foo() {} +//~^ ERROR sysv64 ABI is experimental and subject to change + +fn main() { + foo(); +} diff --git a/src/test/run-pass/abi-sysv64-register-usage.rs b/src/test/run-pass/abi-sysv64-register-usage.rs new file mode 100644 index 000000000000..5e58240359e6 --- /dev/null +++ b/src/test/run-pass/abi-sysv64-register-usage.rs @@ -0,0 +1,125 @@ +// 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. + +// Checks if the correct registers are being used to pass arguments +// when the sysv64 ABI is specified. + +#![feature(abi_sysv64)] +#![feature(naked_functions)] +#![feature(asm)] + +#[naked] +#[inline(never)] +#[allow(unused_variables)] +pub unsafe extern "sysv64" fn all_the_registers(rdi: i64, rsi: i64, rdx: i64, + rcx: i64, r8 : i64, r9 : i64, + xmm0: f32, xmm1: f32, xmm2: f32, + xmm3: f32, xmm4: f32, xmm5: f32, + xmm6: f32, xmm7: f32) -> i64 { + // this assembly checks all registers for specific values, and puts in rax + // how many values were correct. + asm!("cmp rdi, 0x1; + xor rax, rax; + setz al; + + cmp rsi, 0x2; + xor rdi, rdi + setz dil; + add rax, rdi; + + cmp rdx, 0x3; + setz dil; + add rax, rdi; + + cmp rcx, 0x4; + setz dil; + add rax, rdi; + + cmp r8, 0x5; + setz dil; + add rax, rdi; + + cmp r9, 0x6; + setz dil; + add rax, rdi; + + movd esi, xmm0; + cmp rsi, 0x3F800000; + setz dil; + add rax, rdi; + + movd esi, xmm1; + cmp rsi, 0x40000000; + setz dil; + add rax, rdi; + + movd esi, xmm2; + cmp rsi, 0x40800000; + setz dil; + add rax, rdi; + + movd esi, xmm3; + cmp rsi, 0x41000000; + setz dil; + add rax, rdi; + + movd esi, xmm4; + cmp rsi, 0x41800000; + setz dil; + add rax, rdi; + + movd esi, xmm5; + cmp rsi, 0x42000000; + setz dil; + add rax, rdi; + + movd esi, xmm6; + cmp rsi, 0x42800000; + setz dil; + add rax, rdi; + + movd esi, xmm7; + cmp rsi, 0x43000000; + setz dil; + add rax, rdi; + ret + " :::: "intel"); + unreachable!(); +} + +// this struct contains 8 i64's, while only 6 can be passed in registers. +#[derive(PartialEq, Eq, Debug)] +pub struct LargeStruct(i64, i64, i64, i64, i64, i64, i64, i64); + +#[inline(never)] +pub extern "sysv64" fn large_struct_by_val(mut foo: LargeStruct) -> LargeStruct { + foo.0 *= 1; + foo.1 *= 2; + foo.2 *= 3; + foo.3 *= 4; + foo.4 *= 5; + foo.5 *= 6; + foo.6 *= 7; + foo.7 *= 8; + foo +} + +pub fn main() { + assert_eq!(unsafe { + all_the_registers(1, 2, 3, 4, 5, 6, + 1.0, 2.0, 4.0, 8.0, + 16.0, 32.0, 64.0, 128.0) + }, 14); + + assert_eq!( + large_struct_by_val(LargeStruct(1, 2, 3, 4, 5, 6, 7, 8)), + LargeStruct(1, 4, 9, 16, 25, 36, 49, 64) + ); +} From eef4434bf8ebcf2f9377166ff069656a1708586d Mon Sep 17 00:00:00 2001 From: CensoredUsername Date: Sat, 27 Aug 2016 19:45:15 +0200 Subject: [PATCH 035/443] Add the sysv64 calling convention to the list of known calling conventions and add the feature(abi_sysv64) to the list of known features --- src/doc/reference.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/doc/reference.md b/src/doc/reference.md index be3559a58808..ec2d3e2822e2 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -1677,6 +1677,7 @@ There are also some platform-specific ABI strings: * `extern "cdecl"` -- The default for x86\_32 C code. * `extern "stdcall"` -- The default for the Win32 API on x86\_32. * `extern "win64"` -- The default for C code on x86\_64 Windows. +* `extern "sysv64"` -- The default for C code on non-Windows x86\_64. * `extern "aapcs"` -- The default for ARM. * `extern "fastcall"` -- The `fastcall` ABI -- corresponds to MSVC's `__fastcall` and GCC and clang's `__attribute__((fastcall))` @@ -2485,6 +2486,9 @@ The currently implemented features of the reference compiler are: * - `dotdot_in_tuple_patterns` - Allows `..` in tuple (struct) patterns. +* - `abi_sysv64` - Allows the usage of the system V AMD64 calling convention + (e.g. `extern "sysv64" func fn_();`) + If a feature is promoted to a language feature, then all existing programs will start to receive compilation warnings about `#![feature]` directives which enabled the new feature (because the directive is no longer necessary). However, if a From 0e30446259be88af7b9ae6c733b49fc0c88bd7ce Mon Sep 17 00:00:00 2001 From: CensoredUsername Date: Tue, 30 Aug 2016 03:54:29 +0200 Subject: [PATCH 036/443] Select the proper x86_64 ABI based first and foremost on the specified calling convention instead of just looking at the selected platform --- src/librustc_trans/abi.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs index 9f3c20a4fd09..7f209dde27db 100644 --- a/src/librustc_trans/abi.rs +++ b/src/librustc_trans/abi.rs @@ -484,7 +484,9 @@ impl FnType { match &ccx.sess().target.target.arch[..] { "x86" => cabi_x86::compute_abi_info(ccx, self), - "x86_64" => if ccx.sess().target.target.options.is_like_windows { + "x86_64" => if abi == Abi::SysV64 { + cabi_x86_64::compute_abi_info(ccx, self); + } else if abi == Abi::Win64 || ccx.sess().target.target.options.is_like_windows { cabi_x86_win64::compute_abi_info(ccx, self); } else { cabi_x86_64::compute_abi_info(ccx, self); From d282a633fa6f511f087a53976ce71c269d14c861 Mon Sep 17 00:00:00 2001 From: CensoredUsername Date: Sat, 27 Aug 2016 20:29:14 +0200 Subject: [PATCH 037/443] Guard against platforms on which the sysv64 calling convention is not valid in non-codegen tests. Remove false positive in a test that relied on the exact formatting of an error string and rewrite the sysv64 register allocation test at it was triggering undefined behaviour --- .../compile-fail/feature-gate-abi-sysv64.rs | 6 + .../run-pass/abi-sysv64-register-usage.rs | 147 ++++++++---------- src/test/ui/codemap_tests/unicode.stderr | 2 +- 3 files changed, 71 insertions(+), 84 deletions(-) diff --git a/src/test/compile-fail/feature-gate-abi-sysv64.rs b/src/test/compile-fail/feature-gate-abi-sysv64.rs index 2a4aae8c06bb..d7c012743231 100644 --- a/src/test/compile-fail/feature-gate-abi-sysv64.rs +++ b/src/test/compile-fail/feature-gate-abi-sysv64.rs @@ -11,9 +11,15 @@ // Test that the sysv64 ABI cannot be used when abi-sysv64 feature // gate is not used. +// ignore-android +// ignore-arm +// ignore-aarch64 + +#[cfg(target_arch = "x86_64")] extern "sysv64" fn foo() {} //~^ ERROR sysv64 ABI is experimental and subject to change +#[cfg(target_arch = "x86_64")] fn main() { foo(); } diff --git a/src/test/run-pass/abi-sysv64-register-usage.rs b/src/test/run-pass/abi-sysv64-register-usage.rs index 5e58240359e6..7e3b32122ac2 100644 --- a/src/test/run-pass/abi-sysv64-register-usage.rs +++ b/src/test/run-pass/abi-sysv64-register-usage.rs @@ -11,93 +11,42 @@ // Checks if the correct registers are being used to pass arguments // when the sysv64 ABI is specified. +// ignore-android +// ignore-arm +// ignore-aarch64 + #![feature(abi_sysv64)] -#![feature(naked_functions)] #![feature(asm)] -#[naked] -#[inline(never)] -#[allow(unused_variables)] -pub unsafe extern "sysv64" fn all_the_registers(rdi: i64, rsi: i64, rdx: i64, - rcx: i64, r8 : i64, r9 : i64, - xmm0: f32, xmm1: f32, xmm2: f32, - xmm3: f32, xmm4: f32, xmm5: f32, - xmm6: f32, xmm7: f32) -> i64 { - // this assembly checks all registers for specific values, and puts in rax - // how many values were correct. - asm!("cmp rdi, 0x1; - xor rax, rax; - setz al; - - cmp rsi, 0x2; - xor rdi, rdi - setz dil; - add rax, rdi; - - cmp rdx, 0x3; - setz dil; - add rax, rdi; - - cmp rcx, 0x4; - setz dil; - add rax, rdi; - - cmp r8, 0x5; - setz dil; - add rax, rdi; - - cmp r9, 0x6; - setz dil; - add rax, rdi; - - movd esi, xmm0; - cmp rsi, 0x3F800000; - setz dil; - add rax, rdi; - - movd esi, xmm1; - cmp rsi, 0x40000000; - setz dil; - add rax, rdi; - - movd esi, xmm2; - cmp rsi, 0x40800000; - setz dil; - add rax, rdi; - - movd esi, xmm3; - cmp rsi, 0x41000000; - setz dil; - add rax, rdi; - - movd esi, xmm4; - cmp rsi, 0x41800000; - setz dil; - add rax, rdi; - - movd esi, xmm5; - cmp rsi, 0x42000000; - setz dil; - add rax, rdi; - - movd esi, xmm6; - cmp rsi, 0x42800000; - setz dil; - add rax, rdi; - - movd esi, xmm7; - cmp rsi, 0x43000000; - setz dil; - add rax, rdi; - ret - " :::: "intel"); - unreachable!(); +#[cfg(target_arch = "x86_64")] +pub extern "sysv64" fn all_the_registers(rdi: i64, rsi: i64, rdx: i64, + rcx: i64, r8 : i64, r9 : i64, + xmm0: f32, xmm1: f32, xmm2: f32, + xmm3: f32, xmm4: f32, xmm5: f32, + xmm6: f32, xmm7: f32) -> i64 { + assert_eq!(rdi, 1); + assert_eq!(rsi, 2); + assert_eq!(rdx, 3); + assert_eq!(rcx, 4); + assert_eq!(r8, 5); + assert_eq!(r9, 6); + assert_eq!(xmm0, 1.0f32); + assert_eq!(xmm1, 2.0f32); + assert_eq!(xmm2, 4.0f32); + assert_eq!(xmm3, 8.0f32); + assert_eq!(xmm4, 16.0f32); + assert_eq!(xmm5, 32.0f32); + assert_eq!(xmm6, 64.0f32); + assert_eq!(xmm7, 128.0f32); + 42 } // this struct contains 8 i64's, while only 6 can be passed in registers. +#[cfg(target_arch = "x86_64")] #[derive(PartialEq, Eq, Debug)] pub struct LargeStruct(i64, i64, i64, i64, i64, i64, i64, i64); +#[cfg(target_arch = "x86_64")] #[inline(never)] pub extern "sysv64" fn large_struct_by_val(mut foo: LargeStruct) -> LargeStruct { foo.0 *= 1; @@ -111,15 +60,47 @@ pub extern "sysv64" fn large_struct_by_val(mut foo: LargeStruct) -> LargeStruct foo } +#[cfg(target_arch = "x86_64")] pub fn main() { - assert_eq!(unsafe { - all_the_registers(1, 2, 3, 4, 5, 6, - 1.0, 2.0, 4.0, 8.0, - 16.0, 32.0, 64.0, 128.0) - }, 14); + let result: i64; + unsafe { + asm!("mov rdi, 1; + mov rsi, 2; + mov rdx, 3; + mov rcx, 4; + mov r8, 5; + mov r9, 6; + mov eax, 0x3F800000; + movd xmm0, eax; + mov eax, 0x40000000; + movd xmm1, eax; + mov eax, 0x40800000; + movd xmm2, eax; + mov eax, 0x41000000; + movd xmm3, eax; + mov eax, 0x41800000; + movd xmm4, eax; + mov eax, 0x42000000; + movd xmm5, eax; + mov eax, 0x42800000; + movd xmm6, eax; + mov eax, 0x43000000; + movd xmm7, eax; + call r10 + " + : "={rax}"(result) + : "{r10}"(all_the_registers as usize) + : "rdi", "rsi", "rdx", "rcx", "r8", "r9", "r11", "cc", "memory" + : "intel", "alignstack" + ) + } + assert_eq!(result, 42); assert_eq!( large_struct_by_val(LargeStruct(1, 2, 3, 4, 5, 6, 7, 8)), LargeStruct(1, 4, 9, 16, 25, 36, 49, 64) ); } + +#[cfg(not(target_arch = "x86_64"))] +pub fn main() {} \ No newline at end of file diff --git a/src/test/ui/codemap_tests/unicode.stderr b/src/test/ui/codemap_tests/unicode.stderr index aa42ae341c54..a748e13ecf10 100644 --- a/src/test/ui/codemap_tests/unicode.stderr +++ b/src/test/ui/codemap_tests/unicode.stderr @@ -1,4 +1,4 @@ -error: invalid ABI: expected one of [cdecl, stdcall, fastcall, vectorcall, aapcs, win64, Rust, C, system, rust-intrinsic, rust-call, platform-intrinsic], found `路濫狼á́́` +error: invalid ABI: expected one of [cdecl, stdcall, fastcall, vectorcall, aapcs, win64, sysv64, Rust, C, system, rust-intrinsic, rust-call, platform-intrinsic], found `路濫狼á́́` --> $DIR/unicode.rs:11:8 | 11 | extern "路濫狼á́́" fn foo() {} From 46a719e2ccc03f22537b1a3ce9e345770ca4e1ba Mon Sep 17 00:00:00 2001 From: CensoredUsername Date: Tue, 30 Aug 2016 03:24:34 +0200 Subject: [PATCH 038/443] Remove useless //ignore-arch directives on a compile-fail test, and add another test that checks if the sysv64 abi corresponds to the same rules as the C abi on unix platforms --- .../compile-fail/feature-gate-abi-sysv64.rs | 6 - src/test/run-pass/abi-sysv64-arg-passing.rs | 341 ++++++++++++++++++ 2 files changed, 341 insertions(+), 6 deletions(-) create mode 100644 src/test/run-pass/abi-sysv64-arg-passing.rs diff --git a/src/test/compile-fail/feature-gate-abi-sysv64.rs b/src/test/compile-fail/feature-gate-abi-sysv64.rs index d7c012743231..2a4aae8c06bb 100644 --- a/src/test/compile-fail/feature-gate-abi-sysv64.rs +++ b/src/test/compile-fail/feature-gate-abi-sysv64.rs @@ -11,15 +11,9 @@ // Test that the sysv64 ABI cannot be used when abi-sysv64 feature // gate is not used. -// ignore-android -// ignore-arm -// ignore-aarch64 - -#[cfg(target_arch = "x86_64")] extern "sysv64" fn foo() {} //~^ ERROR sysv64 ABI is experimental and subject to change -#[cfg(target_arch = "x86_64")] fn main() { foo(); } diff --git a/src/test/run-pass/abi-sysv64-arg-passing.rs b/src/test/run-pass/abi-sysv64-arg-passing.rs new file mode 100644 index 000000000000..3f6ae71ffa8e --- /dev/null +++ b/src/test/run-pass/abi-sysv64-arg-passing.rs @@ -0,0 +1,341 @@ +// 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. + +// Checks if the "sysv64" calling convention behaves the same as the +// "C" calling convention on platforms where both should be the same + +// This file contains versions of the following run-pass tests with +// the calling convention changed to "sysv64" + +// cabi-int-widening +// extern-pass-char +// extern-pass-u32 +// extern-pass-u64 +// extern-pass-double +// extern-pass-empty +// extern-pass-TwoU8s +// extern-pass-TwoU16s +// extern-pass-TwoU32s +// extern-pass-TwoU64s +// extern-return-TwoU8s +// extern-return-TwoU16s +// extern-return-TwoU32s +// extern-return-TwoU64s +// foreign-fn-with-byval +// issue-28676 +// struct-return + +// ignore-android +// ignore-arm +// ignore-aarch64 +// ignore-msvc + +// note: msvc is ignored as rust_test_helpers does not have the sysv64 abi on msvc + +#![feature(abi_sysv64)] +#[allow(dead_code)] +#[allow(improper_ctypes)] + +#[cfg(target_arch = "x86_64")] +mod tests { + #[repr(C)] + #[derive(Copy, Clone, PartialEq, Debug)] + pub struct TwoU8s { + one: u8, two: u8 + } + + #[repr(C)] + #[derive(Copy, Clone, PartialEq, Debug)] + pub struct TwoU16s { + one: u16, two: u16 + } + + #[repr(C)] + #[derive(Copy, Clone, PartialEq, Debug)] + pub struct TwoU32s { + one: u32, two: u32 + } + + #[repr(C)] + #[derive(Copy, Clone, PartialEq, Debug)] + pub struct TwoU64s { + one: u64, two: u64 + } + + #[repr(C)] + pub struct ManyInts { + arg1: i8, + arg2: i16, + arg3: i32, + arg4: i16, + arg5: i8, + arg6: TwoU8s, + } + + #[repr(C)] + pub struct Empty; + + #[repr(C)] + #[derive(Copy, Clone)] + pub struct S { + x: u64, + y: u64, + z: u64, + } + + #[repr(C)] + #[derive(Copy, Clone)] + pub struct Quad { a: u64, b: u64, c: u64, d: u64 } + + #[repr(C)] + #[derive(Copy, Clone)] + pub struct Floats { a: f64, b: u8, c: f64 } + + #[link(name = "rust_test_helpers")] + extern "sysv64" { + pub fn rust_int8_to_int32(_: i8) -> i32; + pub fn rust_dbg_extern_identity_u8(v: u8) -> u8; + pub fn rust_dbg_extern_identity_u32(v: u32) -> u32; + pub fn rust_dbg_extern_identity_u64(v: u64) -> u64; + pub fn rust_dbg_extern_identity_double(v: f64) -> f64; + pub fn rust_dbg_extern_empty_struct(v1: ManyInts, e: Empty, v2: ManyInts); + pub fn rust_dbg_extern_identity_TwoU8s(v: TwoU8s) -> TwoU8s; + pub fn rust_dbg_extern_identity_TwoU16s(v: TwoU16s) -> TwoU16s; + pub fn rust_dbg_extern_identity_TwoU32s(v: TwoU32s) -> TwoU32s; + pub fn rust_dbg_extern_identity_TwoU64s(v: TwoU64s) -> TwoU64s; + pub fn rust_dbg_extern_return_TwoU8s() -> TwoU8s; + pub fn rust_dbg_extern_return_TwoU16s() -> TwoU16s; + pub fn rust_dbg_extern_return_TwoU32s() -> TwoU32s; + pub fn rust_dbg_extern_return_TwoU64s() -> TwoU64s; + pub fn get_x(x: S) -> u64; + pub fn get_y(x: S) -> u64; + pub fn get_z(x: S) -> u64; + pub fn get_c_many_params(_: *const (), _: *const (), + _: *const (), _: *const (), f: Quad) -> u64; + pub fn rust_dbg_abi_1(q: Quad) -> Quad; + pub fn rust_dbg_abi_2(f: Floats) -> Floats; + } + + pub fn cabi_int_widening() { + let x = unsafe { + rust_int8_to_int32(-1) + }; + + assert!(x == -1); + } + + pub fn extern_pass_char() { + unsafe { + assert_eq!(22, rust_dbg_extern_identity_u8(22)); + } + } + + pub fn extern_pass_u32() { + unsafe { + assert_eq!(22, rust_dbg_extern_identity_u32(22)); + } + } + + pub fn extern_pass_u64() { + unsafe { + assert_eq!(22, rust_dbg_extern_identity_u64(22)); + } + } + + pub fn extern_pass_double() { + unsafe { + assert_eq!(22.0_f64, rust_dbg_extern_identity_double(22.0_f64)); + } + } + + pub fn extern_pass_empty() { + unsafe { + let x = ManyInts { + arg1: 2, + arg2: 3, + arg3: 4, + arg4: 5, + arg5: 6, + arg6: TwoU8s { one: 7, two: 8, } + }; + let y = ManyInts { + arg1: 1, + arg2: 2, + arg3: 3, + arg4: 4, + arg5: 5, + arg6: TwoU8s { one: 6, two: 7, } + }; + let empty = Empty; + rust_dbg_extern_empty_struct(x, empty, y); + } + } + + pub fn extern_pass_twou8s() { + unsafe { + let x = TwoU8s {one: 22, two: 23}; + let y = rust_dbg_extern_identity_TwoU8s(x); + assert_eq!(x, y); + } + } + + pub fn extern_pass_twou16s() { + unsafe { + let x = TwoU16s {one: 22, two: 23}; + let y = rust_dbg_extern_identity_TwoU16s(x); + assert_eq!(x, y); + } + } + + pub fn extern_pass_twou32s() { + unsafe { + let x = TwoU32s {one: 22, two: 23}; + let y = rust_dbg_extern_identity_TwoU32s(x); + assert_eq!(x, y); + } + } + + pub fn extern_pass_twou64s() { + unsafe { + let x = TwoU64s {one: 22, two: 23}; + let y = rust_dbg_extern_identity_TwoU64s(x); + assert_eq!(x, y); + } + } + + pub fn extern_return_twou8s() { + unsafe { + let y = rust_dbg_extern_return_TwoU8s(); + assert_eq!(y.one, 10); + assert_eq!(y.two, 20); + } + } + + pub fn extern_return_twou16s() { + unsafe { + let y = rust_dbg_extern_return_TwoU16s(); + assert_eq!(y.one, 10); + assert_eq!(y.two, 20); + } + } + + pub fn extern_return_twou32s() { + unsafe { + let y = rust_dbg_extern_return_TwoU32s(); + assert_eq!(y.one, 10); + assert_eq!(y.two, 20); + } + } + + pub fn extern_return_twou64s() { + unsafe { + let y = rust_dbg_extern_return_TwoU64s(); + assert_eq!(y.one, 10); + assert_eq!(y.two, 20); + } + } + + #[inline(never)] + fn indirect_call(func: unsafe extern "sysv64" fn(s: S) -> u64, s: S) -> u64 { + unsafe { + func(s) + } + } + + pub fn foreign_fn_with_byval() { + let s = S { x: 1, y: 2, z: 3 }; + assert_eq!(s.x, indirect_call(get_x, s)); + assert_eq!(s.y, indirect_call(get_y, s)); + assert_eq!(s.z, indirect_call(get_z, s)); + } + + fn test() { + use std::ptr; + unsafe { + let null = ptr::null(); + let q = Quad { + a: 1, + b: 2, + c: 3, + d: 4 + }; + assert_eq!(get_c_many_params(null, null, null, null, q), q.c); + } + } + + pub fn issue_28676() { + test(); + } + + fn test1() { + unsafe { + let q = Quad { a: 0xaaaa_aaaa_aaaa_aaaa, + b: 0xbbbb_bbbb_bbbb_bbbb, + c: 0xcccc_cccc_cccc_cccc, + d: 0xdddd_dddd_dddd_dddd }; + let qq = rust_dbg_abi_1(q); + println!("a: {:x}", qq.a as usize); + println!("b: {:x}", qq.b as usize); + println!("c: {:x}", qq.c as usize); + println!("d: {:x}", qq.d as usize); + assert_eq!(qq.a, q.c + 1); + assert_eq!(qq.b, q.d - 1); + assert_eq!(qq.c, q.a + 1); + assert_eq!(qq.d, q.b - 1); + } + } + + fn test2() { + unsafe { + let f = Floats { a: 1.234567890e-15_f64, + b: 0b_1010_1010, + c: 1.0987654321e-15_f64 }; + let ff = rust_dbg_abi_2(f); + println!("a: {}", ff.a as f64); + println!("b: {}", ff.b as usize); + println!("c: {}", ff.c as f64); + assert_eq!(ff.a, f.c + 1.0f64); + assert_eq!(ff.b, 0xff); + assert_eq!(ff.c, f.a - 1.0f64); + } + } + + pub fn struct_return() { + test1(); + test2(); + } +} + +#[cfg(target_arch = "x86_64")] +fn main() { + use tests::*; + cabi_int_widening(); + extern_pass_char(); + extern_pass_u32(); + extern_pass_u64(); + extern_pass_double(); + extern_pass_empty(); + extern_pass_twou8s(); + extern_pass_twou16s(); + extern_pass_twou32s(); + extern_pass_twou64s(); + extern_return_twou8s(); + extern_return_twou16s(); + extern_return_twou32s(); + extern_return_twou64s(); + foreign_fn_with_byval(); + issue_28676(); + struct_return(); +} + +#[cfg(not(target_arch = "x86_64"))] +fn main() { + +} From bab60124a5069ae6be3591ee43632de8b848c5fd Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 30 Aug 2016 10:21:33 -0500 Subject: [PATCH 039/443] rustbuild: fix building std for musl targets closes #36143 --- src/bootstrap/compile.rs | 6 +++--- src/libstd/build.rs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 155848901cdb..6b3b5cf8cda7 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -93,16 +93,16 @@ pub fn std_link(build: &Build, add_to_sysroot(&out_dir, &libdir); if target.contains("musl") && !target.contains("mips") { - copy_third_party_objects(build, target, &libdir); + copy_third_party_objects(build, &libdir); } } /// Copies the crt(1,i,n).o startup objects /// /// Only required for musl targets that statically link to libc -fn copy_third_party_objects(build: &Build, target: &str, into: &Path) { +fn copy_third_party_objects(build: &Build, into: &Path) { for &obj in &["crt1.o", "crti.o", "crtn.o"] { - copy(&compiler_file(build.cc(target), obj), &into.join(obj)); + copy(&build.config.musl_root.as_ref().unwrap().join("lib").join(obj), &into.join(obj)); } } diff --git a/src/libstd/build.rs b/src/libstd/build.rs index 9018e48d06bd..535ce53a0fbd 100644 --- a/src/libstd/build.rs +++ b/src/libstd/build.rs @@ -35,7 +35,7 @@ fn main() { println!("cargo:rustc-link-lib=dl"); println!("cargo:rustc-link-lib=log"); println!("cargo:rustc-link-lib=gcc"); - } else { + } else if !target.contains("musl") { println!("cargo:rustc-link-lib=dl"); println!("cargo:rustc-link-lib=rt"); println!("cargo:rustc-link-lib=pthread"); From 8f8d88290be865f411afed0fb1132af1959362a9 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 30 Aug 2016 10:25:43 -0500 Subject: [PATCH 040/443] for mips-musl pass -ldl and co to the linker --- src/libstd/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/build.rs b/src/libstd/build.rs index 535ce53a0fbd..2d540c6b59ac 100644 --- a/src/libstd/build.rs +++ b/src/libstd/build.rs @@ -35,7 +35,7 @@ fn main() { println!("cargo:rustc-link-lib=dl"); println!("cargo:rustc-link-lib=log"); println!("cargo:rustc-link-lib=gcc"); - } else if !target.contains("musl") { + } else if !target.contains("musl") || target.contains("mips") { println!("cargo:rustc-link-lib=dl"); println!("cargo:rustc-link-lib=rt"); println!("cargo:rustc-link-lib=pthread"); From dd72b6b91f88b82f1f564ca6dfeec621bd6fa3ec Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Tue, 30 Aug 2016 00:03:29 +0300 Subject: [PATCH 041/443] fix broken type parameter indexing logic in wfcheck Fixes #36075 --- src/librustc/ty/mod.rs | 9 ++++-- src/librustc_typeck/check/wfcheck.rs | 31 ++++++------------- src/librustc_typeck/collect.rs | 24 ++++++-------- .../constrained_type_params.rs | 24 +++++++++----- src/test/run-pass/issue-36075.rs | 22 +++++++++++++ 5 files changed, 65 insertions(+), 45 deletions(-) create mode 100644 src/test/run-pass/issue-36075.rs diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 759dc3003721..4b2af26bb8d9 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -717,11 +717,16 @@ pub struct RegionParameterDef<'tcx> { impl<'tcx> RegionParameterDef<'tcx> { pub fn to_early_bound_region(&self) -> ty::Region { - ty::ReEarlyBound(ty::EarlyBoundRegion { + ty::ReEarlyBound(self.to_early_bound_region_data()) + } + + pub fn to_early_bound_region_data(&self) -> ty::EarlyBoundRegion { + ty::EarlyBoundRegion { index: self.index, name: self.name, - }) + } } + pub fn to_bound_region(&self) -> ty::BoundRegion { // this is an early bound region, so unaffected by #32330 ty::BoundRegion::BrNamed(self.def_id, self.name, Issue32330::WontChange) diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 6b6a688bf1d1..e90b0ad32c9a 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -457,44 +457,31 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { let variances = self.tcx().item_variances(item_def_id); let mut constrained_parameters: FnvHashSet<_> = - variances[ast_generics.lifetimes.len()..] - .iter().enumerate() + variances.iter().enumerate() .filter(|&(_, &variance)| variance != ty::Bivariant) - .map(|(index, _)| self.param_ty(ast_generics, index)) - .map(|p| Parameter::Type(p)) + .map(|(index, _)| Parameter(index as u32)) .collect(); identify_constrained_type_params(ty_predicates.predicates.as_slice(), None, &mut constrained_parameters); - for (index, &variance) in variances.iter().enumerate() { - let (span, name) = if index < ast_generics.lifetimes.len() { - if variance != ty::Bivariant { - continue; - } + for (index, _) in variances.iter().enumerate() { + if constrained_parameters.contains(&Parameter(index as u32)) { + continue; + } + let (span, name) = if index < ast_generics.lifetimes.len() { (ast_generics.lifetimes[index].lifetime.span, ast_generics.lifetimes[index].lifetime.name) } else { - let index = index - ast_generics.lifetimes.len(); - let param_ty = self.param_ty(ast_generics, index); - if constrained_parameters.contains(&Parameter::Type(param_ty)) { - continue; - } - (ast_generics.ty_params[index].span, param_ty.name) + (ast_generics.ty_params[index].span, + ast_generics.ty_params[index].name) }; self.report_bivariance(span, name); } } - fn param_ty(&self, ast_generics: &hir::Generics, index: usize) -> ty::ParamTy { - ty::ParamTy { - idx: index as u32, - name: ast_generics.ty_params[index].name - } - } - fn report_bivariance(&self, span: Span, param_name: ast::Name) diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 30b9d1558706..0097991210d8 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -2158,7 +2158,7 @@ fn enforce_impl_params_are_constrained<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let ty_generics = generics_of_def_id(ccx, impl_def_id); for (ty_param, param) in ty_generics.types.iter().zip(&generics.ty_params) { let param_ty = ty::ParamTy::for_def(ty_param); - if !input_parameters.contains(&ctp::Parameter::Type(param_ty)) { + if !input_parameters.contains(&ctp::Parameter::from(param_ty)) { report_unused_parameter(ccx, param.span, "type", ¶m_ty.to_string()); } } @@ -2189,23 +2189,19 @@ fn enforce_impl_lifetimes_are_constrained<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, ty::ConstTraitItem(..) | ty::MethodTraitItem(..) => None }) .flat_map(|ty| ctp::parameters_for(&ty, true)) - .filter_map(|p| match p { - ctp::Parameter::Type(_) => None, - ctp::Parameter::Region(r) => Some(r), - }) .collect(); - for (index, lifetime_def) in ast_generics.lifetimes.iter().enumerate() { - let region = ty::EarlyBoundRegion { - index: index as u32, - name: lifetime_def.lifetime.name - }; + for (ty_lifetime, lifetime) in impl_scheme.generics.regions.iter() + .zip(&ast_generics.lifetimes) + { + let param = ctp::Parameter::from(ty_lifetime.to_early_bound_region_data()); + if - lifetimes_in_associated_types.contains(®ion) && // (*) - !input_parameters.contains(&ctp::Parameter::Region(region)) + lifetimes_in_associated_types.contains(¶m) && // (*) + !input_parameters.contains(¶m) { - report_unused_parameter(ccx, lifetime_def.lifetime.span, - "lifetime", ®ion.name.to_string()); + report_unused_parameter(ccx, lifetime.lifetime.span, + "lifetime", &lifetime.lifetime.name.to_string()); } } diff --git a/src/librustc_typeck/constrained_type_params.rs b/src/librustc_typeck/constrained_type_params.rs index 9e5c3a5d575b..39f9e4316b9c 100644 --- a/src/librustc_typeck/constrained_type_params.rs +++ b/src/librustc_typeck/constrained_type_params.rs @@ -13,9 +13,14 @@ use rustc::ty::fold::{TypeFoldable, TypeVisitor}; use rustc::util::nodemap::FnvHashSet; #[derive(Clone, PartialEq, Eq, Hash, Debug)] -pub enum Parameter { - Type(ty::ParamTy), - Region(ty::EarlyBoundRegion), +pub struct Parameter(pub u32); + +impl From for Parameter { + fn from(param: ty::ParamTy) -> Self { Parameter(param.idx) } +} + +impl From for Parameter { + fn from(param: ty::EarlyBoundRegion) -> Self { Parameter(param.index) } } /// If `include_projections` is false, returns the list of parameters that are @@ -49,8 +54,8 @@ impl<'tcx> TypeVisitor<'tcx> for ParameterCollector { // projections are not injective return false; } - ty::TyParam(ref d) => { - self.parameters.push(Parameter::Type(d.clone())); + ty::TyParam(data) => { + self.parameters.push(Parameter::from(data)); } _ => {} } @@ -61,7 +66,7 @@ impl<'tcx> TypeVisitor<'tcx> for ParameterCollector { fn visit_region(&mut self, r: &'tcx ty::Region) -> bool { match *r { ty::ReEarlyBound(data) => { - self.parameters.push(Parameter::Region(data)); + self.parameters.push(Parameter::from(data)); } _ => {} } @@ -141,13 +146,15 @@ pub fn setup_constraining_predicates<'tcx>(predicates: &mut [ty::Predicate<'tcx> // * ::Item = T // * T: Debug // * U: Iterator + debug!("setup_constraining_predicates: predicates={:?} \ + impl_trait_ref={:?} input_parameters={:?}", + predicates, impl_trait_ref, input_parameters); let mut i = 0; let mut changed = true; while changed { changed = false; for j in i..predicates.len() { - if let ty::Predicate::Projection(ref poly_projection) = predicates[j] { // Note that we can skip binder here because the impl // trait ref never contains any late-bound regions. @@ -181,5 +188,8 @@ pub fn setup_constraining_predicates<'tcx>(predicates: &mut [ty::Predicate<'tcx> i += 1; changed = true; } + debug!("setup_constraining_predicates: predicates={:?} \ + i={} impl_trait_ref={:?} input_parameters={:?}", + predicates, i, impl_trait_ref, input_parameters); } } diff --git a/src/test/run-pass/issue-36075.rs b/src/test/run-pass/issue-36075.rs new file mode 100644 index 000000000000..fe399e10c1c3 --- /dev/null +++ b/src/test/run-pass/issue-36075.rs @@ -0,0 +1,22 @@ +// 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. + +trait DeclarationParser { + type Declaration; +} + +struct DeclarationListParser<'i, I, P> + where P: DeclarationParser +{ + input: &'i (), + parser: P +} + +fn main() {} From 3401f4ed3daf842138d72b1e53bf29067d82e590 Mon Sep 17 00:00:00 2001 From: ggomez Date: Mon, 29 Aug 2016 15:23:35 +0200 Subject: [PATCH 042/443] Add E0466 error explanation --- src/librustc_metadata/diagnostics.rs | 38 +++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/src/librustc_metadata/diagnostics.rs b/src/librustc_metadata/diagnostics.rs index 099ec62b38de..f0652f23a590 100644 --- a/src/librustc_metadata/diagnostics.rs +++ b/src/librustc_metadata/diagnostics.rs @@ -91,6 +91,43 @@ You need to link your code to the relevant crate in order to be able to use it well, and you link to them the same way. "##, +E0466: r##" +Macro import declarations were malformed. + +Erroneous code examples: + +```compile_fail,E0466 +#[macro_use(a_macro(another_macro))] // error: invalid import declaration +extern crate some_crate; + +#[macro_use(i_want = "some_macros")] // error: invalid import declaration +extern crate another_crate; +``` + +This is a syntax error at the level of attribute declarations. The proper +syntax for macro imports is the following: + +```ignore +// In some_crate: +#[macro_export] +macro_rules! get_tacos { + ... +} + +#[macro_export] +macro_rules! get_pimientos { + ... +} + +// In your crate: +#[macro_use(get_tacos, get_pimientos)] // It imports `get_tacos` and +extern crate some_crate; // `get_pimientos` macros from some_crate. +``` + +If you would like to import all exported macros, write `macro_use` with no +arguments. +"##, + } register_diagnostics! { @@ -102,7 +139,6 @@ register_diagnostics! { E0462, // found staticlib `..` instead of rlib or dylib E0464, // multiple matching crates for `..` E0465, // multiple .. candidates for `..` found - E0466, // bad macro import E0467, // bad macro reexport E0468, // an `extern crate` loading macros must be at the crate root E0469, // imported macro not found From b9eaeb12648e1b26ef86d9efc24f0f456c5d8e2c Mon Sep 17 00:00:00 2001 From: ggomez Date: Mon, 29 Aug 2016 15:25:17 +0200 Subject: [PATCH 043/443] Add E0467 error explanation --- src/librustc_metadata/diagnostics.rs | 30 +++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/src/librustc_metadata/diagnostics.rs b/src/librustc_metadata/diagnostics.rs index f0652f23a590..5127936b2e23 100644 --- a/src/librustc_metadata/diagnostics.rs +++ b/src/librustc_metadata/diagnostics.rs @@ -128,6 +128,35 @@ If you would like to import all exported macros, write `macro_use` with no arguments. "##, +E0467: r##" +Macro reexport declarations were empty or malformed. + +Erroneous code examples: + +```compile_fail,E0467 +#[macro_reexport] // error: no macros listed for export +extern crate macros_for_good; + +#[macro_reexport(fun_macro = "foo")] // error: not a macro identifier +extern crate other_macros_for_good; +``` + +This is a syntax error at the level of attribute declarations. + +Currently, `macro_reexport` requires at least one macro name to be listed. +Unlike `macro_use`, listing no names does not reexport all macros from the +given crate. + +Decide which macros you would like to export and list them properly. + +These are proper reexport declarations: + +```ignore +#[macro_reexport(some_macro, another_macro)] +extern crate macros_for_good; +``` +"##, + } register_diagnostics! { @@ -139,7 +168,6 @@ register_diagnostics! { E0462, // found staticlib `..` instead of rlib or dylib E0464, // multiple matching crates for `..` E0465, // multiple .. candidates for `..` found - E0467, // bad macro reexport E0468, // an `extern crate` loading macros must be at the crate root E0469, // imported macro not found E0470, // reexported macro not found From e32dad3a7e3425b9707d7ae944298fa3a2fb7314 Mon Sep 17 00:00:00 2001 From: ggomez Date: Mon, 29 Aug 2016 15:29:07 +0200 Subject: [PATCH 044/443] Add E0468 error explanation --- src/librustc_metadata/diagnostics.rs | 29 +++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/src/librustc_metadata/diagnostics.rs b/src/librustc_metadata/diagnostics.rs index 5127936b2e23..42f607ccca08 100644 --- a/src/librustc_metadata/diagnostics.rs +++ b/src/librustc_metadata/diagnostics.rs @@ -157,6 +157,34 @@ extern crate macros_for_good; ``` "##, +E0468: r##" +A non-root module attempts to import macros from another crate. + +Example of erroneous code: + +```compile_fail,E0468 +mod foo { + #[macro_use(helpful_macro)] // error: must be at crate root to import + extern crate some_crate; // macros from another crate + helpful_macro!(...) +} +``` + +Only `extern crate` imports at the crate root level are allowed to import +macros. + +Either move the macro import to crate root or do without the foreign macros. +This will work: + +```ignore +#[macro_use(helpful_macro)] +extern crate some_crate; + +mod foo { + helpful_macro!(...) +} +``` +"##, } register_diagnostics! { @@ -168,7 +196,6 @@ register_diagnostics! { E0462, // found staticlib `..` instead of rlib or dylib E0464, // multiple matching crates for `..` E0465, // multiple .. candidates for `..` found - E0468, // an `extern crate` loading macros must be at the crate root E0469, // imported macro not found E0470, // reexported macro not found E0519, // local crate and dependency have same (crate-name, disambiguator) From 980402cd11422bbf41d6c5d2c71c3bffb8fbd8d7 Mon Sep 17 00:00:00 2001 From: ggomez Date: Mon, 29 Aug 2016 15:33:35 +0200 Subject: [PATCH 045/443] Add E0469 error explanation --- src/librustc_metadata/diagnostics.rs | 44 +++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/src/librustc_metadata/diagnostics.rs b/src/librustc_metadata/diagnostics.rs index 42f607ccca08..f3189bbaa075 100644 --- a/src/librustc_metadata/diagnostics.rs +++ b/src/librustc_metadata/diagnostics.rs @@ -185,6 +185,49 @@ mod foo { } ``` "##, + +E0469: r##" +A macro listed for import was not found. + +Erroneous code example: + +```compile_fail,E0469 +#[macro_use(drink, be_merry)] // error: imported macro not found +extern crate collections; + +fn main() { + // ... +} +``` + +Either the listed macro is not contained in the imported crate, or it is not +exported from the given crate. + +This could be caused by a typo. Did you misspell the macro's name? + +Double-check the names of the macros listed for import, and that the crate +in question exports them. + +A working version would be: + +```ignore +// In some_crate: +#[macro_export] +macro_rules! eat { + ... +} + +#[macro_export] +macro_rules! drink { + ... +} + +// In your crate: +#[macro_use(eat, drink)] +extern crate some_crate; //ok! +``` +"##, + } register_diagnostics! { @@ -196,7 +239,6 @@ register_diagnostics! { E0462, // found staticlib `..` instead of rlib or dylib E0464, // multiple matching crates for `..` E0465, // multiple .. candidates for `..` found - E0469, // imported macro not found E0470, // reexported macro not found E0519, // local crate and dependency have same (crate-name, disambiguator) E0523, // two dependencies have same (crate-name, disambiguator) but different SVH From 5629f7e62114e8da941dc08e2deae4afd92129dc Mon Sep 17 00:00:00 2001 From: ggomez Date: Mon, 29 Aug 2016 15:39:04 +0200 Subject: [PATCH 046/443] Add E0470 error explanation --- src/librustc_metadata/diagnostics.rs | 45 ++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/src/librustc_metadata/diagnostics.rs b/src/librustc_metadata/diagnostics.rs index f3189bbaa075..321893074668 100644 --- a/src/librustc_metadata/diagnostics.rs +++ b/src/librustc_metadata/diagnostics.rs @@ -211,7 +211,7 @@ in question exports them. A working version would be: ```ignore -// In some_crate: +// In some_crate crate: #[macro_export] macro_rules! eat { ... @@ -228,6 +228,48 @@ extern crate some_crate; //ok! ``` "##, +E0470: r##" +A macro listed for reexport was not found. + +Erroneous code example: + +```compile_fail,E0470 +#[macro_reexport(drink, be_merry)] +extern crate collections; + +fn main() { + // ... +} +``` + +Either the listed macro is not contained in the imported crate, or it is not +exported from the given crate. + +This could be caused by a typo. Did you misspell the macro's name? + +Double-check the names of the macros listed for reexport, and that the crate +in question exports them. + +A working version: + +```ignore +// In some_crate crate: +#[macro_export] +macro_rules! eat { + ... +} + +#[macro_export] +macro_rules! drink { + ... +} + +// In your_crate: +#[macro_reexport(eat, drink)] +extern crate some_crate; +``` +"##, + } register_diagnostics! { @@ -239,7 +281,6 @@ register_diagnostics! { E0462, // found staticlib `..` instead of rlib or dylib E0464, // multiple matching crates for `..` E0465, // multiple .. candidates for `..` found - E0470, // reexported macro not found E0519, // local crate and dependency have same (crate-name, disambiguator) E0523, // two dependencies have same (crate-name, disambiguator) but different SVH } From 25145b2ef18b872bf46b939126d607b9107e9966 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 30 Aug 2016 16:30:57 -0500 Subject: [PATCH 047/443] copy_third_party_objects -> copy_musl_third_party_objects --- src/bootstrap/compile.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 6b3b5cf8cda7..5a73f2e21bc0 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -93,14 +93,14 @@ pub fn std_link(build: &Build, add_to_sysroot(&out_dir, &libdir); if target.contains("musl") && !target.contains("mips") { - copy_third_party_objects(build, &libdir); + copy_musl_third_party_objects(build, &libdir); } } /// Copies the crt(1,i,n).o startup objects /// /// Only required for musl targets that statically link to libc -fn copy_third_party_objects(build: &Build, into: &Path) { +fn copy_musl_third_party_objects(build: &Build, into: &Path) { for &obj in &["crt1.o", "crti.o", "crtn.o"] { copy(&build.config.musl_root.as_ref().unwrap().join("lib").join(obj), &into.join(obj)); } From e0279d71926d0fd7925f55f600bc9947dd070e68 Mon Sep 17 00:00:00 2001 From: James Miller Date: Wed, 31 Aug 2016 16:40:43 +1200 Subject: [PATCH 048/443] Normalize the function signature of closures Previously we didn't normalize the function signatures used for closures. This didn't cause a problem in most cases, but caused an ICE in during MIR type checking. Fixes #36139 --- src/librustc_typeck/astconv.rs | 7 ++++- src/librustc_typeck/check/closure.rs | 2 ++ .../issue-36139-normalize-closure-sig.rs | 28 +++++++++++++++++++ 3 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 src/test/run-pass/issue-36139-normalize-closure-sig.rs diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index f24a7cf2121e..844b39c6d16f 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1877,11 +1877,16 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { hir::DefaultReturn(..) => self.tcx().mk_nil(), }; + let input_tys = self_ty.into_iter().chain(arg_tys).collect(); + + debug!("ty_of_method_or_bare_fn: input_tys={:?}", input_tys); + debug!("ty_of_method_or_bare_fn: output_ty={:?}", output_ty); + (self.tcx().mk_bare_fn(ty::BareFnTy { unsafety: unsafety, abi: abi, sig: ty::Binder(ty::FnSig { - inputs: self_ty.into_iter().chain(arg_tys).collect(), + inputs: input_tys, output: output_ty, variadic: decl.variadic }), diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index 46e8c27f6d33..aa61974e0390 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -74,6 +74,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let fn_sig = self.tcx.liberate_late_bound_regions( self.tcx.region_maps.call_site_extent(expr.id, body.id), &fn_ty.sig); + let fn_sig = + (**self).normalize_associated_types_in(body.span, body.id, &fn_sig); check_fn(self, hir::Unsafety::Normal, expr.id, &fn_sig, decl, expr.id, &body); diff --git a/src/test/run-pass/issue-36139-normalize-closure-sig.rs b/src/test/run-pass/issue-36139-normalize-closure-sig.rs new file mode 100644 index 000000000000..adde0ed30667 --- /dev/null +++ b/src/test/run-pass/issue-36139-normalize-closure-sig.rs @@ -0,0 +1,28 @@ +// 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. + +// Previously the closure's argument would be inferred to +// >::Item, causing an error in MIR type +// checking + +trait ITrait<'a> {type Item;} + +struct S {} + +impl<'a> ITrait<'a> for S { type Item = &'a mut usize; } + +fn m(_: F) + where I: for<'a> ITrait<'a>, + F: for<'a> FnMut(>::Item) { } + + +fn main() { + m::(|x| { *x += 1; }); +} From ad447a12b5b057802a434eb02373a966328cb3f9 Mon Sep 17 00:00:00 2001 From: CensoredUsername Date: Wed, 31 Aug 2016 15:52:10 +0200 Subject: [PATCH 049/443] Add a tracking issue to the feature gate of the sysv64 ABI --- src/libsyntax/feature_gate.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 18924a3dc253..e224e30b1a2a 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -285,7 +285,7 @@ declare_features! ( // Allows the sysV64 ABI to be specified on all platforms // instead of just the platforms on which it is the C ABI - (active, abi_sysv64, "1.13.0", None) + (active, abi_sysv64, "1.13.0", Some(36167)) ); declare_features! ( From 638b7c89e6c3de5c21cf10ea28b8b8ea259b5f27 Mon Sep 17 00:00:00 2001 From: Federico Ravasio Date: Sun, 28 Aug 2016 12:51:00 +0200 Subject: [PATCH 050/443] Updated E0493 to new format. --- src/librustc_mir/transform/qualify_consts.rs | 4 ++++ src/test/compile-fail/E0493.rs | 4 +++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 9e076851bc37..a6f6faf24696 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -252,11 +252,15 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> { let mut err = struct_span_err!(self.tcx.sess, self.span, E0493, "{}", msg); + if self.mode != Mode::Const { help!(&mut err, "in Nightly builds, add `#![feature(drop_types_in_const)]` \ to the crate attributes to enable"); + } else { + err.span_label(self.span, &format!("constants cannot have destructors")); } + err.emit(); } diff --git a/src/test/compile-fail/E0493.rs b/src/test/compile-fail/E0493.rs index 689f469533d9..d5b29a628f0b 100644 --- a/src/test/compile-fail/E0493.rs +++ b/src/test/compile-fail/E0493.rs @@ -16,7 +16,9 @@ impl Drop for Foo { fn drop(&mut self) {} } -const F : Foo = Foo { a : 0 }; //~ ERROR E0493 +const F : Foo = Foo { a : 0 }; +//~^ ERROR constants are not allowed to have destructors [E0493] +//~| NOTE constants cannot have destructors fn main() { } From 52c2d87aa989eb83bfe61884e3c5f24cb5e923d5 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 5 Aug 2016 17:18:25 -0400 Subject: [PATCH 051/443] remove unused normalize field --- src/librustc/infer/mod.rs | 25 +------------------------ 1 file changed, 1 insertion(+), 24 deletions(-) diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 9854cd95397b..37c2a8f0d2cf 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -136,13 +136,6 @@ pub struct InferCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { // avoid reporting the same error twice. pub reported_trait_errors: RefCell>>, - // This is a temporary field used for toggling on normalization in the inference context, - // as we move towards the approach described here: - // https://internals.rust-lang.org/t/flattening-the-contexts-for-fun-and-profit/2293 - // At a point sometime in the future normalization will be done by the typing context - // directly. - normalize: bool, - // Sadly, the behavior of projection varies a bit depending on the // stage of compilation. The specifics are given in the // documentation for `Reveal`. @@ -458,7 +451,6 @@ pub struct InferCtxtBuilder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { tables: Option>>, param_env: Option>, projection_mode: Reveal, - normalize: bool } impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'gcx> { @@ -473,7 +465,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'gcx> { tables: tables.map(RefCell::new), param_env: param_env, projection_mode: projection_mode, - normalize: false } } @@ -485,7 +476,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'gcx> { tables: None, param_env: None, projection_mode: projection_mode, - normalize: false } } @@ -506,7 +496,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'gcx> { evaluation_cache: traits::EvaluationCache::new(), projection_cache: RefCell::new(traits::ProjectionCache::new()), reported_trait_errors: RefCell::new(FnvHashSet()), - normalize: false, projection_mode: Reveal::NotSpecializable, tainted_by_errors_flag: Cell::new(false), err_count_on_creation: self.sess.err_count(), @@ -525,7 +514,6 @@ impl<'a, 'gcx, 'tcx> InferCtxtBuilder<'a, 'gcx, 'tcx> { ref tables, ref mut param_env, projection_mode, - normalize } = *self; let tables = if let Some(ref tables) = *tables { InferTables::Local(tables) @@ -547,7 +535,6 @@ impl<'a, 'gcx, 'tcx> InferCtxtBuilder<'a, 'gcx, 'tcx> { selection_cache: traits::SelectionCache::new(), evaluation_cache: traits::EvaluationCache::new(), reported_trait_errors: RefCell::new(FnvHashSet()), - normalize: normalize, projection_mode: projection_mode, tainted_by_errors_flag: Cell::new(false), err_count_on_creation: tcx.sess.err_count(), @@ -1702,17 +1689,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } let closure_ty = self.tcx.closure_type(def_id, substs); - if self.normalize { - let closure_ty = self.tcx.erase_regions(&closure_ty); - - if !closure_ty.has_projection_types() { - return closure_ty; - } - - self.normalize_projections_in(&closure_ty) - } else { - closure_ty - } + closure_ty } } From b44d94a5162ee4b2e20f4ae82328f3e7f6a152b8 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sun, 7 Aug 2016 06:41:17 -0400 Subject: [PATCH 052/443] remove unneccessary uses of `drain_fulfillment_cx` There were various places that we are invoking `drain_fulfillment_cx` with a "result" of `()`. This is kind of pointless, since it amounts to just a call to `select_all_or_error` along with some extra overhead. --- src/librustc/traits/specialize/mod.rs | 35 +++++++++++++++------------ src/librustc_trans/common.rs | 2 +- 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs index 9acfe2754820..0604136ec601 100644 --- a/src/librustc/traits/specialize/mod.rs +++ b/src/librustc/traits/specialize/mod.rs @@ -207,24 +207,27 @@ fn fulfill_implication<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, for oblig in obligations.into_iter() { fulfill_cx.register_predicate_obligation(&infcx, oblig); } + match fulfill_cx.select_all_or_error(infcx) { + Err(errors) => { + // no dice! + debug!("fulfill_implication: for impls on {:?} and {:?}, could not fulfill: {:?} given \ + {:?}", + source_trait_ref, + target_trait_ref, + errors, + infcx.parameter_environment.caller_bounds); + Err(()) + } - if let Err(errors) = infcx.drain_fulfillment_cx(&mut fulfill_cx, &()) { - // no dice! - debug!("fulfill_implication: for impls on {:?} and {:?}, could not fulfill: {:?} given \ - {:?}", - source_trait_ref, - target_trait_ref, - errors, - infcx.parameter_environment.caller_bounds); - Err(()) - } else { - debug!("fulfill_implication: an impl for {:?} specializes {:?}", - source_trait_ref, - target_trait_ref); + Ok(()) => { + debug!("fulfill_implication: an impl for {:?} specializes {:?}", + source_trait_ref, + target_trait_ref); - // Now resolve the *substitution* we built for the target earlier, replacing - // the inference variables inside with whatever we got from fulfillment. - Ok(infcx.resolve_type_vars_if_possible(&target_substs)) + // Now resolve the *substitution* we built for the target earlier, replacing + // the inference variables inside with whatever we got from fulfillment. + Ok(infcx.resolve_type_vars_if_possible(&target_substs)) + } } } diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index d5dcae5f6b0a..95a38cd21d93 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -1028,7 +1028,7 @@ pub fn normalize_and_test_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fulfill_cx.register_predicate_obligation(&infcx, obligation); } - infcx.drain_fulfillment_cx(&mut fulfill_cx, &()).is_ok() + fulfill_cx.select_all_or_error(infcx).is_ok() }) } From 4eb7362c2c8e614b25aa7daa286805ce1382c6af Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 8 Aug 2016 09:40:12 -0400 Subject: [PATCH 053/443] simplify DepNode for trait selection --- src/librustc/dep_graph/dep_node.rs | 7 ++-- src/librustc/infer/mod.rs | 58 +++++++++++++----------------- src/librustc/ty/mod.rs | 3 +- src/librustc_trans/common.rs | 2 +- src/librustc_trans/monomorphize.rs | 4 +++ 5 files changed, 34 insertions(+), 40 deletions(-) diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index e95fbcc89175..18179027c25d 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -132,7 +132,7 @@ pub enum DepNode { // which would yield an overly conservative dep-graph. TraitItems(D), ReprHints(D), - TraitSelect(D, Vec), + TraitSelect(Vec), } impl DepNode { @@ -237,10 +237,9 @@ impl DepNode { TraitImpls(ref d) => op(d).map(TraitImpls), TraitItems(ref d) => op(d).map(TraitItems), ReprHints(ref d) => op(d).map(ReprHints), - TraitSelect(ref d, ref type_ds) => { - let d = try_opt!(op(d)); + TraitSelect(ref type_ds) => { let type_ds = try_opt!(type_ds.iter().map(|d| op(d)).collect()); - Some(TraitSelect(d, type_ds)) + Some(TraitSelect(type_ds)) } } } diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 37c2a8f0d2cf..836e52ea45a5 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -670,6 +670,15 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.drain_fulfillment_cx_or_panic(DUMMY_SP, &mut fulfill_cx, &result) } + /// Finishes processes any obligations that remain in the + /// fulfillment context, and then returns the result with all type + /// variables removed and regions erased. Because this is intended + /// for use after type-check has completed, if any errors occur, + /// it will panic. It is used during normalization and other cases + /// where processing the obligations in `fulfill_cx` may cause + /// type inference variables that appear in `result` to be + /// unified, and hence we need to process those obligations to get + /// the complete picture of the type. pub fn drain_fulfillment_cx_or_panic(&self, span: Span, fulfill_cx: &mut traits::FulfillmentContext<'tcx>, @@ -679,45 +688,26 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { { debug!("drain_fulfillment_cx_or_panic()"); - let when = "resolving bounds after type-checking"; - let v = match self.drain_fulfillment_cx(fulfill_cx, result) { - Ok(v) => v, - Err(errors) => { - span_bug!(span, "Encountered errors `{:?}` {}", errors, when); - } - }; - - match self.tcx.lift_to_global(&v) { - Some(v) => v, - None => { - span_bug!(span, "Uninferred types/regions in `{:?}` {}", v, when); - } - } - } - - /// Finishes processes any obligations that remain in the fulfillment - /// context, and then "freshens" and returns `result`. This is - /// primarily used during normalization and other cases where - /// processing the obligations in `fulfill_cx` may cause type - /// inference variables that appear in `result` to be unified, and - /// hence we need to process those obligations to get the complete - /// picture of the type. - pub fn drain_fulfillment_cx(&self, - fulfill_cx: &mut traits::FulfillmentContext<'tcx>, - result: &T) - -> Result>> - where T : TypeFoldable<'tcx> - { - debug!("drain_fulfillment_cx(result={:?})", - result); - // In principle, we only need to do this so long as `result` // contains unbound type parameters. It could be a slight // optimization to stop iterating early. - fulfill_cx.select_all_or_error(self)?; + match fulfill_cx.select_all_or_error(self) { + Ok(()) => { } + Err(errors) => { + span_bug!(span, "Encountered errors `{:?}` resolving bounds after type-checking", + errors); + } + } let result = self.resolve_type_vars_if_possible(result); - Ok(self.tcx.erase_regions(&result)) + let result = self.tcx.erase_regions(&result); + + match self.tcx.lift_to_global(&result) { + Some(result) => result, + None => { + span_bug!(span, "Uninferred types/regions in `{:?}`", result); + } + } } pub fn projection_mode(&self) -> Reveal { diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 1ea82a9c639d..a00ea8de7e71 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -958,8 +958,9 @@ impl<'tcx> TraitPredicate<'tcx> { _ => None }) + .chain(iter::once(self.def_id())) .collect(); - DepNode::TraitSelect(self.def_id(), def_ids) + DepNode::TraitSelect(def_ids) } pub fn input_types<'a>(&'a self) -> impl DoubleEndedIterator> + 'a { diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index 95a38cd21d93..9758fc074464 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -1028,7 +1028,7 @@ pub fn normalize_and_test_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fulfill_cx.register_predicate_obligation(&infcx, obligation); } - fulfill_cx.select_all_or_error(infcx).is_ok() + fulfill_cx.select_all_or_error(&infcx).is_ok() }) } diff --git a/src/librustc_trans/monomorphize.rs b/src/librustc_trans/monomorphize.rs index 0ffb83067f91..4dd5797a3182 100644 --- a/src/librustc_trans/monomorphize.rs +++ b/src/librustc_trans/monomorphize.rs @@ -48,7 +48,11 @@ pub fn apply_param_substs<'a, 'tcx, T>(tcx: TyCtxt<'a, 'tcx, 'tcx>, -> T where T: TransNormalize<'tcx> { + debug!("apply_param_substs(param_substs={:?}, value={:?})", param_substs, value); let substituted = value.subst(tcx, param_substs); + debug!("apply_param_substs: substituted={:?}{}", + substituted, + if substituted.has_projection_types() { " [needs projection]" } else { "" }); tcx.normalize_associated_type(&substituted) } From 72694d582931348f6ac18620c8b4ce5c9c9c7a3e Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 8 Aug 2016 20:50:19 -0400 Subject: [PATCH 054/443] give `apply_param_substs` a `SharedCrateContext` I plan to put a cache on the shared context, for now at least. --- src/librustc_trans/base.rs | 6 ++--- src/librustc_trans/callee.rs | 20 +++++++-------- src/librustc_trans/collector.rs | 40 +++++++++++++++-------------- src/librustc_trans/common.rs | 4 +-- src/librustc_trans/debuginfo/mod.rs | 2 +- src/librustc_trans/mir/constant.rs | 2 +- src/librustc_trans/monomorphize.rs | 4 ++- src/librustc_trans/partitioning.rs | 17 +++++++----- src/librustc_trans/trans_item.rs | 2 +- 9 files changed, 53 insertions(+), 44 deletions(-) diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index fa10adf6c118..99126095ede3 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -1128,7 +1128,7 @@ pub fn trans_instance<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, instance: Instance let fn_ty = ccx.tcx().lookup_item_type(instance.def).ty; let fn_ty = ccx.tcx().erase_regions(&fn_ty); - let fn_ty = monomorphize::apply_param_substs(ccx.tcx(), instance.substs, &fn_ty); + let fn_ty = monomorphize::apply_param_substs(ccx.shared(), instance.substs, &fn_ty); let sig = ccx.tcx().erase_late_bound_regions(fn_ty.fn_sig()); let sig = ccx.tcx().normalize_associated_type(&sig); @@ -1151,7 +1151,7 @@ pub fn trans_ctor_shim<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, attributes::set_frame_pointer_elimination(ccx, llfndecl); let ctor_ty = ccx.tcx().lookup_item_type(def_id).ty; - let ctor_ty = monomorphize::apply_param_substs(ccx.tcx(), substs, &ctor_ty); + let ctor_ty = monomorphize::apply_param_substs(ccx.shared(), substs, &ctor_ty); let sig = ccx.tcx().erase_late_bound_regions(&ctor_ty.fn_sig()); let sig = ccx.tcx().normalize_associated_type(&sig); @@ -1894,7 +1894,7 @@ fn collect_and_partition_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a }; let codegen_units = time(time_passes, "codegen unit partitioning", || { - partitioning::partition(scx.tcx(), + partitioning::partition(scx, items.iter().cloned(), strategy, &inlining_map, diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs index a30f8f291a67..33cacbe194bb 100644 --- a/src/librustc_trans/callee.rs +++ b/src/librustc_trans/callee.rs @@ -28,7 +28,7 @@ use base; use base::*; use build::*; use closure; -use common::{self, Block, Result, CrateContext, FunctionContext}; +use common::{self, Block, Result, CrateContext, FunctionContext, SharedCrateContext}; use consts; use debuginfo::DebugLoc; use declare; @@ -37,7 +37,7 @@ use monomorphize::{self, Instance}; use trans_item::TransItem; use type_of; use Disr; -use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; +use rustc::ty::{self, Ty, TypeFoldable}; use rustc::hir; use syntax_pos::DUMMY_SP; @@ -97,7 +97,7 @@ impl<'tcx> Callee<'tcx> { return Callee::trait_method(ccx, trait_id, def_id, substs); } - let fn_ty = def_ty(tcx, def_id, substs); + let fn_ty = def_ty(ccx.shared(), def_id, substs); if let ty::TyFnDef(_, _, f) = fn_ty.sty { if f.abi == Abi::RustIntrinsic || f.abi == Abi::PlatformIntrinsic { return Callee { @@ -155,20 +155,20 @@ impl<'tcx> Callee<'tcx> { vtable_closure.substs, trait_closure_kind); - let method_ty = def_ty(tcx, def_id, substs); + let method_ty = def_ty(ccx.shared(), def_id, substs); Callee::ptr(llfn, method_ty) } traits::VtableFnPointer(vtable_fn_pointer) => { let trait_closure_kind = tcx.lang_items.fn_trait_kind(trait_id).unwrap(); let llfn = trans_fn_pointer_shim(ccx, trait_closure_kind, vtable_fn_pointer.fn_ty); - let method_ty = def_ty(tcx, def_id, substs); + let method_ty = def_ty(ccx.shared(), def_id, substs); Callee::ptr(llfn, method_ty) } traits::VtableObject(ref data) => { Callee { data: Virtual(tcx.get_vtable_index_of_object_method(data, def_id)), - ty: def_ty(tcx, def_id, substs) + ty: def_ty(ccx.shared(), def_id, substs) } } vtable => { @@ -244,12 +244,12 @@ impl<'tcx> Callee<'tcx> { } /// Given a DefId and some Substs, produces the monomorphic item type. -fn def_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, +fn def_ty<'a, 'tcx>(shared: &SharedCrateContext<'a, 'tcx>, def_id: DefId, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> { - let ty = tcx.lookup_item_type(def_id).ty; - monomorphize::apply_param_substs(tcx, substs, &ty) + let ty = shared.tcx().lookup_item_type(def_id).ty; + monomorphize::apply_param_substs(shared, substs, &ty) } /// Translates an adapter that implements the `Fn` trait for a fn @@ -407,7 +407,7 @@ fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let substs = tcx.normalize_associated_type(&substs); let instance = Instance::new(def_id, substs); let item_ty = ccx.tcx().lookup_item_type(def_id).ty; - let fn_ty = monomorphize::apply_param_substs(ccx.tcx(), substs, &item_ty); + let fn_ty = monomorphize::apply_param_substs(ccx.shared(), substs, &item_ty); if let Some(&llfn) = ccx.instances().borrow().get(&instance) { return (llfn, fn_ty); diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index ba979813aa1f..c82bfa5c91ba 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -459,7 +459,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { format!("Could not find MIR for closure: {:?}", def_id) }); - let concrete_substs = monomorphize::apply_param_substs(self.scx.tcx(), + let concrete_substs = monomorphize::apply_param_substs(self.scx, self.param_substs, &substs.func_substs); let concrete_substs = self.scx.tcx().erase_regions(&concrete_substs); @@ -477,11 +477,11 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { // have to instantiate all methods of the trait being cast to, so we // can build the appropriate vtable. mir::Rvalue::Cast(mir::CastKind::Unsize, ref operand, target_ty) => { - let target_ty = monomorphize::apply_param_substs(self.scx.tcx(), + let target_ty = monomorphize::apply_param_substs(self.scx, self.param_substs, &target_ty); let source_ty = operand.ty(self.mir, self.scx.tcx()); - let source_ty = monomorphize::apply_param_substs(self.scx.tcx(), + let source_ty = monomorphize::apply_param_substs(self.scx, self.param_substs, &source_ty); let (source_ty, target_ty) = find_vtable_types_for_unsizing(self.scx, @@ -508,7 +508,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { assert!(can_have_local_instance(self.scx.tcx(), exchange_malloc_fn_def_id)); let empty_substs = self.scx.empty_substs_for_def_id(exchange_malloc_fn_def_id); let exchange_malloc_fn_trans_item = - create_fn_trans_item(self.scx.tcx(), + create_fn_trans_item(self.scx, exchange_malloc_fn_def_id, empty_substs, self.param_substs); @@ -531,7 +531,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { let ty = lvalue.ty(self.mir, self.scx.tcx()) .to_ty(self.scx.tcx()); - let ty = monomorphize::apply_param_substs(self.scx.tcx(), + let ty = monomorphize::apply_param_substs(self.scx, self.param_substs, &ty); assert!(ty.is_normalized_for_trans()); @@ -555,7 +555,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { // references to `const` items if let mir::Literal::Item { def_id, substs } = constant.literal { let tcx = self.scx.tcx(); - let substs = monomorphize::apply_param_substs(tcx, + let substs = monomorphize::apply_param_substs(self.scx, self.param_substs, &substs); @@ -613,7 +613,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { // result in a translation item ... if can_result_in_trans_item(self.scx.tcx(), callee_def_id) { // ... and create one if it does. - let trans_item = create_fn_trans_item(self.scx.tcx(), + let trans_item = create_fn_trans_item(self.scx, callee_def_id, callee_substs, self.param_substs); @@ -670,7 +670,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { if is_drop_in_place_intrinsic(tcx, def_id, bare_fn_ty) => { let operand_ty = args[0].ty(self.mir, tcx); if let ty::TyRawPtr(mt) = operand_ty.sty { - let operand_ty = monomorphize::apply_param_substs(tcx, + let operand_ty = monomorphize::apply_param_substs(self.scx, self.param_substs, &mt.ty); let ty = glue::get_drop_glue_type(tcx, operand_ty); @@ -732,7 +732,7 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, assert!(can_have_local_instance(scx.tcx(), exchange_free_fn_def_id)); let fn_substs = scx.empty_substs_for_def_id(exchange_free_fn_def_id); let exchange_free_fn_trans_item = - create_fn_trans_item(scx.tcx(), + create_fn_trans_item(scx, exchange_free_fn_def_id, fn_substs, Substs::empty(scx.tcx())); @@ -769,7 +769,7 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, }; if can_have_local_instance(scx.tcx(), destructor_did) { - let trans_item = create_fn_trans_item(scx.tcx(), + let trans_item = create_fn_trans_item(scx, destructor_did, substs, Substs::empty(scx.tcx())); @@ -800,7 +800,7 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, ty::TyStruct(ref adt_def, substs) | ty::TyEnum(ref adt_def, substs) => { for field in adt_def.all_fields() { - let field_type = monomorphize::apply_param_substs(scx.tcx(), + let field_type = monomorphize::apply_param_substs(scx, substs, &field.unsubst_ty()); let field_type = glue::get_drop_glue_type(scx.tcx(), field_type); @@ -894,8 +894,7 @@ fn do_static_trait_method_dispatch<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, callee_substs, param_substs); - - let rcvr_substs = monomorphize::apply_param_substs(tcx, + let rcvr_substs = monomorphize::apply_param_substs(scx, param_substs, &callee_substs); let trait_ref = ty::TraitRef::from_method(tcx, trait_id, rcvr_substs); @@ -1016,11 +1015,13 @@ fn find_vtable_types_for_unsizing<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, } } -fn create_fn_trans_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, +fn create_fn_trans_item<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, def_id: DefId, fn_substs: &'tcx Substs<'tcx>, param_substs: &'tcx Substs<'tcx>) -> TransItem<'tcx> { + let tcx = scx.tcx(); + debug!("create_fn_trans_item(def_id={}, fn_substs={:?}, param_substs={:?})", def_id_to_string(tcx, def_id), fn_substs, @@ -1029,7 +1030,7 @@ fn create_fn_trans_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // We only get here, if fn_def_id either designates a local item or // an inlineable external item. Non-inlineable external items are // ignored because we don't want to generate any code for them. - let concrete_substs = monomorphize::apply_param_substs(tcx, + let concrete_substs = monomorphize::apply_param_substs(scx, param_substs, &fn_substs); assert!(concrete_substs.is_normalized_for_trans()); @@ -1063,7 +1064,7 @@ fn create_trans_items_for_vtable_methods<'a, 'tcx>(scx: &SharedCrateContext<'a, // create translation items .filter_map(|impl_method| { if can_have_local_instance(scx.tcx(), impl_method.method.def_id) { - Some(create_fn_trans_item(scx.tcx(), + Some(create_fn_trans_item(scx, impl_method.method.def_id, impl_method.substs, Substs::empty(scx.tcx()))) @@ -1114,7 +1115,7 @@ impl<'b, 'a, 'v> hir_visit::Visitor<'v> for RootCollector<'b, 'a, 'v> { hir::ItemImpl(..) => { if self.mode == TransItemCollectionMode::Eager { - create_trans_items_for_default_impls(self.scx.tcx(), + create_trans_items_for_default_impls(self.scx, item, self.output); } @@ -1202,9 +1203,10 @@ impl<'b, 'a, 'v> hir_visit::Visitor<'v> for RootCollector<'b, 'a, 'v> { } } -fn create_trans_items_for_default_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, +fn create_trans_items_for_default_impls<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, item: &'tcx hir::Item, output: &mut Vec>) { + let tcx = scx.tcx(); match item.node { hir::ItemImpl(_, _, @@ -1255,7 +1257,7 @@ fn create_trans_items_for_default_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, if can_have_local_instance(tcx, method.def_id) { let empty_substs = tcx.erase_regions(&mth.substs); - let item = create_fn_trans_item(tcx, + let item = create_fn_trans_item(scx, method.def_id, callee_substs, empty_substs); diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index 9758fc074464..c51b32331112 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -350,7 +350,7 @@ impl<'a, 'tcx> FunctionContext<'a, 'tcx> { pub fn monomorphize(&self, value: &T) -> T where T: TransNormalize<'tcx> { - monomorphize::apply_param_substs(self.ccx.tcx(), + monomorphize::apply_param_substs(self.ccx.shared(), self.param_substs, value) } @@ -519,7 +519,7 @@ impl<'blk, 'tcx> BlockS<'blk, 'tcx> { pub fn monomorphize(&self, value: &T) -> T where T: TransNormalize<'tcx> { - monomorphize::apply_param_substs(self.tcx(), + monomorphize::apply_param_substs(self.fcx.ccx.shared(), self.fcx.param_substs, value) } diff --git a/src/librustc_trans/debuginfo/mod.rs b/src/librustc_trans/debuginfo/mod.rs index 5e248261e118..a3a7a79fb58b 100644 --- a/src/librustc_trans/debuginfo/mod.rs +++ b/src/librustc_trans/debuginfo/mod.rs @@ -414,7 +414,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, if cx.tcx().trait_id_of_impl(impl_def_id).is_none() { let impl_self_ty = cx.tcx().lookup_item_type(impl_def_id).ty; let impl_self_ty = cx.tcx().erase_regions(&impl_self_ty); - let impl_self_ty = monomorphize::apply_param_substs(cx.tcx(), + let impl_self_ty = monomorphize::apply_param_substs(cx.shared(), instance.substs, &impl_self_ty); diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index 1badfdba6603..ade266a580e7 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -258,7 +258,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { fn monomorphize(&self, value: &T) -> T where T: TransNormalize<'tcx> { - monomorphize::apply_param_substs(self.ccx.tcx(), + monomorphize::apply_param_substs(self.ccx.shared(), self.substs, value) } diff --git a/src/librustc_trans/monomorphize.rs b/src/librustc_trans/monomorphize.rs index 4dd5797a3182..66b227fe5c54 100644 --- a/src/librustc_trans/monomorphize.rs +++ b/src/librustc_trans/monomorphize.rs @@ -42,12 +42,13 @@ impl<'tcx> Instance<'tcx> { /// Monomorphizes a type from the AST by first applying the in-scope /// substitutions and then normalizing any associated types. -pub fn apply_param_substs<'a, 'tcx, T>(tcx: TyCtxt<'a, 'tcx, 'tcx>, +pub fn apply_param_substs<'a, 'tcx, T>(scx: &SharedCrateContext<'a, 'tcx>, param_substs: &Substs<'tcx>, value: &T) -> T where T: TransNormalize<'tcx> { + let tcx = scx.tcx(); debug!("apply_param_substs(param_substs={:?}, value={:?})", param_substs, value); let substituted = value.subst(tcx, param_substs); debug!("apply_param_substs: substituted={:?}{}", @@ -65,3 +66,4 @@ pub fn field_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, { tcx.normalize_associated_type(&f.ty(tcx, param_substs)) } + diff --git a/src/librustc_trans/partitioning.rs b/src/librustc_trans/partitioning.rs index 7341e8db41de..a161bd199b1f 100644 --- a/src/librustc_trans/partitioning.rs +++ b/src/librustc_trans/partitioning.rs @@ -117,6 +117,7 @@ //! inlining, even when they are not marked #[inline]. use collector::InliningMap; +use context::SharedCrateContext; use llvm; use monomorphize; use rustc::dep_graph::{DepNode, WorkProductId}; @@ -250,7 +251,7 @@ impl<'tcx> CodegenUnit<'tcx> { // Anything we can't find a proper codegen unit for goes into this. const FALLBACK_CODEGEN_UNIT: &'static str = "__rustc_fallback_codegen_unit"; -pub fn partition<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, +pub fn partition<'a, 'tcx, I>(scx: &SharedCrateContext<'a, 'tcx>, trans_items: I, strategy: PartitioningStrategy, inlining_map: &InliningMap<'tcx>, @@ -258,6 +259,8 @@ pub fn partition<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, -> Vec> where I: Iterator> { + let tcx = scx.tcx(); + if let PartitioningStrategy::FixedUnitCount(1) = strategy { // If there is only a single codegen-unit, we can use a very simple // scheme and don't have to bother with doing much analysis. @@ -267,7 +270,7 @@ pub fn partition<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // In the first step, we place all regular translation items into their // respective 'home' codegen unit. Regular translation items are all // functions and statics defined in the local crate. - let mut initial_partitioning = place_root_translation_items(tcx, + let mut initial_partitioning = place_root_translation_items(scx, trans_items, reachable); @@ -306,12 +309,13 @@ struct PreInliningPartitioning<'tcx> { struct PostInliningPartitioning<'tcx>(Vec>); -fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, +fn place_root_translation_items<'a, 'tcx, I>(scx: &SharedCrateContext<'a, 'tcx>, trans_items: I, _reachable: &NodeSet) -> PreInliningPartitioning<'tcx> where I: Iterator> { + let tcx = scx.tcx(); let mut roots = FnvHashSet(); let mut codegen_units = FnvHashMap(); @@ -319,7 +323,7 @@ fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let is_root = !trans_item.is_instantiated_only_on_demand(); if is_root { - let characteristic_def_id = characteristic_def_id_of_trans_item(tcx, trans_item); + let characteristic_def_id = characteristic_def_id_of_trans_item(scx, trans_item); let is_volatile = trans_item.is_generic_fn(); let codegen_unit_name = match characteristic_def_id { @@ -477,9 +481,10 @@ fn place_inlined_translation_items<'tcx>(initial_partitioning: PreInliningPartit } } -fn characteristic_def_id_of_trans_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, +fn characteristic_def_id_of_trans_item<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, trans_item: TransItem<'tcx>) -> Option { + let tcx = scx.tcx(); match trans_item { TransItem::Fn(instance) => { // If this is a method, we want to put it into the same module as @@ -497,7 +502,7 @@ fn characteristic_def_id_of_trans_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // self-type is: let impl_self_ty = tcx.lookup_item_type(impl_def_id).ty; let impl_self_ty = tcx.erase_regions(&impl_self_ty); - let impl_self_ty = monomorphize::apply_param_substs(tcx, + let impl_self_ty = monomorphize::apply_param_substs(scx, instance.substs, &impl_self_ty); diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs index 2c91c408487b..8a0f37230c8d 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -176,7 +176,7 @@ impl<'a, 'tcx> TransItem<'tcx> { let item_ty = ccx.tcx().lookup_item_type(instance.def).ty; let item_ty = ccx.tcx().erase_regions(&item_ty); - let mono_ty = monomorphize::apply_param_substs(ccx.tcx(), instance.substs, &item_ty); + let mono_ty = monomorphize::apply_param_substs(ccx.shared(), instance.substs, &item_ty); let attrs = ccx.tcx().get_attrs(instance.def); let lldecl = declare::declare_fn(ccx, symbol_name, mono_ty); From c5be6f6cc6a87368f694faf0874b3b41d359faad Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 8 Aug 2016 20:51:09 -0400 Subject: [PATCH 055/443] add cache to shared context for proj --- src/librustc_trans/context.rs | 46 +++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index 7c1a607015de..b0b7ae1f5984 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -84,6 +84,7 @@ pub struct SharedCrateContext<'a, 'tcx: 'a> { translation_items: RefCell>>, trait_cache: RefCell>>, + project_cache: RefCell>>, } /// The local portion of a `CrateContext`. There is one `LocalCrateContext` @@ -195,6 +196,46 @@ impl<'tcx> DepTrackingMapConfig for MirCache<'tcx> { } } +// # Global Cache + +pub struct ProjectionCache<'gcx> { + data: PhantomData<&'gcx ()> +} + +impl<'gcx> DepTrackingMapConfig for ProjectionCache<'gcx> { + type Key = Ty<'gcx>; + type Value = Ty<'gcx>; + fn to_dep_node(key: &Self::Key) -> DepNode { + // Ideally, we'd just put `key` into the dep-node, but we + // can't put full types in there. So just collect up all the + // def-ids of structs/enums as well as any traits that we + // project out of. It doesn't matter so much what we do here, + // except that if we are too coarse, we'll create overly + // coarse edges between impls and the trans. For example, if + // we just used the def-id of things we are projecting out of, + // then the key for `::T` and `::T` would both share a dep-node + // (`TraitSelect(SomeTrait)`), and hence the impls for both + // `Foo` and `Bar` would be considered inputs. So a change to + // `Bar` would affect things that just normalized `Foo`. + // Anyway, this heuristic is not ideal, but better than + // nothing. + let def_ids: Vec = + key.walk() + .filter_map(|t| match t.sty { + ty::TyStruct(adt_def, _) | + ty::TyEnum(adt_def, _) => + Some(adt_def.did), + ty::TyProjection(ref proj) => + Some(proj.trait_ref.def_id), + _ => + None + }) + .collect(); + DepNode::TraitSelect(def_ids) + } +} + /// This list owns a number of LocalCrateContexts and binds them to their common /// SharedCrateContext. This type just exists as a convenience, something to /// pass around all LocalCrateContexts with and get an iterator over them. @@ -496,6 +537,7 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { use_dll_storage_attrs: use_dll_storage_attrs, translation_items: RefCell::new(FnvHashSet()), trait_cache: RefCell::new(DepTrackingMap::new(tcx.dep_graph.clone())), + project_cache: RefCell::new(DepTrackingMap::new(tcx.dep_graph.clone())), } } @@ -519,6 +561,10 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { &self.trait_cache } + pub fn project_cache(&self) -> &RefCell>> { + &self.project_cache + } + pub fn link_meta<'a>(&'a self) -> &'a LinkMeta { &self.link_meta } From f5c775274275fa34b068ddf802bd528f790f7af8 Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Thu, 1 Sep 2016 00:27:03 +0300 Subject: [PATCH 056/443] Fix optimization regressions for operations on [x; n]-initialized arrays. --- src/librustc_trans/tvec.rs | 2 +- src/llvm | 2 +- src/rustllvm/llvm-auto-clean-trigger | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/librustc_trans/tvec.rs b/src/librustc_trans/tvec.rs index 7e4719870cd8..cf897fc5a151 100644 --- a/src/librustc_trans/tvec.rs +++ b/src/librustc_trans/tvec.rs @@ -52,7 +52,7 @@ pub fn slice_for_each<'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, let current = Phi(header_bcx, val_ty(start), &[start], &[bcx.llbb]); let keep_going = - ICmp(header_bcx, llvm::IntULT, current, end, DebugLoc::None); + ICmp(header_bcx, llvm::IntNE, current, end, DebugLoc::None); CondBr(header_bcx, keep_going, body_bcx.llbb, next_bcx.llbb, DebugLoc::None); let body_bcx = f(body_bcx, if zst { data_ptr } else { current }); diff --git a/src/llvm b/src/llvm index eee68eafa7e8..16b79d01fd6d 160000 --- a/src/llvm +++ b/src/llvm @@ -1 +1 @@ -Subproject commit eee68eafa7e8e4ce996b49f5551636639a6c331a +Subproject commit 16b79d01fd6d942cf3c9120b92df56b13ec92665 diff --git a/src/rustllvm/llvm-auto-clean-trigger b/src/rustllvm/llvm-auto-clean-trigger index 67f8730c2582..1080070d21a3 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. -2016-08-23 +2016-08-30 From 7057c421c0bb1cb75c26f7135b44cb7f98db6508 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 11 Aug 2016 15:46:54 -0400 Subject: [PATCH 057/443] cache projections in trans --- src/librustc_trans/monomorphize.rs | 47 ++++++++++++++++++++++++++---- 1 file changed, 41 insertions(+), 6 deletions(-) diff --git a/src/librustc_trans/monomorphize.rs b/src/librustc_trans/monomorphize.rs index 66b227fe5c54..ab2a39864336 100644 --- a/src/librustc_trans/monomorphize.rs +++ b/src/librustc_trans/monomorphize.rs @@ -8,13 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use common::*; use rustc::hir::def_id::DefId; use rustc::infer::TransNormalize; +use rustc::ty::fold::{TypeFolder, TypeFoldable}; use rustc::ty::subst::{Subst, Substs}; use rustc::ty::{self, Ty, TyCtxt}; -use common::*; use rustc::util::ppaux; - +use rustc::util::common::MemoizationMap; use std::fmt; #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] @@ -51,10 +52,8 @@ pub fn apply_param_substs<'a, 'tcx, T>(scx: &SharedCrateContext<'a, 'tcx>, let tcx = scx.tcx(); debug!("apply_param_substs(param_substs={:?}, value={:?})", param_substs, value); let substituted = value.subst(tcx, param_substs); - debug!("apply_param_substs: substituted={:?}{}", - substituted, - if substituted.has_projection_types() { " [needs projection]" } else { "" }); - tcx.normalize_associated_type(&substituted) + let substituted = scx.tcx().erase_regions(&substituted); + AssociatedTypeNormalizer::new(scx).fold(&substituted) } @@ -67,3 +66,39 @@ pub fn field_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, tcx.normalize_associated_type(&f.ty(tcx, param_substs)) } +struct AssociatedTypeNormalizer<'a, 'b: 'a, 'gcx: 'b> { + shared: &'a SharedCrateContext<'b, 'gcx>, +} + +impl<'a, 'b, 'gcx> AssociatedTypeNormalizer<'a, 'b, 'gcx> { + fn new(shared: &'a SharedCrateContext<'b, 'gcx>) -> Self { + AssociatedTypeNormalizer { + shared: shared, + } + } + + fn fold>(&mut self, value: &T) -> T { + if !value.has_projection_types() { + value.clone() + } else { + value.fold_with(self) + } + } +} + +impl<'a, 'b, 'gcx> TypeFolder<'gcx, 'gcx> for AssociatedTypeNormalizer<'a, 'b, 'gcx> { + fn tcx<'c>(&'c self) -> TyCtxt<'c, 'gcx, 'gcx> { + self.shared.tcx() + } + + fn fold_ty(&mut self, ty: Ty<'gcx>) -> Ty<'gcx> { + if !ty.has_projection_types() { + ty + } else { + self.shared.project_cache().memoize(ty, || { + debug!("AssociatedTypeNormalizer: ty={:?}", ty); + self.shared.tcx().normalize_associated_type(&ty) + }) + } + } +} From 9a400f0a313c765ed8a39d0863321ff9e88d8961 Mon Sep 17 00:00:00 2001 From: Matthew Piziak Date: Wed, 31 Aug 2016 18:17:44 -0400 Subject: [PATCH 058/443] replace `../` with `../../std/` to support `core` docs --- src/libcore/ops.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index 78c8fc0ac454..e36539bf17d5 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -217,7 +217,7 @@ macro_rules! forward_ref_binop { /// [std::time::SystemTime] implements `Add`, which permits /// operations of the form `SystemTime = SystemTime + Duration`. /// -/// [std::time::SystemTime]: ../time/struct.SystemTime.html +/// [std::time::SystemTime]: ../../std/time/struct.SystemTime.html #[lang = "add"] #[stable(feature = "rust1", since = "1.0.0")] pub trait Add { @@ -290,7 +290,7 @@ add_impl! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 f32 f64 } /// [std::time::SystemTime] implements `Sub`, which permits /// operations of the form `SystemTime = SystemTime - Duration`. /// -/// [std::time::SystemTime]: ../time/struct.SystemTime.html +/// [std::time::SystemTime]: ../../std/time/struct.SystemTime.html #[lang = "sub"] #[stable(feature = "rust1", since = "1.0.0")] pub trait Sub { From 1b0476297e6d8bee01197e507f50350a748388a2 Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Wed, 31 Aug 2016 15:19:43 -0700 Subject: [PATCH 059/443] Special case a few colors for Windows --- src/librustc_errors/emitter.rs | 15 +++++++++++++-- src/librustc_errors/lib.rs | 8 +++++++- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index ed133d21b8a0..dcdbe2a85259 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -883,7 +883,11 @@ impl Destination { Style::FileNameStyle | Style::LineAndColumn => {} Style::LineNumber => { try!(self.start_attr(term::Attr::Bold)); - try!(self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_BLUE))); + if cfg!(windows) { + try!(self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_CYAN))); + } else { + try!(self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_BLUE))); + } } Style::ErrorCode => { try!(self.start_attr(term::Attr::Bold)); @@ -896,6 +900,9 @@ impl Destination { } Style::OldSchoolNoteText | Style::HeaderMsg => { try!(self.start_attr(term::Attr::Bold)); + if cfg!(windows) { + try!(self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_WHITE))); + } } Style::UnderlinePrimary | Style::LabelPrimary => { try!(self.start_attr(term::Attr::Bold)); @@ -904,7 +911,11 @@ impl Destination { Style::UnderlineSecondary | Style::LabelSecondary => { try!(self.start_attr(term::Attr::Bold)); - try!(self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_BLUE))); + if cfg!(windows) { + try!(self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_CYAN))); + } else { + try!(self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_BLUE))); + } } Style::NoStyle => {} Style::Level(l) => { diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index c99bc4704485..d82d7dbe70f9 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -732,7 +732,13 @@ impl Level { pub fn color(self) -> term::color::Color { match self { Bug | Fatal | PhaseFatal | Error => term::color::BRIGHT_RED, - Warning => term::color::YELLOW, + Warning => { + if cfg!(windows) { + term::color::BRIGHT_YELLOW + } else { + term::color::YELLOW + } + }, Note => term::color::BRIGHT_GREEN, Help => term::color::BRIGHT_CYAN, Cancelled => unreachable!(), From 439afcd9747808fb187b0676d63af5375a677e3d Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Wed, 31 Aug 2016 17:48:26 -0700 Subject: [PATCH 060/443] Update error message for lifetime of borrowed values --- src/librustc_borrowck/borrowck/mod.rs | 22 ++++++++++------- .../borrowck-let-suggestion-suffixes.rs | 24 +++++++++---------- .../regions-escape-loop-via-vec.rs | 4 ++-- .../lifetimes}/borrowck-let-suggestion.rs | 5 ---- .../lifetimes/borrowck-let-suggestion.stderr | 14 +++++++++++ src/test/ui/span/issue-11925.stderr | 4 ++-- 6 files changed, 44 insertions(+), 29 deletions(-) rename src/test/{compile-fail/borrowck => ui/lifetimes}/borrowck-let-suggestion.rs (66%) create mode 100644 src/test/ui/lifetimes/borrowck-let-suggestion.stderr diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index e8b44d85bf91..ac8cfa7f4370 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -1029,6 +1029,12 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { } err_out_of_scope(super_scope, sub_scope, cause) => { + let (value_kind, value_msg) = match err.cmt.cat { + mc::Categorization::Rvalue(_) => + ("temporary value", "temporary value created here"), + _ => + ("borrowed value", "does not live long enough") + }; match cause { euv::ClosureCapture(s) => { // The primary span starts out as the closure creation point. @@ -1039,13 +1045,13 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { Some(primary) => { db.span = MultiSpan::from_span(s); db.span_label(primary, &format!("capture occurs here")); - db.span_label(s, &format!("does not live long enough")); + db.span_label(s, &value_msg); } None => () } } _ => { - db.span_label(error_span, &format!("does not live long enough")); + db.span_label(error_span, &value_msg); } } @@ -1054,14 +1060,15 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { match (sub_span, super_span) { (Some(s1), Some(s2)) if s1 == s2 => { - db.span_label(s1, &"borrowed value dropped before borrower"); + db.span_label(s1, &format!("{} dropped before borrower", value_kind)); db.note("values in a scope are dropped in the opposite order \ they are created"); } _ => { match sub_span { Some(s) => { - db.span_label(s, &"borrowed value must be valid until here"); + db.span_label(s, &format!("{} needs to live until here", + value_kind)); } None => { self.tcx.note_and_explain_region( @@ -1073,7 +1080,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { } match super_span { Some(s) => { - db.span_label(s, &"borrowed value only valid until here"); + db.span_label(s, &format!("{} only lives until here", value_kind)); } None => { self.tcx.note_and_explain_region( @@ -1086,9 +1093,8 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { } } - if let Some(span) = statement_scope_span(self.tcx, super_scope) { - db.span_help(span, - "consider using a `let` binding to increase its lifetime"); + if let Some(_) = statement_scope_span(self.tcx, super_scope) { + db.note("consider using a `let` binding to increase its lifetime"); } } diff --git a/src/test/compile-fail/borrowck/borrowck-let-suggestion-suffixes.rs b/src/test/compile-fail/borrowck/borrowck-let-suggestion-suffixes.rs index 6c9f67b2b33d..95c74348e788 100644 --- a/src/test/compile-fail/borrowck/borrowck-let-suggestion-suffixes.rs +++ b/src/test/compile-fail/borrowck/borrowck-let-suggestion-suffixes.rs @@ -25,9 +25,9 @@ fn f() { v3.push(&'x'); // statement 6 //~^ ERROR borrowed value does not live long enough - //~| NOTE does not live long enough - //~| NOTE borrowed value only valid until here - //~| HELP consider using a `let` binding to increase its lifetime + //~| NOTE temporary value created here + //~| NOTE temporary value only lives until here + //~| NOTE consider using a `let` binding to increase its lifetime { @@ -35,26 +35,26 @@ fn f() { v4.push(&'y'); //~^ ERROR borrowed value does not live long enough - //~| NOTE does not live long enough - //~| NOTE borrowed value only valid until here - //~| HELP consider using a `let` binding to increase its lifetime + //~| NOTE temporary value created here + //~| NOTE temporary value only lives until here + //~| NOTE consider using a `let` binding to increase its lifetime } // (statement 7) - //~^ NOTE borrowed value must be valid until here + //~^ NOTE temporary value needs to live until here let mut v5 = Vec::new(); // statement 8 v5.push(&'z'); //~^ ERROR borrowed value does not live long enough - //~| NOTE does not live long enough - //~| NOTE borrowed value only valid until here - //~| HELP consider using a `let` binding to increase its lifetime + //~| NOTE temporary value created here + //~| NOTE temporary value only lives until here + //~| NOTE consider using a `let` binding to increase its lifetime v1.push(&old[0]); } //~^ NOTE borrowed value dropped before borrower -//~| NOTE borrowed value must be valid until here -//~| NOTE borrowed value must be valid until here +//~| NOTE temporary value needs to live until here +//~| NOTE temporary value needs to live until here fn main() { f(); diff --git a/src/test/compile-fail/regions-escape-loop-via-vec.rs b/src/test/compile-fail/regions-escape-loop-via-vec.rs index 8c026df7d975..f5ea7a2108e7 100644 --- a/src/test/compile-fail/regions-escape-loop-via-vec.rs +++ b/src/test/compile-fail/regions-escape-loop-via-vec.rs @@ -24,8 +24,8 @@ fn broken() { x += 1; //~ ERROR cannot assign //~^ NOTE assignment to borrowed `x` occurs here } - //~^ NOTE borrowed value only valid until here + //~^ NOTE borrowed value only lives until here } -//~^ NOTE borrowed value must be valid until here +//~^ NOTE borrowed value needs to live until here fn main() { } diff --git a/src/test/compile-fail/borrowck/borrowck-let-suggestion.rs b/src/test/ui/lifetimes/borrowck-let-suggestion.rs similarity index 66% rename from src/test/compile-fail/borrowck/borrowck-let-suggestion.rs rename to src/test/ui/lifetimes/borrowck-let-suggestion.rs index ef8f44c1df78..eeafaab44c62 100644 --- a/src/test/compile-fail/borrowck/borrowck-let-suggestion.rs +++ b/src/test/ui/lifetimes/borrowck-let-suggestion.rs @@ -10,12 +10,7 @@ fn f() { let x = [1].iter(); - //~^ ERROR borrowed value does not live long enough - //~| NOTE does not live long enough - //~| NOTE borrowed value only valid until here - //~| HELP consider using a `let` binding to increase its lifetime } -//~^ borrowed value must be valid until here fn main() { f(); diff --git a/src/test/ui/lifetimes/borrowck-let-suggestion.stderr b/src/test/ui/lifetimes/borrowck-let-suggestion.stderr new file mode 100644 index 000000000000..91600340019c --- /dev/null +++ b/src/test/ui/lifetimes/borrowck-let-suggestion.stderr @@ -0,0 +1,14 @@ +error: borrowed value does not live long enough + --> $DIR/borrowck-let-suggestion.rs:12:13 + | +12 | let x = [1].iter(); + | ^^^ - temporary value only lives until here + | | + | temporary value created here +13 | } + | - temporary value needs to live until here + | + = note: consider using a `let` binding to increase its lifetime + +error: aborting due to previous error + diff --git a/src/test/ui/span/issue-11925.stderr b/src/test/ui/span/issue-11925.stderr index d379cfc3d68a..3fedb2884bc5 100644 --- a/src/test/ui/span/issue-11925.stderr +++ b/src/test/ui/span/issue-11925.stderr @@ -5,10 +5,10 @@ error: `x` does not live long enough | ^ | | | does not live long enough - | borrowed value only valid until here + | borrowed value only lives until here ... 23 | } - | - borrowed value must be valid until here + | - borrowed value needs to live until here error: aborting due to previous error From 00d208eea87c1cbeefb8a0a83237a71c9eea2d6c Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 31 Aug 2016 22:06:01 -0400 Subject: [PATCH 061/443] remove `normalize_infer_ctxt` constructor --- src/librustc/infer/mod.rs | 11 ----------- src/librustc/traits/specialize/mod.rs | 2 +- src/librustc_lint/types.rs | 2 +- src/librustc_trans/common.rs | 4 ++-- src/librustc_trans/context.rs | 2 +- src/librustc_trans/glue.rs | 2 +- src/librustc_trans/meth.rs | 2 +- 7 files changed, 7 insertions(+), 18 deletions(-) diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 836e52ea45a5..b6114f293ad3 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -468,17 +468,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'gcx> { } } - pub fn normalizing_infer_ctxt(self, projection_mode: Reveal) - -> InferCtxtBuilder<'a, 'gcx, 'tcx> { - InferCtxtBuilder { - global_tcx: self, - arenas: ty::CtxtArenas::new(), - tables: None, - param_env: None, - projection_mode: projection_mode, - } - } - /// Fake InferCtxt with the global tcx. Used by pre-MIR borrowck /// for MemCategorizationContext/ExprUseVisitor. /// If any inference functionality is used, ICEs will occur. diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs index 0604136ec601..f3ba4d16eb0b 100644 --- a/src/librustc/traits/specialize/mod.rs +++ b/src/librustc/traits/specialize/mod.rs @@ -147,7 +147,7 @@ pub fn specializes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, .unwrap() .subst(tcx, &penv.free_substs); - let result = tcx.normalizing_infer_ctxt(Reveal::ExactMatch).enter(|mut infcx| { + let result = tcx.infer_ctxt(None, None, Reveal::ExactMatch).enter(|mut infcx| { // Normalize the trait reference, adding any obligations // that arise into the impl1 assumptions. let Normalized { value: impl1_trait_ref, obligations: normalization_obligations } = { diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index b0b5947145db..40e78c007ccf 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -691,7 +691,7 @@ impl LateLintPass for VariantSizeDifferences { if let hir::ItemEnum(ref enum_definition, ref gens) = it.node { if gens.ty_params.is_empty() { // sizes only make sense for non-generic types let t = cx.tcx.node_id_to_type(it.id); - let layout = cx.tcx.normalizing_infer_ctxt(Reveal::All).enter(|infcx| { + let layout = cx.tcx.infer_ctxt(None, None, Reveal::All).enter(|infcx| { let ty = cx.tcx.erase_regions(&t); ty.layout(&infcx).unwrap_or_else(|e| { bug!("failed to get layout for `{}`: {}", t, e) diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index c51b32331112..f4682de7dff6 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -955,7 +955,7 @@ pub fn fulfill_obligation<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, // Do the initial selection for the obligation. This yields the // shallow result we are looking for -- that is, what specific impl. - tcx.normalizing_infer_ctxt(Reveal::All).enter(|infcx| { + tcx.infer_ctxt(None, None, Reveal::All).enter(|infcx| { let mut selcx = SelectionContext::new(&infcx); let obligation_cause = traits::ObligationCause::misc(span, @@ -1014,7 +1014,7 @@ pub fn normalize_and_test_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, debug!("normalize_and_test_predicates(predicates={:?})", predicates); - tcx.normalizing_infer_ctxt(Reveal::All).enter(|infcx| { + tcx.infer_ctxt(None, None, Reveal::All).enter(|infcx| { let mut selcx = SelectionContext::new(&infcx); let mut fulfill_cx = traits::FulfillmentContext::new(); let cause = traits::ObligationCause::dummy(); diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index b0b7ae1f5984..2422b9f30069 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -996,7 +996,7 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { } pub fn layout_of(&self, ty: Ty<'tcx>) -> &'tcx ty::layout::Layout { - self.tcx().normalizing_infer_ctxt(traits::Reveal::All).enter(|infcx| { + self.tcx().infer_ctxt(None, None, traits::Reveal::All).enter(|infcx| { ty.layout(&infcx).unwrap_or_else(|e| { bug!("failed to get layout for `{}`: {}", ty, e); }) diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs index 8d182a95a1ab..9e1e415f62a6 100644 --- a/src/librustc_trans/glue.rs +++ b/src/librustc_trans/glue.rs @@ -113,7 +113,7 @@ pub fn get_drop_glue_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, match t.sty { ty::TyBox(typ) if !type_needs_drop(tcx, typ) && type_is_sized(tcx, typ) => { - tcx.normalizing_infer_ctxt(traits::Reveal::All).enter(|infcx| { + tcx.infer_ctxt(None, None, traits::Reveal::All).enter(|infcx| { let layout = t.layout(&infcx).unwrap(); if layout.size(&tcx.data_layout).bytes() == 0 { // `Box` does not allocate. diff --git a/src/librustc_trans/meth.rs b/src/librustc_trans/meth.rs index 483bc99c310f..e958795570ee 100644 --- a/src/librustc_trans/meth.rs +++ b/src/librustc_trans/meth.rs @@ -314,7 +314,7 @@ pub fn get_impl_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, match trait_def.ancestors(impl_def_id).fn_defs(tcx, name).next() { Some(node_item) => { - let substs = tcx.normalizing_infer_ctxt(Reveal::All).enter(|infcx| { + let substs = tcx.infer_ctxt(None, None, Reveal::All).enter(|infcx| { let substs = substs.rebase_onto(tcx, trait_def_id, impl_substs); let substs = traits::translate_substs(&infcx, impl_def_id, substs, node_item.node); From cbafc5758ba905e57d3f10476deb05a79588cd81 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Mon, 29 Aug 2016 12:24:55 +1200 Subject: [PATCH 062/443] save-analsysis: add save-analysis-api CLI flag --- src/librustc/session/config.rs | 10 ++++++++-- src/librustc_driver/lib.rs | 5 ++++- src/librustc_save_analysis/lib.rs | 4 +++- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 562dce6a1b12..8eb80472d6e0 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -848,9 +848,13 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, ls: bool = (false, parse_bool, [UNTRACKED], "list the symbols defined by a library crate"), save_analysis: bool = (false, parse_bool, [UNTRACKED], - "write syntax and type analysis (in JSON format) information in addition to normal output"), + "write syntax and type analysis (in JSON format) information, \ + addition to normal output"), save_analysis_csv: bool = (false, parse_bool, [UNTRACKED], - "write syntax and type analysis (in CSV format) information in addition to normal output"), + "write syntax and type analysis (in CSV format) information, in addition to normal output"), + save_analysis_api: bool = (false, parse_bool, [UNTRACKED], + "write syntax and type analysis information for opaque libraries (in JSON format), \ + in addition to normal output"), print_move_fragments: bool = (false, parse_bool, [UNTRACKED], "print out move-fragment data for every fn"), flowgraph_print_loans: bool = (false, parse_bool, [UNTRACKED], @@ -2359,6 +2363,8 @@ mod tests { assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash()); opts.debugging_opts.save_analysis_csv = true; assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash()); + opts.debugging_opts.save_analysis_api = true; + assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash()); opts.debugging_opts.print_move_fragments = true; assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash()); opts.debugging_opts.flowgraph_print_loans = true; diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index efadf1ff488d..95f8aa620a91 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -555,7 +555,8 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls { fn save_analysis(sess: &Session) -> bool { sess.opts.debugging_opts.save_analysis || - sess.opts.debugging_opts.save_analysis_csv + sess.opts.debugging_opts.save_analysis_csv || + sess.opts.debugging_opts.save_analysis_api } fn save_analysis_format(sess: &Session) -> save::Format { @@ -563,6 +564,8 @@ fn save_analysis_format(sess: &Session) -> save::Format { save::Format::Json } else if sess.opts.debugging_opts.save_analysis_csv { save::Format::Csv + } else if sess.opts.debugging_opts.save_analysis_api { + save::Format::JsonApi } else { unreachable!(); } diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index db535e22f194..77273bd3f2ed 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -727,13 +727,14 @@ impl Visitor for PathCollector { pub enum Format { Csv, Json, + JsonApi, } impl Format { fn extension(&self) -> &'static str { match *self { Format::Csv => ".csv", - Format::Json => ".json", + Format::Json | Format::JsonApi => ".json", } } } @@ -803,6 +804,7 @@ pub fn process_crate<'l, 'tcx>(tcx: TyCtxt<'l, 'tcx, 'tcx>, match format { Format::Csv => dump!(CsvDumper::new(output)), Format::Json => dump!(JsonDumper::new(output)), + Format::JsonApi => /* TODO */ dump!(JsonDumper::new(output)), } } From c7dfc89f854f629816253f84ac0cc15d7792d63f Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Mon, 29 Aug 2016 13:29:12 +1200 Subject: [PATCH 063/443] JsonApiDumper --- src/librustc_save_analysis/json_api_dumper.rs | 356 ++++++++++++++++++ src/librustc_save_analysis/lib.rs | 4 +- 2 files changed, 359 insertions(+), 1 deletion(-) create mode 100644 src/librustc_save_analysis/json_api_dumper.rs diff --git a/src/librustc_save_analysis/json_api_dumper.rs b/src/librustc_save_analysis/json_api_dumper.rs new file mode 100644 index 000000000000..e92c23d7d7c5 --- /dev/null +++ b/src/librustc_save_analysis/json_api_dumper.rs @@ -0,0 +1,356 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::io::Write; + +use rustc::hir::def_id::DefId; +use rustc_serialize::json::as_json; + +use external_data::*; +use data::VariableKind; +use dump::Dump; + +pub struct JsonApiDumper<'b, W: Write + 'b> { + output: &'b mut W, + result: Analysis, +} + +impl<'b, W: Write> JsonApiDumper<'b, W> { + pub fn new(writer: &'b mut W) -> JsonApiDumper<'b, W> { + JsonApiDumper { output: writer, result: Analysis::new() } + } +} + +impl<'b, W: Write> Drop for JsonApiDumper<'b, W> { + fn drop(&mut self) { + if let Err(_) = write!(self.output, "{}", as_json(&self.result)) { + error!("Error writing output"); + } + } +} + +macro_rules! impl_fn { + ($fn_name: ident, $data_type: ident, $bucket: ident) => { + fn $fn_name(&mut self, data: $data_type) { + if let Some(datum) = From::from(data) { + self.result.$bucket.push(datum); + } + } + } +} + +impl<'b, W: Write + 'b> Dump for JsonApiDumper<'b, W> { + fn crate_prelude(&mut self, data: CratePreludeData) { + self.result.prelude = Some(data) + } + + impl_fn!(use_data, UseData, imports); + impl_fn!(use_glob, UseGlobData, imports); + + impl_fn!(enum_data, EnumData, defs); + impl_fn!(tuple_variant, TupleVariantData, defs); + impl_fn!(struct_variant, StructVariantData, defs); + impl_fn!(struct_data, StructData, defs); + impl_fn!(trait_data, TraitData, defs); + impl_fn!(function, FunctionData, defs); + impl_fn!(method, MethodData, defs); + impl_fn!(macro_data, MacroData, defs); + impl_fn!(mod_data, ModData, defs); + impl_fn!(typedef, TypeDefData, defs); + impl_fn!(variable, VariableData, defs); +} + +// FIXME methods. The defs have information about possible overriding and the +// refs have decl information (e.g., a trait method where we know the required +// method, but not the supplied method). In both cases, we are currently +// ignoring it. + +#[derive(Debug, RustcEncodable)] +struct Analysis { + prelude: Option, + imports: Vec, + defs: Vec, +} + +impl Analysis { + fn new() -> Analysis { + Analysis { + prelude: None, + imports: vec![], + defs: vec![], + } + } +} + +// DefId::index is a newtype and so the JSON serialisation is ugly. Therefore +// we use our own Id which is the same, but without the newtype. +#[derive(Debug, RustcEncodable)] +struct Id { + krate: u32, + index: u32, +} + +impl From for Id { + fn from(id: DefId) -> Id { + Id { + krate: id.krate, + index: id.index.as_u32(), + } + } +} + +#[derive(Debug, RustcEncodable)] +struct Import { + kind: ImportKind, + id: Id, + span: SpanData, + name: String, + value: String, +} + +#[derive(Debug, RustcEncodable)] +enum ImportKind { + Use, + GlobUse, +} + +impl From for Option { + fn from(data: UseData) -> Option { + Some(Import { + kind: ImportKind::Use, + id: From::from(data.id), + span: data.span, + name: data.name, + value: String::new(), + }) + } +} +impl From for Option { + fn from(data: UseGlobData) -> Option { + Some(Import { + kind: ImportKind::GlobUse, + id: From::from(data.id), + span: data.span, + name: "*".to_owned(), + value: data.names.join(", "), + }) + } +} + +#[derive(Debug, RustcEncodable)] +struct Def { + kind: DefKind, + id: Id, + span: SpanData, + name: String, + qualname: String, + value: String, + parent: Option, + children: Vec, + decl_id: Option, +} + +#[derive(Debug, RustcEncodable)] +enum DefKind { + // value = variant names + Enum, + // value = enum name + variant name + types + Tuple, + // value = [enum name +] name + fields + Struct, + // value = signature + Trait, + // value = type + generics + Function, + // value = type + generics + Method, + // No id, no value. + Macro, + // value = file_name + Mod, + // value = aliased type + Type, + // value = type and init expression (for all variable kinds). + Static, + Const, + Field, +} + +impl From for Option { + fn from(data: EnumData) -> Option { + Some(Def { + kind: DefKind::Enum, + id: From::from(data.id), + span: data.span, + name: data.name, + qualname: data.qualname, + value: data.value, + parent: None, + children: data.variants.into_iter().map(|id| From::from(id)).collect(), + decl_id: None, + }) + } +} + +impl From for Option { + fn from(data: TupleVariantData) -> Option { + Some(Def { + kind: DefKind::Tuple, + id: From::from(data.id), + span: data.span, + name: data.name, + qualname: data.qualname, + value: data.value, + parent: None, + children: vec![], + decl_id: None, + }) + } +} +impl From for Option { + fn from(data: StructVariantData) -> Option { + Some(Def { + kind: DefKind::Struct, + id: From::from(data.id), + span: data.span, + name: data.name, + qualname: data.qualname, + value: data.value, + parent: None, + children: vec![], + decl_id: None, + }) + } +} +impl From for Option { + fn from(data: StructData) -> Option { + Some(Def { + kind: DefKind::Struct, + id: From::from(data.id), + span: data.span, + name: data.name, + qualname: data.qualname, + value: data.value, + parent: None, + children: data.fields.into_iter().map(|id| From::from(id)).collect(), + decl_id: None, + }) + } +} +impl From for Option { + fn from(data: TraitData) -> Option { + Some(Def { + kind: DefKind::Trait, + id: From::from(data.id), + span: data.span, + name: data.name, + qualname: data.qualname, + value: data.value, + children: data.items.into_iter().map(|id| From::from(id)).collect(), + parent: None, + decl_id: None, + }) + } +} +impl From for Option { + fn from(data: FunctionData) -> Option { + Some(Def { + kind: DefKind::Function, + id: From::from(data.id), + span: data.span, + name: data.name, + qualname: data.qualname, + value: data.value, + children: vec![], + parent: None, + decl_id: None, + }) + } +} +impl From for Option { + fn from(data: MethodData) -> Option { + Some(Def { + kind: DefKind::Method, + id: From::from(data.id), + span: data.span, + name: data.name, + qualname: data.qualname, + value: data.value, + children: vec![], + parent: None, + decl_id: data.decl_id.map(|id| From::from(id)), + }) + } +} +impl From for Option { + fn from(data: MacroData) -> Option { + Some(Def { + kind: DefKind::Macro, + id: From::from(null_def_id()), + span: data.span, + name: data.name, + qualname: data.qualname, + value: String::new(), + children: vec![], + parent: None, + decl_id: None, + }) + } +} +impl From for Option { + fn from(data:ModData) -> Option { + Some(Def { + kind: DefKind::Mod, + id: From::from(data.id), + span: data.span, + name: data.name, + qualname: data.qualname, + value: data.filename, + children: data.items.into_iter().map(|id| From::from(id)).collect(), + parent: None, + decl_id: None, + }) + } +} +impl From for Option { + fn from(data: TypeDefData) -> Option { + Some(Def { + kind: DefKind::Type, + id: From::from(data.id), + span: data.span, + name: data.name, + qualname: data.qualname, + value: data.value, + children: vec![], + parent: None, + decl_id: None, + }) + } +} +impl From for Option { + fn from(data: VariableData) -> Option { + Some(Def { + kind: match data.kind { + VariableKind::Static => DefKind::Static, + VariableKind::Const => DefKind::Const, + VariableKind::Local => { return None } + VariableKind::Field => DefKind::Field, + }, + id: From::from(data.id), + span: data.span, + name: data.name, + qualname: data.qualname, + value: data.value, + children: vec![], + parent: None, + decl_id: None, + }) + } +} diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 77273bd3f2ed..5aa8bec3d36c 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -30,6 +30,7 @@ extern crate serialize as rustc_serialize; extern crate syntax_pos; mod csv_dumper; +mod json_api_dumper; mod json_dumper; mod data; mod dump; @@ -57,6 +58,7 @@ use syntax::codemap::MacroAttribute; use syntax_pos::*; pub use self::csv_dumper::CsvDumper; +pub use self::json_api_dumper::JsonApiDumper; pub use self::json_dumper::JsonDumper; pub use self::data::*; pub use self::dump::Dump; @@ -804,7 +806,7 @@ pub fn process_crate<'l, 'tcx>(tcx: TyCtxt<'l, 'tcx, 'tcx>, match format { Format::Csv => dump!(CsvDumper::new(output)), Format::Json => dump!(JsonDumper::new(output)), - Format::JsonApi => /* TODO */ dump!(JsonDumper::new(output)), + Format::JsonApi => dump!(JsonApiDumper::new(output)), } } From 4e4306c6dfa7a8dd43a7ee9bbc531f4b14b03aec Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Mon, 29 Aug 2016 16:46:55 +1200 Subject: [PATCH 064/443] Thread visibility info through save-analysis and filter save-analysis-api on it. --- src/librustc_save_analysis/data.rs | 47 +++- src/librustc_save_analysis/dump_visitor.rs | 39 ++- src/librustc_save_analysis/external_data.rs | 28 ++- src/librustc_save_analysis/json_api_dumper.rs | 228 ++++++++++-------- src/librustc_save_analysis/lib.rs | 15 +- 5 files changed, 235 insertions(+), 122 deletions(-) diff --git a/src/librustc_save_analysis/data.rs b/src/librustc_save_analysis/data.rs index 493f7669337f..b88276578889 100644 --- a/src/librustc_save_analysis/data.rs +++ b/src/librustc_save_analysis/data.rs @@ -13,8 +13,9 @@ //! The `Dump` trait can be used together with `DumpVisitor` in order to //! retrieve the data from a crate. +use rustc::hir; use rustc::hir::def_id::DefId; -use syntax::ast::{CrateNum, NodeId}; +use syntax::ast::{self, CrateNum, NodeId}; use syntax_pos::Span; pub struct CrateData { @@ -76,6 +77,35 @@ pub enum Data { VariableRefData(VariableRefData), } +#[derive(Eq, PartialEq, Clone, Copy, Debug, RustcEncodable)] +pub enum Visibility { + Public, + Restricted, + Inherited, +} + +impl<'a> From<&'a ast::Visibility> for Visibility { + fn from(v: &'a ast::Visibility) -> Visibility { + match *v { + ast::Visibility::Public => Visibility::Public, + ast::Visibility::Crate(_) => Visibility::Restricted, + ast::Visibility::Restricted { .. } => Visibility::Restricted, + ast::Visibility::Inherited => Visibility::Inherited, + } + } +} + +impl<'a> From<&'a hir::Visibility> for Visibility { + fn from(v: &'a hir::Visibility) -> Visibility { + match *v { + hir::Visibility::Public => Visibility::Public, + hir::Visibility::Crate => Visibility::Restricted, + hir::Visibility::Restricted { .. } => Visibility::Restricted, + hir::Visibility::Inherited => Visibility::Inherited, + } + } +} + /// Data for the prelude of a crate. #[derive(Debug, RustcEncodable)] pub struct CratePreludeData { @@ -103,7 +133,7 @@ pub struct EnumData { pub span: Span, pub scope: NodeId, pub variants: Vec, - + pub visibility: Visibility, } /// Data for extern crates. @@ -135,6 +165,7 @@ pub struct FunctionData { pub span: Span, pub scope: NodeId, pub value: String, + pub visibility: Visibility, } /// Data about a function call. @@ -215,6 +246,7 @@ pub struct MethodData { pub scope: NodeId, pub value: String, pub decl_id: Option, + pub visibility: Visibility, } /// Data for modules. @@ -227,6 +259,7 @@ pub struct ModData { pub scope: NodeId, pub filename: String, pub items: Vec, + pub visibility: Visibility, } /// Data for a reference to a module. @@ -248,6 +281,7 @@ pub struct StructData { pub scope: NodeId, pub value: String, pub fields: Vec, + pub visibility: Visibility, } #[derive(Debug, RustcEncodable)] @@ -270,6 +304,7 @@ pub struct TraitData { pub scope: NodeId, pub value: String, pub items: Vec, + pub visibility: Visibility, } #[derive(Debug, RustcEncodable)] @@ -291,6 +326,7 @@ pub struct TypeDefData { pub span: Span, pub qualname: String, pub value: String, + pub visibility: Visibility, } /// Data for a reference to a type or trait. @@ -308,7 +344,8 @@ pub struct UseData { pub span: Span, pub name: String, pub mod_id: Option, - pub scope: NodeId + pub scope: NodeId, + pub visibility: Visibility, } #[derive(Debug, RustcEncodable)] @@ -316,7 +353,8 @@ pub struct UseGlobData { pub id: NodeId, pub span: Span, pub names: Vec, - pub scope: NodeId + pub scope: NodeId, + pub visibility: Visibility, } /// Data for local and global variables (consts and statics). @@ -330,6 +368,7 @@ pub struct VariableData { pub scope: NodeId, pub value: String, pub type_value: String, + pub visibility: Visibility, } #[derive(Debug, RustcEncodable)] diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index dbe956f021e4..e0475bfed931 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -364,7 +364,8 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { qualname: format!("{}::{}", qualname, path_to_string(p)), type_value: typ, value: String::new(), - scope: 0 + scope: 0, + visibility: Visibility::Inherited, }.lower(self.tcx)); } } @@ -376,6 +377,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { body: Option<&ast::Block>, id: ast::NodeId, name: ast::Name, + vis: Visibility, span: Span) { debug!("process_method: {}:{}", id, name); @@ -416,6 +418,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { qualname: method_data.qualname.clone(), value: sig_str, decl_id: decl_id, + visibility: vis, }.lower(self.tcx)); } @@ -483,7 +486,8 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { name: name, id: param.id, qualname: qualname, - value: String::new() + value: String::new(), + visibility: Visibility::Inherited, }.lower(self.tcx)); } } @@ -532,7 +536,8 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { name: ast::Name, span: Span, typ: &ast::Ty, - expr: &ast::Expr) { + expr: &ast::Expr, + vis: Visibility) { let qualname = format!("::{}", self.tcx.node_path_str(id)); let sub_span = self.span.sub_span_after_keyword(span, keywords::Const); @@ -546,7 +551,8 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { qualname: qualname, value: self.span.snippet(expr.span), type_value: ty_to_string(&typ), - scope: self.cur_scope + scope: self.cur_scope, + visibility: vis, }.lower(self.tcx)); } @@ -588,6 +594,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { scope: self.cur_scope, value: val, fields: fields, + visibility: From::from(&item.vis), }.lower(self.tcx)); } @@ -744,6 +751,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { scope: self.cur_scope, value: val, items: methods.iter().map(|i| i.id).collect(), + visibility: From::from(&item.vis), }.lower(self.tcx)); } @@ -989,7 +997,8 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { qualname: format!("{}${}", path_to_string(p), id), value: value, type_value: typ, - scope: 0 + scope: 0, + visibility: Visibility::Inherited, }.lower(self.tcx)); } } @@ -1072,7 +1081,8 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D> id: item.id, mod_id: mod_id, name: ident.to_string(), - scope: self.cur_scope + scope: self.cur_scope, + visibility: From::from(&item.vis), }.lower(self.tcx)); } self.write_sub_paths_truncated(path, true); @@ -1095,7 +1105,8 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D> span: sub_span.expect("No span found for use glob"), id: item.id, names: names, - scope: self.cur_scope + scope: self.cur_scope, + visibility: From::from(&item.vis), }.lower(self.tcx)); } self.write_sub_paths(path, true); @@ -1167,7 +1178,8 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D> name: item.ident.to_string(), id: item.id, qualname: qualname.clone(), - value: value + value: value, + visibility: From::from(&item.vis), }.lower(self.tcx)); } @@ -1200,13 +1212,15 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D> trait_item.ident.name, trait_item.span, &ty, - &expr); + &expr, + Visibility::Public); } ast::TraitItemKind::Method(ref sig, ref body) => { self.process_method(sig, body.as_ref().map(|x| &**x), trait_item.id, trait_item.ident.name, + Visibility::Public, trait_item.span); } ast::TraitItemKind::Const(_, None) | @@ -1223,13 +1237,15 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D> impl_item.ident.name, impl_item.span, &ty, - &expr); + &expr, + From::from(&impl_item.vis)); } ast::ImplItemKind::Method(ref sig, ref body) => { self.process_method(sig, Some(body), impl_item.id, impl_item.ident.name, + From::from(&impl_item.vis), impl_item.span); } ast::ImplItemKind::Type(_) | @@ -1399,7 +1415,8 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D> qualname: format!("{}${}", path_to_string(p), id), value: value, type_value: String::new(), - scope: 0 + scope: 0, + visibility: Visibility::Inherited, }.lower(self.tcx)); } } diff --git a/src/librustc_save_analysis/external_data.rs b/src/librustc_save_analysis/external_data.rs index 65e4f7e869b0..b7dded7b6247 100644 --- a/src/librustc_save_analysis/external_data.rs +++ b/src/librustc_save_analysis/external_data.rs @@ -15,7 +15,7 @@ use syntax::ast::{CrateNum, NodeId}; use syntax::codemap::CodeMap; use syntax_pos::Span; -use data; +use data::{self, Visibility}; // FIXME: this should be pub(crate), but the current snapshot doesn't allow it yet pub trait Lower { @@ -91,7 +91,8 @@ pub struct EnumData { pub qualname: String, pub span: SpanData, pub scope: DefId, - pub variants: Vec + pub variants: Vec, + pub visibility: Visibility, } impl Lower for data::EnumData { @@ -106,6 +107,7 @@ impl Lower for data::EnumData { span: SpanData::from_span(self.span, tcx.sess.codemap()), scope: make_def_id(self.scope, &tcx.map), variants: self.variants.into_iter().map(|id| make_def_id(id, &tcx.map)).collect(), + visibility: self.visibility, } } } @@ -166,6 +168,7 @@ pub struct FunctionData { pub span: SpanData, pub scope: DefId, pub value: String, + pub visibility: Visibility, } impl Lower for data::FunctionData { @@ -180,6 +183,7 @@ impl Lower for data::FunctionData { span: SpanData::from_span(self.span, tcx.sess.codemap()), scope: make_def_id(self.scope, &tcx.map), value: self.value, + visibility: self.visibility, } } } @@ -323,6 +327,7 @@ pub struct MethodData { pub scope: DefId, pub value: String, pub decl_id: Option, + pub visibility: Visibility, } impl Lower for data::MethodData { @@ -337,6 +342,7 @@ impl Lower for data::MethodData { qualname: self.qualname, value: self.value, decl_id: self.decl_id, + visibility: self.visibility, } } } @@ -351,6 +357,7 @@ pub struct ModData { pub scope: DefId, pub filename: String, pub items: Vec, + pub visibility: Visibility, } impl Lower for data::ModData { @@ -365,6 +372,7 @@ impl Lower for data::ModData { scope: make_def_id(self.scope, &tcx.map), filename: self.filename, items: self.items.into_iter().map(|id| make_def_id(id, &tcx.map)).collect(), + visibility: self.visibility, } } } @@ -401,6 +409,7 @@ pub struct StructData { pub scope: DefId, pub value: String, pub fields: Vec, + pub visibility: Visibility, } impl Lower for data::StructData { @@ -416,6 +425,7 @@ impl Lower for data::StructData { scope: make_def_id(self.scope, &tcx.map), value: self.value, fields: self.fields.into_iter().map(|id| make_def_id(id, &tcx.map)).collect(), + visibility: self.visibility, } } } @@ -456,6 +466,7 @@ pub struct TraitData { pub scope: DefId, pub value: String, pub items: Vec, + pub visibility: Visibility, } impl Lower for data::TraitData { @@ -470,6 +481,7 @@ impl Lower for data::TraitData { scope: make_def_id(self.scope, &tcx.map), value: self.value, items: self.items.into_iter().map(|id| make_def_id(id, &tcx.map)).collect(), + visibility: self.visibility, } } } @@ -509,6 +521,7 @@ pub struct TypeDefData { pub span: SpanData, pub qualname: String, pub value: String, + pub visibility: Visibility, } impl Lower for data::TypeDefData { @@ -521,6 +534,7 @@ impl Lower for data::TypeDefData { span: SpanData::from_span(self.span, tcx.sess.codemap()), qualname: self.qualname, value: self.value, + visibility: self.visibility, } } } @@ -553,7 +567,8 @@ pub struct UseData { pub span: SpanData, pub name: String, pub mod_id: Option, - pub scope: DefId + pub scope: DefId, + pub visibility: Visibility, } impl Lower for data::UseData { @@ -566,6 +581,7 @@ impl Lower for data::UseData { name: self.name, mod_id: self.mod_id, scope: make_def_id(self.scope, &tcx.map), + visibility: self.visibility, } } } @@ -575,7 +591,8 @@ pub struct UseGlobData { pub id: DefId, pub span: SpanData, pub names: Vec, - pub scope: DefId + pub scope: DefId, + pub visibility: Visibility, } impl Lower for data::UseGlobData { @@ -587,6 +604,7 @@ impl Lower for data::UseGlobData { span: SpanData::from_span(self.span, tcx.sess.codemap()), names: self.names, scope: make_def_id(self.scope, &tcx.map), + visibility: self.visibility, } } } @@ -602,6 +620,7 @@ pub struct VariableData { pub scope: DefId, pub value: String, pub type_value: String, + pub visibility: Visibility, } impl Lower for data::VariableData { @@ -617,6 +636,7 @@ impl Lower for data::VariableData { scope: make_def_id(self.scope, &tcx.map), value: self.value, type_value: self.type_value, + visibility: self.visibility, } } } diff --git a/src/librustc_save_analysis/json_api_dumper.rs b/src/librustc_save_analysis/json_api_dumper.rs index e92c23d7d7c5..9cc1badf7cdd 100644 --- a/src/librustc_save_analysis/json_api_dumper.rs +++ b/src/librustc_save_analysis/json_api_dumper.rs @@ -14,7 +14,7 @@ use rustc::hir::def_id::DefId; use rustc_serialize::json::as_json; use external_data::*; -use data::VariableKind; +use data::{VariableKind, Visibility}; use dump::Dump; pub struct JsonApiDumper<'b, W: Write + 'b> { @@ -123,24 +123,30 @@ enum ImportKind { impl From for Option { fn from(data: UseData) -> Option { - Some(Import { - kind: ImportKind::Use, - id: From::from(data.id), - span: data.span, - name: data.name, - value: String::new(), - }) + match data.visibility { + Visibility::Public => Some(Import { + kind: ImportKind::Use, + id: From::from(data.id), + span: data.span, + name: data.name, + value: String::new(), + }), + _ => None, + } } } impl From for Option { fn from(data: UseGlobData) -> Option { - Some(Import { - kind: ImportKind::GlobUse, - id: From::from(data.id), - span: data.span, - name: "*".to_owned(), - value: data.names.join(", "), - }) + match data.visibility { + Visibility::Public => Some(Import { + kind: ImportKind::GlobUse, + id: From::from(data.id), + span: data.span, + name: "*".to_owned(), + value: data.names.join(", "), + }), + _ => None, + } } } @@ -185,17 +191,20 @@ enum DefKind { impl From for Option { fn from(data: EnumData) -> Option { - Some(Def { - kind: DefKind::Enum, - id: From::from(data.id), - span: data.span, - name: data.name, - qualname: data.qualname, - value: data.value, - parent: None, - children: data.variants.into_iter().map(|id| From::from(id)).collect(), - decl_id: None, - }) + match data.visibility { + Visibility::Public => Some(Def { + kind: DefKind::Enum, + id: From::from(data.id), + span: data.span, + name: data.name, + qualname: data.qualname, + value: data.value, + parent: None, + children: data.variants.into_iter().map(|id| From::from(id)).collect(), + decl_id: None, + }), + _ => None, + } } } @@ -231,7 +240,8 @@ impl From for Option { } impl From for Option { fn from(data: StructData) -> Option { - Some(Def { + match data.visibility { + Visibility::Public => Some(Def { kind: DefKind::Struct, id: From::from(data.id), span: data.span, @@ -241,52 +251,63 @@ impl From for Option { parent: None, children: data.fields.into_iter().map(|id| From::from(id)).collect(), decl_id: None, - }) + }), + _ => None, + } } } impl From for Option { fn from(data: TraitData) -> Option { - Some(Def { - kind: DefKind::Trait, - id: From::from(data.id), - span: data.span, - name: data.name, - qualname: data.qualname, - value: data.value, - children: data.items.into_iter().map(|id| From::from(id)).collect(), - parent: None, - decl_id: None, - }) + match data.visibility { + Visibility::Public => Some(Def { + kind: DefKind::Trait, + id: From::from(data.id), + span: data.span, + name: data.name, + qualname: data.qualname, + value: data.value, + children: data.items.into_iter().map(|id| From::from(id)).collect(), + parent: None, + decl_id: None, + }), + _ => None, + } } } impl From for Option { fn from(data: FunctionData) -> Option { - Some(Def { - kind: DefKind::Function, - id: From::from(data.id), - span: data.span, - name: data.name, - qualname: data.qualname, - value: data.value, - children: vec![], - parent: None, - decl_id: None, - }) + match data.visibility { + Visibility::Public => Some(Def { + kind: DefKind::Function, + id: From::from(data.id), + span: data.span, + name: data.name, + qualname: data.qualname, + value: data.value, + children: vec![], + parent: None, + decl_id: None, + }), + _ => None, + } } } impl From for Option { fn from(data: MethodData) -> Option { - Some(Def { - kind: DefKind::Method, - id: From::from(data.id), - span: data.span, - name: data.name, - qualname: data.qualname, - value: data.value, - children: vec![], - parent: None, - decl_id: data.decl_id.map(|id| From::from(id)), - }) + match data.visibility { + Visibility::Public => Some(Def { + kind: DefKind::Method, + id: From::from(data.id), + span: data.span, + name: data.name, + qualname: data.qualname, + value: data.value, + children: vec![], + parent: None, + decl_id: data.decl_id.map(|id| From::from(id)), + }), + _ => None, + } } } impl From for Option { @@ -306,51 +327,60 @@ impl From for Option { } impl From for Option { fn from(data:ModData) -> Option { - Some(Def { - kind: DefKind::Mod, - id: From::from(data.id), - span: data.span, - name: data.name, - qualname: data.qualname, - value: data.filename, - children: data.items.into_iter().map(|id| From::from(id)).collect(), - parent: None, - decl_id: None, - }) + match data.visibility { + Visibility::Public => Some(Def { + kind: DefKind::Mod, + id: From::from(data.id), + span: data.span, + name: data.name, + qualname: data.qualname, + value: data.filename, + children: data.items.into_iter().map(|id| From::from(id)).collect(), + parent: None, + decl_id: None, + }), + _ => None, + } } } impl From for Option { fn from(data: TypeDefData) -> Option { - Some(Def { - kind: DefKind::Type, - id: From::from(data.id), - span: data.span, - name: data.name, - qualname: data.qualname, - value: data.value, - children: vec![], - parent: None, - decl_id: None, - }) + match data.visibility { + Visibility::Public => Some(Def { + kind: DefKind::Type, + id: From::from(data.id), + span: data.span, + name: data.name, + qualname: data.qualname, + value: data.value, + children: vec![], + parent: None, + decl_id: None, + }), + _ => None, + } } } impl From for Option { fn from(data: VariableData) -> Option { - Some(Def { - kind: match data.kind { - VariableKind::Static => DefKind::Static, - VariableKind::Const => DefKind::Const, - VariableKind::Local => { return None } - VariableKind::Field => DefKind::Field, - }, - id: From::from(data.id), - span: data.span, - name: data.name, - qualname: data.qualname, - value: data.value, - children: vec![], - parent: None, - decl_id: None, - }) + match data.visibility { + Visibility::Public => Some(Def { + kind: match data.kind { + VariableKind::Static => DefKind::Static, + VariableKind::Const => DefKind::Const, + VariableKind::Local => { return None } + VariableKind::Field => DefKind::Field, + }, + id: From::from(data.id), + span: data.span, + name: data.name, + qualname: data.qualname, + value: data.value, + children: vec![], + parent: None, + decl_id: None, + }), + _ => None, + } } } diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 5aa8bec3d36c..3645eb68394d 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -140,6 +140,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { span: sub_span.unwrap(), scope: self.enclosing_scope(item.id), value: make_signature(decl, generics), + visibility: From::from(&item.vis), })) } ast::ItemKind::Static(ref typ, mt, ref expr) => { @@ -164,6 +165,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { scope: self.enclosing_scope(item.id), value: value, type_value: ty_to_string(&typ), + visibility: From::from(&item.vis), })) } ast::ItemKind::Const(ref typ, ref expr) => { @@ -179,6 +181,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { scope: self.enclosing_scope(item.id), value: self.span_utils.snippet(expr.span), type_value: ty_to_string(&typ), + visibility: From::from(&item.vis), })) } ast::ItemKind::Mod(ref m) => { @@ -197,6 +200,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { scope: self.enclosing_scope(item.id), filename: filename, items: m.items.iter().map(|i| i.id).collect(), + visibility: From::from(&item.vis), })) } ast::ItemKind::Enum(ref def, _) => { @@ -217,6 +221,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { qualname: qualname, scope: self.enclosing_scope(item.id), variants: def.variants.iter().map(|v| v.node.data.id()).collect(), + visibility: From::from(&item.vis), })) } ast::ItemKind::Impl(_, _, _, ref trait_ref, ref typ, _) => { @@ -281,6 +286,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { scope: scope, value: "".to_owned(), type_value: typ, + visibility: From::from(&field.vis), }) } else { None @@ -293,7 +299,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 = match self.tcx.impl_of_method(self.tcx.map.local_def_id(id)) { + let (qualname, vis) = match self.tcx.impl_of_method(self.tcx.map.local_def_id(id)) { Some(impl_id) => match self.tcx.map.get_if_local(impl_id) { Some(NodeItem(item)) => { match item.node { @@ -306,7 +312,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { result.push_str(&self.tcx.item_path_str(def_id)); } result.push_str(">"); - result + (result, From::from(&item.vis)) } _ => { span_bug!(span, @@ -327,8 +333,8 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { None => match self.tcx.trait_of_item(self.tcx.map.local_def_id(id)) { Some(def_id) => { match self.tcx.map.get_if_local(def_id) { - Some(NodeItem(_)) => { - format!("::{}", self.tcx.item_path_str(def_id)) + Some(NodeItem(item)) => { + (format!("::{}", self.tcx.item_path_str(def_id)), From::from(&item.vis)) } r => { span_bug!(span, @@ -369,6 +375,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { scope: self.enclosing_scope(id), // FIXME you get better data here by using the visitor. value: String::new(), + visibility: vis, }) } From 4dc7b585a2d7784e5c8a8e390c77441df4aea29b Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Tue, 30 Aug 2016 16:00:48 +1200 Subject: [PATCH 065/443] save-analysis: add parent info to api dumps The parent id is used for constructing rustdoc URLs by clients --- src/librustc_driver/driver.rs | 3 +- src/librustc_save_analysis/data.rs | 9 +- src/librustc_save_analysis/dump_visitor.rs | 131 ++++++++++-------- src/librustc_save_analysis/external_data.rs | 14 +- src/librustc_save_analysis/json_api_dumper.rs | 19 ++- src/librustc_save_analysis/lib.rs | 6 + src/test/run-make/save-analysis/Makefile | 1 + 7 files changed, 113 insertions(+), 70 deletions(-) diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 94092be4922b..df1378f9e0d0 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -248,7 +248,8 @@ fn keep_hygiene_data(sess: &Session) -> bool { fn keep_ast(sess: &Session) -> bool { sess.opts.debugging_opts.keep_ast || sess.opts.debugging_opts.save_analysis || - sess.opts.debugging_opts.save_analysis_csv + sess.opts.debugging_opts.save_analysis_csv || + sess.opts.debugging_opts.save_analysis_api } /// The name used for source code that doesn't originate in a file diff --git a/src/librustc_save_analysis/data.rs b/src/librustc_save_analysis/data.rs index b88276578889..a58cce0745f3 100644 --- a/src/librustc_save_analysis/data.rs +++ b/src/librustc_save_analysis/data.rs @@ -166,6 +166,7 @@ pub struct FunctionData { pub scope: NodeId, pub value: String, pub visibility: Visibility, + pub parent: Option, } /// Data about a function call. @@ -292,7 +293,8 @@ pub struct StructVariantData { pub qualname: String, pub type_value: String, pub value: String, - pub scope: NodeId + pub scope: NodeId, + pub parent: Option, } #[derive(Debug, RustcEncodable)] @@ -315,7 +317,8 @@ pub struct TupleVariantData { pub qualname: String, pub type_value: String, pub value: String, - pub scope: NodeId + pub scope: NodeId, + pub parent: Option, } /// Data for a typedef. @@ -327,6 +330,7 @@ pub struct TypeDefData { pub qualname: String, pub value: String, pub visibility: Visibility, + pub parent: Option, } /// Data for a reference to a type or trait. @@ -366,6 +370,7 @@ pub struct VariableData { pub qualname: String, pub span: Span, pub scope: NodeId, + pub parent: Option, pub value: String, pub type_value: String, pub visibility: Visibility, diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index e0475bfed931..c4eba4171de0 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -365,6 +365,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { type_value: typ, value: String::new(), scope: 0, + parent: None, visibility: Visibility::Inherited, }.lower(self.tcx)); } @@ -488,6 +489,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { qualname: qualname, value: String::new(), visibility: Visibility::Inherited, + parent: None, }.lower(self.tcx)); } } @@ -531,13 +533,14 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { self.visit_expr(expr); } - fn process_const(&mut self, - id: ast::NodeId, - name: ast::Name, - span: Span, - typ: &ast::Ty, - expr: &ast::Expr, - vis: Visibility) { + fn process_assoc_const(&mut self, + id: ast::NodeId, + name: ast::Name, + span: Span, + typ: &ast::Ty, + expr: &ast::Expr, + parent_id: NodeId, + vis: Visibility) { let qualname = format!("::{}", self.tcx.node_path_str(id)); let sub_span = self.span.sub_span_after_keyword(span, keywords::Const); @@ -552,6 +555,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { value: self.span.snippet(expr.span), type_value: ty_to_string(&typ), scope: self.cur_scope, + parent: Some(parent_id), visibility: vis, }.lower(self.tcx)); } @@ -646,7 +650,8 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { qualname: qualname, type_value: enum_data.qualname.clone(), value: val, - scope: enum_data.scope + scope: enum_data.scope, + parent: Some(item.id), }.lower(self.tcx)); } } @@ -669,7 +674,8 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { qualname: qualname, type_value: enum_data.qualname.clone(), value: val, - scope: enum_data.scope + scope: enum_data.scope, + parent: Some(item.id), }.lower(self.tcx)); } } @@ -722,7 +728,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { } self.process_generic_params(type_parameters, item.span, "", item.id); for impl_item in impl_items { - self.visit_impl_item(impl_item); + self.process_impl_item(impl_item, item.id); } } @@ -792,7 +798,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { // walk generics and methods self.process_generic_params(generics, item.span, &qualname, item.id); for method in methods { - self.visit_trait_item(method) + self.process_trait_item(method, item.id) } } @@ -998,6 +1004,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { value: value, type_value: typ, scope: 0, + parent: None, visibility: Visibility::Inherited, }.lower(self.tcx)); } @@ -1046,6 +1053,57 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { } } } + + fn process_trait_item(&mut self, trait_item: &ast::TraitItem, trait_id: NodeId) { + self.process_macro_use(trait_item.span, trait_item.id); + match trait_item.node { + ast::TraitItemKind::Const(ref ty, Some(ref expr)) => { + self.process_assoc_const(trait_item.id, + trait_item.ident.name, + trait_item.span, + &ty, + &expr, + trait_id, + Visibility::Public); + } + ast::TraitItemKind::Method(ref sig, ref body) => { + self.process_method(sig, + body.as_ref().map(|x| &**x), + trait_item.id, + trait_item.ident.name, + Visibility::Public, + trait_item.span); + } + ast::TraitItemKind::Const(_, None) | + ast::TraitItemKind::Type(..) | + ast::TraitItemKind::Macro(_) => {} + } + } + + fn process_impl_item(&mut self, impl_item: &ast::ImplItem, impl_id: NodeId) { + self.process_macro_use(impl_item.span, impl_item.id); + match impl_item.node { + ast::ImplItemKind::Const(ref ty, ref expr) => { + self.process_assoc_const(impl_item.id, + impl_item.ident.name, + impl_item.span, + &ty, + &expr, + impl_id, + From::from(&impl_item.vis)); + } + ast::ImplItemKind::Method(ref sig, ref body) => { + self.process_method(sig, + Some(body), + impl_item.id, + impl_item.ident.name, + From::from(&impl_item.vis), + impl_item.span); + } + ast::ImplItemKind::Type(_) | + ast::ImplItemKind::Macro(_) => {} + } + } } impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D> { @@ -1180,6 +1238,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D> qualname: qualname.clone(), value: value, visibility: From::from(&item.vis), + parent: None, }.lower(self.tcx)); } @@ -1204,55 +1263,6 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D> } } - fn visit_trait_item(&mut self, trait_item: &ast::TraitItem) { - self.process_macro_use(trait_item.span, trait_item.id); - match trait_item.node { - ast::TraitItemKind::Const(ref ty, Some(ref expr)) => { - self.process_const(trait_item.id, - trait_item.ident.name, - trait_item.span, - &ty, - &expr, - Visibility::Public); - } - ast::TraitItemKind::Method(ref sig, ref body) => { - self.process_method(sig, - body.as_ref().map(|x| &**x), - trait_item.id, - trait_item.ident.name, - Visibility::Public, - trait_item.span); - } - ast::TraitItemKind::Const(_, None) | - ast::TraitItemKind::Type(..) | - ast::TraitItemKind::Macro(_) => {} - } - } - - fn visit_impl_item(&mut self, impl_item: &ast::ImplItem) { - self.process_macro_use(impl_item.span, impl_item.id); - match impl_item.node { - ast::ImplItemKind::Const(ref ty, ref expr) => { - self.process_const(impl_item.id, - impl_item.ident.name, - impl_item.span, - &ty, - &expr, - From::from(&impl_item.vis)); - } - ast::ImplItemKind::Method(ref sig, ref body) => { - self.process_method(sig, - Some(body), - impl_item.id, - impl_item.ident.name, - From::from(&impl_item.vis), - impl_item.span); - } - ast::ImplItemKind::Type(_) | - ast::ImplItemKind::Macro(_) => {} - } - } - fn visit_ty(&mut self, t: &ast::Ty) { self.process_macro_use(t.span, t.id); match t.node { @@ -1416,6 +1426,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D> value: value, type_value: String::new(), scope: 0, + parent: None, visibility: Visibility::Inherited, }.lower(self.tcx)); } diff --git a/src/librustc_save_analysis/external_data.rs b/src/librustc_save_analysis/external_data.rs index b7dded7b6247..4333c6dd18e6 100644 --- a/src/librustc_save_analysis/external_data.rs +++ b/src/librustc_save_analysis/external_data.rs @@ -169,6 +169,7 @@ pub struct FunctionData { pub scope: DefId, pub value: String, pub visibility: Visibility, + pub parent: Option, } impl Lower for data::FunctionData { @@ -184,6 +185,7 @@ impl Lower for data::FunctionData { scope: make_def_id(self.scope, &tcx.map), value: self.value, visibility: self.visibility, + parent: self.parent.map(|id| make_def_id(id, &tcx.map)), } } } @@ -328,6 +330,7 @@ pub struct MethodData { pub value: String, pub decl_id: Option, pub visibility: Visibility, + pub parent: Option } impl Lower for data::MethodData { @@ -343,6 +346,7 @@ impl Lower for data::MethodData { value: self.value, decl_id: self.decl_id, visibility: self.visibility, + parent: Some(make_def_id(self.scope, &tcx.map)), } } } @@ -438,7 +442,8 @@ pub struct StructVariantData { pub qualname: String, pub type_value: String, pub value: String, - pub scope: DefId + pub scope: DefId, + pub parent: Option, } impl Lower for data::StructVariantData { @@ -453,6 +458,7 @@ impl Lower for data::StructVariantData { type_value: self.type_value, value: self.value, scope: make_def_id(self.scope, &tcx.map), + parent: self.parent.map(|id| make_def_id(id, &tcx.map)), } } } @@ -495,6 +501,7 @@ pub struct TupleVariantData { pub type_value: String, pub value: String, pub scope: DefId, + pub parent: Option, } impl Lower for data::TupleVariantData { @@ -509,6 +516,7 @@ impl Lower for data::TupleVariantData { type_value: self.type_value, value: self.value, scope: make_def_id(self.scope, &tcx.map), + parent: self.parent.map(|id| make_def_id(id, &tcx.map)), } } } @@ -522,6 +530,7 @@ pub struct TypeDefData { pub qualname: String, pub value: String, pub visibility: Visibility, + pub parent: Option, } impl Lower for data::TypeDefData { @@ -535,6 +544,7 @@ impl Lower for data::TypeDefData { qualname: self.qualname, value: self.value, visibility: self.visibility, + parent: self.parent.map(|id| make_def_id(id, &tcx.map)), } } } @@ -620,6 +630,7 @@ pub struct VariableData { pub scope: DefId, pub value: String, pub type_value: String, + pub parent: Option, pub visibility: Visibility, } @@ -636,6 +647,7 @@ impl Lower for data::VariableData { scope: make_def_id(self.scope, &tcx.map), value: self.value, type_value: self.type_value, + parent: self.parent.map(|id| make_def_id(id, &tcx.map)), visibility: self.visibility, } } diff --git a/src/librustc_save_analysis/json_api_dumper.rs b/src/librustc_save_analysis/json_api_dumper.rs index 9cc1badf7cdd..874babb907e4 100644 --- a/src/librustc_save_analysis/json_api_dumper.rs +++ b/src/librustc_save_analysis/json_api_dumper.rs @@ -17,6 +17,13 @@ use external_data::*; use data::{VariableKind, Visibility}; use dump::Dump; +// A dumper to dump a restricted set of JSON information, designed for use with +// libraries distributed without their source. Clients are likely to use type +// information here, and (for example) generate Rustdoc URLs, but don't need +// information for navigating the source of the crate. +// Relative to the regular JSON save-analysis info, this form is filtered to +// remove non-visible items, but includes some extra info for items (e.g., the +// parent field for finding the struct to which a field belongs). pub struct JsonApiDumper<'b, W: Write + 'b> { output: &'b mut W, result: Analysis, @@ -217,7 +224,7 @@ impl From for Option { name: data.name, qualname: data.qualname, value: data.value, - parent: None, + parent: data.parent.map(|id| From::from(id)), children: vec![], decl_id: None, }) @@ -232,7 +239,7 @@ impl From for Option { name: data.name, qualname: data.qualname, value: data.value, - parent: None, + parent: data.parent.map(|id| From::from(id)), children: vec![], decl_id: None, }) @@ -285,7 +292,7 @@ impl From for Option { qualname: data.qualname, value: data.value, children: vec![], - parent: None, + parent: data.parent.map(|id| From::from(id)), decl_id: None, }), _ => None, @@ -303,7 +310,7 @@ impl From for Option { qualname: data.qualname, value: data.value, children: vec![], - parent: None, + parent: data.parent.map(|id| From::from(id)), decl_id: data.decl_id.map(|id| From::from(id)), }), _ => None, @@ -354,7 +361,7 @@ impl From for Option { qualname: data.qualname, value: data.value, children: vec![], - parent: None, + parent: data.parent.map(|id| From::from(id)), decl_id: None, }), _ => None, @@ -377,7 +384,7 @@ impl From for Option { qualname: data.qualname, value: data.value, children: vec![], - parent: None, + parent: data.parent.map(|id| From::from(id)), decl_id: None, }), _ => None, diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 3645eb68394d..9478e25cff7e 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -141,6 +141,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { scope: self.enclosing_scope(item.id), value: make_signature(decl, generics), visibility: From::from(&item.vis), + parent: None, })) } ast::ItemKind::Static(ref typ, mt, ref expr) => { @@ -163,6 +164,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { qualname: qualname, span: sub_span.unwrap(), scope: self.enclosing_scope(item.id), + parent: None, value: value, type_value: ty_to_string(&typ), visibility: From::from(&item.vis), @@ -179,6 +181,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { qualname: qualname, span: sub_span.unwrap(), scope: self.enclosing_scope(item.id), + parent: None, value: self.span_utils.snippet(expr.span), type_value: ty_to_string(&typ), visibility: From::from(&item.vis), @@ -284,6 +287,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { qualname: qualname, span: sub_span.unwrap(), scope: scope, + parent: Some(scope), value: "".to_owned(), type_value: typ, visibility: From::from(&field.vis), @@ -366,6 +370,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { let sub_span = self.span_utils.sub_span_after_keyword(span, keywords::Fn); filter!(self.span_utils, sub_span, span, None); + let parent_scope = self.enclosing_scope(id); Some(FunctionData { id: id, name: name.to_string(), @@ -376,6 +381,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { // FIXME you get better data here by using the visitor. value: String::new(), visibility: vis, + parent: Some(parent_scope), }) } diff --git a/src/test/run-make/save-analysis/Makefile b/src/test/run-make/save-analysis/Makefile index 3c636baaedc5..3711b6ea8959 100644 --- a/src/test/run-make/save-analysis/Makefile +++ b/src/test/run-make/save-analysis/Makefile @@ -5,3 +5,4 @@ krate2: krate2.rs code: foo.rs krate2 $(RUSTC) foo.rs -Zsave-analysis-csv $(RUSTC) foo.rs -Zsave-analysis + $(RUSTC) foo.rs -Zsave-analysis-api From 377be7a5014052766784b2dda1d5b5e33e191b6b Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Tue, 30 Aug 2016 16:40:44 +1200 Subject: [PATCH 066/443] review comments --- src/librustc/session/config.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 8eb80472d6e0..572097881624 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -848,7 +848,7 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, ls: bool = (false, parse_bool, [UNTRACKED], "list the symbols defined by a library crate"), save_analysis: bool = (false, parse_bool, [UNTRACKED], - "write syntax and type analysis (in JSON format) information, \ + "write syntax and type analysis (in JSON format) information, in \ addition to normal output"), save_analysis_csv: bool = (false, parse_bool, [UNTRACKED], "write syntax and type analysis (in CSV format) information, in addition to normal output"), From 3d766a077944f167dbd412538af4c6957943374d Mon Sep 17 00:00:00 2001 From: CensoredUsername Date: Thu, 1 Sep 2016 10:35:37 +0200 Subject: [PATCH 067/443] the win64 calling convention is also used on x86_64-pc-windows-gnu, so ignore windows entirely instead of just msvc --- src/test/run-pass/abi-sysv64-arg-passing.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/run-pass/abi-sysv64-arg-passing.rs b/src/test/run-pass/abi-sysv64-arg-passing.rs index 3f6ae71ffa8e..989155bdfd98 100644 --- a/src/test/run-pass/abi-sysv64-arg-passing.rs +++ b/src/test/run-pass/abi-sysv64-arg-passing.rs @@ -35,9 +35,9 @@ // ignore-android // ignore-arm // ignore-aarch64 -// ignore-msvc +// ignore-windows -// note: msvc is ignored as rust_test_helpers does not have the sysv64 abi on msvc +// note: windows is ignored as rust_test_helpers does not have the sysv64 abi on windows #![feature(abi_sysv64)] #[allow(dead_code)] From 7b92d05804bea222dc6904274f9fc186a6c5208a Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Thu, 1 Sep 2016 13:34:56 +0300 Subject: [PATCH 068/443] turn the RFC1592 warnings into hard errors The warnings have already reached stable The test rfc1592_deprecated is covered by `bad_sized` and `unsized6`. Fixes #33242 Fixes #33243 --- src/librustc/lint/builtin.rs | 14 --- src/librustc/middle/free_region.rs | 1 - src/librustc/traits/error_reporting.rs | 122 ++++--------------- src/librustc/traits/fulfill.rs | 38 ------ src/librustc/traits/object_safety.rs | 2 - src/librustc/traits/select.rs | 16 +-- src/librustc/traits/util.rs | 6 - src/librustc/ty/mod.rs | 17 +-- src/librustc/ty/structural_impls.rs | 6 - src/librustc/ty/util.rs | 1 - src/librustc/ty/wf.rs | 32 ++--- src/librustc/util/ppaux.rs | 4 - src/librustc_lint/lib.rs | 8 -- src/librustc_metadata/tyencode.rs | 3 - src/librustc_mir/transform/qualify_consts.rs | 4 - src/librustc_typeck/astconv.rs | 4 +- src/librustc_typeck/check/closure.rs | 1 - src/librustc_typeck/check/coercion.rs | 2 +- src/librustc_typeck/check/dropck.rs | 4 - src/librustc_typeck/check/method/probe.rs | 1 - src/librustc_typeck/check/mod.rs | 8 -- src/librustc_typeck/collect.rs | 1 - src/librustdoc/clean/mod.rs | 1 - src/test/compile-fail/bad-sized.rs | 2 + src/test/compile-fail/issue-32963.rs | 1 + src/test/compile-fail/rfc1592-deprecated.rs | 32 ----- src/test/compile-fail/unsized6.rs | 4 +- src/test/run-pass/rfc1592-deprecated.rs | 29 ----- 28 files changed, 50 insertions(+), 314 deletions(-) delete mode 100644 src/test/compile-fail/rfc1592-deprecated.rs delete mode 100644 src/test/run-pass/rfc1592-deprecated.rs diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index b2ee38741fca..ed94e5fe377c 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -186,18 +186,6 @@ declare_lint! { "detects super or self keywords at the beginning of global path" } -declare_lint! { - pub UNSIZED_IN_TUPLE, - Warn, - "unsized types in the interior of a tuple were erroneously allowed" -} - -declare_lint! { - pub OBJECT_UNSAFE_FRAGMENT, - Warn, - "object-unsafe non-principal fragments in object types were erroneously allowed" -} - declare_lint! { pub LIFETIME_UNDERSCORE, Warn, @@ -239,8 +227,6 @@ impl LintPass for HardwiredLints { OVERLAPPING_INHERENT_IMPLS, RENAMED_AND_REMOVED_LINTS, SUPER_OR_SELF_IN_GLOBAL_PATH, - UNSIZED_IN_TUPLE, - OBJECT_UNSAFE_FRAGMENT, HR_LIFETIME_IN_ASSOC_TYPE, LIFETIME_UNDERSCORE ) diff --git a/src/librustc/middle/free_region.rs b/src/librustc/middle/free_region.rs index 8193d062631c..bd35bfc9829a 100644 --- a/src/librustc/middle/free_region.rs +++ b/src/librustc/middle/free_region.rs @@ -55,7 +55,6 @@ impl FreeRegionMap { match *predicate { ty::Predicate::Projection(..) | ty::Predicate::Trait(..) | - ty::Predicate::Rfc1592(..) | ty::Predicate::Equate(..) | ty::Predicate::WellFormed(..) | ty::Predicate::ObjectSafe(..) | diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 8318a29de1c5..6d6d7c2b3ba0 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -36,27 +36,23 @@ use util::nodemap::{FnvHashMap, FnvHashSet}; use std::cmp; use std::fmt; -use syntax::ast; use syntax_pos::Span; use errors::DiagnosticBuilder; #[derive(Debug, PartialEq, Eq, Hash)] pub struct TraitErrorKey<'tcx> { span: Span, - warning_node_id: Option, predicate: ty::Predicate<'tcx> } impl<'a, 'gcx, 'tcx> TraitErrorKey<'tcx> { fn from_error(infcx: &InferCtxt<'a, 'gcx, 'tcx>, - e: &FulfillmentError<'tcx>, - warning_node_id: Option) -> Self { + e: &FulfillmentError<'tcx>) -> Self { let predicate = infcx.resolve_type_vars_if_possible(&e.obligation.predicate); TraitErrorKey { span: e.obligation.cause.span, - predicate: infcx.tcx.erase_regions(&predicate), - warning_node_id: warning_node_id + predicate: infcx.tcx.erase_regions(&predicate) } } } @@ -64,22 +60,13 @@ impl<'a, 'gcx, 'tcx> TraitErrorKey<'tcx> { impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { pub fn report_fulfillment_errors(&self, errors: &Vec>) { for error in errors { - self.report_fulfillment_error(error, None); - } - } - - pub fn report_fulfillment_errors_as_warnings(&self, - errors: &Vec>, - node_id: ast::NodeId) { - for error in errors { - self.report_fulfillment_error(error, Some(node_id)); + self.report_fulfillment_error(error); } } fn report_fulfillment_error(&self, - error: &FulfillmentError<'tcx>, - warning_node_id: Option) { - let error_key = TraitErrorKey::from_error(self, error, warning_node_id); + error: &FulfillmentError<'tcx>) { + let error_key = TraitErrorKey::from_error(self, error); debug!("report_fulfillment_errors({:?}) - key={:?}", error, error_key); if !self.reported_trait_errors.borrow_mut().insert(error_key) { @@ -88,10 +75,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } match error.code { FulfillmentErrorCode::CodeSelectionError(ref e) => { - self.report_selection_error(&error.obligation, e, warning_node_id); + self.report_selection_error(&error.obligation, e); } FulfillmentErrorCode::CodeProjectionError(ref e) => { - self.report_projection_error(&error.obligation, e, warning_node_id); + self.report_projection_error(&error.obligation, e); } FulfillmentErrorCode::CodeAmbiguity => { self.maybe_report_ambiguity(&error.obligation); @@ -101,8 +88,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { fn report_projection_error(&self, obligation: &PredicateObligation<'tcx>, - error: &MismatchedProjectionTypes<'tcx>, - warning_node_id: Option) + error: &MismatchedProjectionTypes<'tcx>) { let predicate = self.resolve_type_vars_if_possible(&obligation.predicate); @@ -110,16 +96,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { if predicate.references_error() { return } - if let Some(warning_node_id) = warning_node_id { - self.tcx.sess.add_lint( - ::lint::builtin::UNSIZED_IN_TUPLE, - warning_node_id, - obligation.cause.span, - format!("type mismatch resolving `{}`: {}", - predicate, - error.err)); - return - } + self.probe(|_| { let origin = TypeOrigin::Misc(obligation.cause.span); let err_buf; @@ -442,8 +419,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { pub fn report_selection_error(&self, obligation: &PredicateObligation<'tcx>, - error: &SelectionError<'tcx>, - warning_node_id: Option) + error: &SelectionError<'tcx>) { let span = obligation.cause.span; let mut err = match *error { @@ -466,16 +442,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } else { let trait_ref = trait_predicate.to_poly_trait_ref(); - if let Some(warning_node_id) = warning_node_id { - self.tcx.sess.add_lint( - ::lint::builtin::UNSIZED_IN_TUPLE, - warning_node_id, - obligation.cause.span, - format!("the trait bound `{}` is not satisfied", - trait_ref.to_predicate())); - return; - } - let mut err = struct_span_err!(self.tcx.sess, span, E0277, "the trait bound `{}` is not satisfied", trait_ref.to_predicate()); @@ -541,15 +507,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { ty::Predicate::ObjectSafe(trait_def_id) => { let violations = self.tcx.object_safety_violations(trait_def_id); - let err = self.tcx.report_object_safety_error(span, - trait_def_id, - warning_node_id, - violations); - if let Some(err) = err { - err - } else { - return; - } + self.tcx.report_object_safety_error(span, + trait_def_id, + violations) } ty::Predicate::ClosureKind(closure_def_id, kind) => { @@ -577,13 +537,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // (which may fail). span_bug!(span, "WF predicate not satisfied for {:?}", ty); } - - ty::Predicate::Rfc1592(ref data) => { - span_bug!( - obligation.cause.span, - "RFC1592 predicate not satisfied for {:?}", - data); - } } } } @@ -605,14 +558,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { TraitNotObjectSafe(did) => { let violations = self.tcx.object_safety_violations(did); - let err = self.tcx.report_object_safety_error(span, did, - warning_node_id, - violations); - if let Some(err) = err { - err - } else { - return; - } + self.tcx.report_object_safety_error(span, did, + violations) } }; self.note_obligation_cause(&mut err, obligation); @@ -640,24 +587,17 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn report_object_safety_error(self, span: Span, trait_def_id: DefId, - warning_node_id: Option, violations: Vec) - -> Option> + -> DiagnosticBuilder<'tcx> { - let mut err = match warning_node_id { - Some(_) => None, - None => { - let trait_str = self.item_path_str(trait_def_id); - let mut db = struct_span_err!( - self.sess, span, E0038, - "the trait `{}` cannot be made into an object", - trait_str); - db.span_label(span, - &format!("the trait `{}` cannot be made \ - into an object", trait_str)); - Some(db) - } - }; + let trait_str = self.item_path_str(trait_def_id); + let mut err = struct_span_err!( + self.sess, span, E0038, + "the trait `{}` cannot be made into an object", + trait_str); + err.span_label(span, &format!( + "the trait `{}` cannot be made into an object", trait_str + )); let mut reported_violations = FnvHashSet(); for violation in violations { @@ -697,19 +637,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { &buf } }; - match (warning_node_id, &mut err) { - (Some(node_id), &mut None) => { - self.sess.add_lint( - ::lint::builtin::OBJECT_UNSAFE_FRAGMENT, - node_id, - span, - note.to_string()); - } - (None, &mut Some(ref mut err)) => { - err.note(note); - } - _ => unreachable!() - } + err.note(note); } err } diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index 6598aacc1d3d..65860671c4c6 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -57,9 +57,6 @@ pub struct FulfillmentContext<'tcx> { // fulfillment context. predicates: ObligationForest>, - // A list of new obligations due to RFC1592. - rfc1592_obligations: Vec>, - // A set of constraints that regionck must validate. Each // constraint has the form `T:'a`, meaning "some type `T` must // outlive the lifetime 'a". These constraints derive from @@ -192,7 +189,6 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> { pub fn new() -> FulfillmentContext<'tcx> { FulfillmentContext { predicates: ObligationForest::new(), - rfc1592_obligations: Vec::new(), region_obligations: NodeMap(), deferred_obligations: vec![], } @@ -275,13 +271,6 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> { }); } - pub fn register_rfc1592_obligation(&mut self, - _infcx: &InferCtxt<'a, 'gcx, 'tcx>, - obligation: PredicateObligation<'tcx>) - { - self.rfc1592_obligations.push(obligation); - } - pub fn region_obligations(&self, body_id: ast::NodeId) -> &[RegionObligation<'tcx>] @@ -292,21 +281,6 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> { } } - pub fn select_rfc1592_obligations(&mut self, - infcx: &InferCtxt<'a, 'gcx, 'tcx>) - -> Result<(),Vec>> - { - while !self.rfc1592_obligations.is_empty() { - for obligation in mem::replace(&mut self.rfc1592_obligations, Vec::new()) { - self.register_predicate_obligation(infcx, obligation); - } - - self.select_all_or_error(infcx)?; - } - - Ok(()) - } - pub fn select_all_or_error(&mut self, infcx: &InferCtxt<'a, 'gcx, 'tcx>) -> Result<(),Vec>> @@ -362,7 +336,6 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> { let outcome = self.predicates.process_obligations(&mut FulfillProcessor { selcx: selcx, region_obligations: &mut self.region_obligations, - rfc1592_obligations: &mut self.rfc1592_obligations, deferred_obligations: &mut self.deferred_obligations }); debug!("select: outcome={:?}", outcome); @@ -398,7 +371,6 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> { struct FulfillProcessor<'a, 'b: 'a, 'gcx: 'tcx, 'tcx: 'b> { selcx: &'a mut SelectionContext<'b, 'gcx, 'tcx>, region_obligations: &'a mut NodeMap>>, - rfc1592_obligations: &'a mut Vec>, deferred_obligations: &'a mut Vec> } @@ -413,7 +385,6 @@ impl<'a, 'b, 'gcx, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'gcx, process_predicate(self.selcx, obligation, self.region_obligations, - self.rfc1592_obligations, self.deferred_obligations) .map(|os| os.map(|os| os.into_iter().map(|o| PendingPredicateObligation { obligation: o, @@ -455,7 +426,6 @@ fn process_predicate<'a, 'gcx, 'tcx>( selcx: &mut SelectionContext<'a, 'gcx, 'tcx>, pending_obligation: &mut PendingPredicateObligation<'tcx>, region_obligations: &mut NodeMap>>, - rfc1592_obligations: &mut Vec>, deferred_obligations: &mut Vec>) -> Result>>, FulfillmentErrorCode<'tcx>> @@ -644,14 +614,6 @@ fn process_predicate<'a, 'gcx, 'tcx>( s => Ok(s) } } - - ty::Predicate::Rfc1592(ref inner) => { - rfc1592_obligations.push(PredicateObligation { - predicate: ty::Predicate::clone(inner), - ..obligation.clone() - }); - Ok(Some(vec![])) - } } } diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs index 219d52004676..5f7b71518291 100644 --- a/src/librustc/traits/object_safety.rs +++ b/src/librustc/traits/object_safety.rs @@ -153,7 +153,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { ty::Predicate::TypeOutlives(..) | ty::Predicate::RegionOutlives(..) | ty::Predicate::ClosureKind(..) | - ty::Predicate::Rfc1592(..) | ty::Predicate::Equate(..) => { false } @@ -184,7 +183,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } ty::Predicate::Projection(..) | ty::Predicate::Trait(..) | - ty::Predicate::Rfc1592(..) | ty::Predicate::Equate(..) | ty::Predicate::RegionOutlives(..) | ty::Predicate::WellFormed(..) | diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index b015de79be5c..0573f0c5bbaa 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -513,8 +513,6 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } match obligation.predicate { - ty::Predicate::Rfc1592(..) => EvaluatedToOk, - ty::Predicate::Trait(ref t) => { assert!(!t.has_escaping_regions()); let obligation = obligation.with(t.clone()); @@ -1779,8 +1777,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { ty::TyStr | ty::TySlice(_) | ty::TyTrait(..) => Never, ty::TyTuple(tys) => { - // FIXME(#33242) we only need to constrain the last field - Where(ty::Binder(tys.to_vec())) + Where(ty::Binder(tys.last().into_iter().cloned().collect())) } ty::TyStruct(def, substs) | ty::TyEnum(def, substs) => { @@ -2508,12 +2505,11 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // T -> Trait. (_, &ty::TyTrait(ref data)) => { - let mut object_dids = Some(data.principal.def_id()).into_iter(); - // FIXME(#33243) -// data.builtin_bounds.iter().flat_map(|bound| { -// tcx.lang_items.from_builtin_kind(bound).ok() -// }) -// .chain(Some(data.principal.def_id())); + let mut object_dids = + data.builtin_bounds.iter().flat_map(|bound| { + tcx.lang_items.from_builtin_kind(bound).ok() + }) + .chain(Some(data.principal.def_id())); if let Some(did) = object_dids.find(|did| { !tcx.is_object_safe(*did) }) { diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs index 038de25312d3..2cefc2ad7964 100644 --- a/src/librustc/traits/util.rs +++ b/src/librustc/traits/util.rs @@ -23,9 +23,6 @@ fn anonymize_predicate<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, ty::Predicate::Trait(ref data) => ty::Predicate::Trait(tcx.anonymize_late_bound_regions(data)), - ty::Predicate::Rfc1592(ref data) => - ty::Predicate::Rfc1592(Box::new(anonymize_predicate(tcx, data))), - ty::Predicate::Equate(ref data) => ty::Predicate::Equate(tcx.anonymize_late_bound_regions(data)), @@ -150,9 +147,6 @@ impl<'cx, 'gcx, 'tcx> Elaborator<'cx, 'gcx, 'tcx> { self.stack.extend(predicates); } - ty::Predicate::Rfc1592(..) => { - // Nothing to elaborate. - } ty::Predicate::WellFormed(..) => { // Currently, we do not elaborate WF predicates, // although we easily could. diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 1ea82a9c639d..09420077a8ab 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -804,9 +804,6 @@ pub enum Predicate<'tcx> { /// would be the type parameters. Trait(PolyTraitPredicate<'tcx>), - /// A predicate created by RFC1592 - Rfc1592(Box>), - /// where `T1 == T2`. Equate(PolyEquatePredicate<'tcx>), @@ -906,8 +903,6 @@ impl<'a, 'gcx, 'tcx> Predicate<'tcx> { match *self { Predicate::Trait(ty::Binder(ref data)) => Predicate::Trait(ty::Binder(data.subst(tcx, substs))), - Predicate::Rfc1592(ref pi) => - Predicate::Rfc1592(Box::new(pi.subst_supertrait(tcx, trait_ref))), Predicate::Equate(ty::Binder(ref data)) => Predicate::Equate(ty::Binder(data.subst(tcx, substs))), Predicate::RegionOutlives(ty::Binder(ref data)) => @@ -1108,9 +1103,6 @@ impl<'tcx> Predicate<'tcx> { ty::Predicate::Trait(ref data) => { data.skip_binder().input_types().collect() } - ty::Predicate::Rfc1592(ref data) => { - return data.walk_tys() - } ty::Predicate::Equate(ty::Binder(ref data)) => { vec![data.0, data.1] } @@ -1148,7 +1140,6 @@ impl<'tcx> Predicate<'tcx> { Predicate::Trait(ref t) => { Some(t.to_poly_trait_ref()) } - Predicate::Rfc1592(..) | Predicate::Projection(..) | Predicate::Equate(..) | Predicate::RegionOutlives(..) | @@ -1820,10 +1811,10 @@ impl<'a, 'tcx> AdtDefData<'tcx, 'tcx> { } TyTuple(ref tys) => { - // FIXME(#33242) we only need to constrain the last field - tys.iter().flat_map(|ty| { - self.sized_constraint_for_ty(tcx, stack, ty) - }).collect() + match tys.last() { + None => vec![], + Some(ty) => self.sized_constraint_for_ty(tcx, stack, ty) + } } TyEnum(adt, substs) | TyStruct(adt, substs) => { diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 705cca056f24..ad3769605abd 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -178,9 +178,6 @@ impl<'a, 'tcx> Lift<'tcx> for ty::Predicate<'a> { ty::Predicate::WellFormed(ty) => { tcx.lift(&ty).map(ty::Predicate::WellFormed) } - ty::Predicate::Rfc1592(box ref a) => { - tcx.lift(a).map(|a| ty::Predicate::Rfc1592(Box::new(a))) - } ty::Predicate::ClosureKind(closure_def_id, kind) => { Some(ty::Predicate::ClosureKind(closure_def_id, kind)) } @@ -790,8 +787,6 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> { match *self { ty::Predicate::Trait(ref a) => ty::Predicate::Trait(a.fold_with(folder)), - ty::Predicate::Rfc1592(ref a) => - ty::Predicate::Rfc1592(a.fold_with(folder)), ty::Predicate::Equate(ref binder) => ty::Predicate::Equate(binder.fold_with(folder)), ty::Predicate::RegionOutlives(ref binder) => @@ -812,7 +807,6 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> { fn super_visit_with>(&self, visitor: &mut V) -> bool { match *self { ty::Predicate::Trait(ref a) => a.visit_with(visitor), - ty::Predicate::Rfc1592(ref a) => a.visit_with(visitor), ty::Predicate::Equate(ref binder) => binder.visit_with(visitor), ty::Predicate::RegionOutlives(ref binder) => binder.visit_with(visitor), ty::Predicate::TypeOutlives(ref binder) => binder.visit_with(visitor), diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index dd5c6a9758ab..77d16287fedc 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -318,7 +318,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { match predicate { ty::Predicate::Projection(..) | ty::Predicate::Trait(..) | - ty::Predicate::Rfc1592(..) | ty::Predicate::Equate(..) | ty::Predicate::WellFormed(..) | ty::Predicate::ObjectSafe(..) | diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs index 1f166cb192fa..aef646a7aaca 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/ty/wf.rs @@ -94,9 +94,6 @@ pub fn predicate_obligations<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, } ty::Predicate::ClosureKind(..) => { } - ty::Predicate::Rfc1592(ref data) => { - bug!("RFC1592 predicate `{:?}` in predicate_obligations", data); - } } wf.normalize() @@ -158,7 +155,6 @@ pub fn implied_bounds<'a, 'gcx, 'tcx>( assert!(!obligation.has_escaping_regions()); match obligation.predicate { ty::Predicate::Trait(..) | - ty::Predicate::Rfc1592(..) | ty::Predicate::Equate(..) | ty::Predicate::Projection(..) | ty::Predicate::ClosureKind(..) | @@ -282,21 +278,14 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { } } - fn require_sized(&mut self, subty: Ty<'tcx>, cause: traits::ObligationCauseCode<'tcx>, - rfc1592: bool) { + fn require_sized(&mut self, subty: Ty<'tcx>, cause: traits::ObligationCauseCode<'tcx>) { if !subty.has_escaping_regions() { let cause = self.cause(cause); match self.infcx.tcx.trait_ref_for_builtin_bound(ty::BoundSized, subty) { Ok(trait_ref) => { - let predicate = trait_ref.to_predicate(); - let predicate = if rfc1592 { - ty::Predicate::Rfc1592(box predicate) - } else { - predicate - }; self.out.push( traits::Obligation::new(cause, - predicate)); + trait_ref.to_predicate())); } Err(ErrorReported) => { } } @@ -326,13 +315,13 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { ty::TySlice(subty) | ty::TyArray(subty, _) => { - self.require_sized(subty, traits::SliceOrArrayElem, false); + self.require_sized(subty, traits::SliceOrArrayElem); } ty::TyTuple(ref tys) => { if let Some((_last, rest)) = tys.split_last() { for elem in rest { - self.require_sized(elem, traits::TupleElem, true); + self.require_sized(elem, traits::TupleElem); } } } @@ -401,22 +390,15 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { let cause = self.cause(traits::MiscObligation); - // FIXME(#33243): remove RFC1592 - self.out.push(traits::Obligation::new( - cause.clone(), - ty::Predicate::ObjectSafe(data.principal.def_id()) - )); let component_traits = data.builtin_bounds.iter().flat_map(|bound| { tcx.lang_items.from_builtin_kind(bound).ok() - }); -// .chain(Some(data.principal.def_id())); + }) + .chain(Some(data.principal.def_id())); self.out.extend( component_traits.map(|did| { traits::Obligation::new( cause.clone(), - ty::Predicate::Rfc1592( - box ty::Predicate::ObjectSafe(did) - ) + ty::Predicate::ObjectSafe(did) )}) ); } diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 24b68c66e466..7e2cc2938ca9 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -487,9 +487,6 @@ impl<'tcx> fmt::Debug for ty::Predicate<'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { ty::Predicate::Trait(ref a) => write!(f, "{:?}", a), - ty::Predicate::Rfc1592(ref a) => { - write!(f, "RFC1592({:?})", a) - } ty::Predicate::Equate(ref pair) => write!(f, "{:?}", pair), ty::Predicate::RegionOutlives(ref pair) => write!(f, "{:?}", pair), ty::Predicate::TypeOutlives(ref pair) => write!(f, "{:?}", pair), @@ -1083,7 +1080,6 @@ impl<'tcx> fmt::Display for ty::Predicate<'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { ty::Predicate::Trait(ref data) => write!(f, "{}", data), - ty::Predicate::Rfc1592(ref data) => write!(f, "{}", data), ty::Predicate::Equate(ref predicate) => write!(f, "{}", predicate), ty::Predicate::RegionOutlives(ref predicate) => write!(f, "{}", predicate), ty::Predicate::TypeOutlives(ref predicate) => write!(f, "{}", predicate), diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index 1a4330f58c3c..0f0e9cfb3577 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -191,14 +191,6 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { id: LintId::of(ILLEGAL_STRUCT_OR_ENUM_CONSTANT_PATTERN), reference: "RFC 1445 ", }, - FutureIncompatibleInfo { - id: LintId::of(UNSIZED_IN_TUPLE), - reference: "issue #33242 ", - }, - FutureIncompatibleInfo { - id: LintId::of(OBJECT_UNSAFE_FRAGMENT), - reference: "issue #33243 ", - }, FutureIncompatibleInfo { id: LintId::of(HR_LIFETIME_IN_ASSOC_TYPE), reference: "issue #33685 ", diff --git a/src/librustc_metadata/tyencode.rs b/src/librustc_metadata/tyencode.rs index 7255eae61d45..954ca878c01e 100644 --- a/src/librustc_metadata/tyencode.rs +++ b/src/librustc_metadata/tyencode.rs @@ -479,9 +479,6 @@ pub fn enc_predicate<'a, 'tcx>(w: &mut Cursor>, p: &ty::Predicate<'tcx>) { match *p { - ty::Predicate::Rfc1592(..) => { - bug!("RFC1592 predicate in metadata `{:?}`", p); - } ty::Predicate::Trait(ref trait_ref) => { write!(w, "t"); enc_trait_ref(w, cx, trait_ref.0.trait_ref); diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 9e076851bc37..2fc90ab27a08 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -1019,10 +1019,6 @@ impl<'tcx> MirMapPass<'tcx> for QualifyAndPromoteConstants { if let Err(err) = fulfillment_cx.select_all_or_error(&infcx) { infcx.report_fulfillment_errors(&err); } - - if let Err(errors) = fulfillment_cx.select_rfc1592_obligations(&infcx) { - infcx.report_fulfillment_errors_as_warnings(&errors, id); - } }); } } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index f24a7cf2121e..e15b0b4044ee 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1128,8 +1128,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { tcx.astconv_object_safety_violations(principal.def_id()); if !object_safety_violations.is_empty() { tcx.report_object_safety_error( - span, principal.def_id(), None, object_safety_violations) - .unwrap().emit(); + span, principal.def_id(), object_safety_violations) + .emit(); return tcx.types.err; } diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index 46e8c27f6d33..516dd9c64221 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -165,7 +165,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { ty::Predicate::TypeOutlives(..) => None, ty::Predicate::WellFormed(..) => None, ty::Predicate::ObjectSafe(..) => None, - ty::Predicate::Rfc1592(..) => None, // NB: This predicate is created by breaking down a // `ClosureType: FnFoo()` predicate, where diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 26a470552897..365c18d5e666 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -484,7 +484,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { // Object safety violations or miscellaneous. Err(err) => { - self.report_selection_error(&obligation, &err, None); + self.report_selection_error(&obligation, &err); // Treat this like an obligation and follow through // with the unsizing - the lack of a coercion should // be silent, as it causes a type mismatch later. diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index cede9d871ff4..3a6076774330 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -111,10 +111,6 @@ fn ensure_drop_params_and_item_params_correspond<'a, 'tcx>( return Err(()); } - if let Err(ref errors) = fulfillment_cx.select_rfc1592_obligations(&infcx) { - infcx.report_fulfillment_errors_as_warnings(errors, drop_impl_node_id); - } - let free_regions = FreeRegionMap::new(); infcx.resolve_regions_and_report_errors(&free_regions, drop_impl_node_id); Ok(()) diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 29366823fffd..2e2cb2765d93 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -496,7 +496,6 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { ty::Predicate::WellFormed(..) | ty::Predicate::ObjectSafe(..) | ty::Predicate::ClosureKind(..) | - ty::Predicate::Rfc1592(..) | ty::Predicate::TypeOutlives(..) => { None } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index a7ea8bd7959f..90a9d9bffe7d 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -505,10 +505,6 @@ pub fn check_item_bodies(ccx: &CrateCtxt) -> CompileResult { if let Err(errors) = fulfillment_cx.select_all_or_error(&infcx) { infcx.report_fulfillment_errors(&errors); } - - if let Err(errors) = fulfillment_cx.select_rfc1592_obligations(&infcx) { - infcx.report_fulfillment_errors_as_warnings(&errors, item_id); - } }); } }) @@ -2245,10 +2241,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { Ok(()) => { } Err(errors) => { self.report_fulfillment_errors(&errors); } } - - if let Err(ref errors) = fulfillment_cx.select_rfc1592_obligations(self) { - self.report_fulfillment_errors_as_warnings(errors, self.body_id); - } } /// Select as many obligations as we can at present. diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 30b9d1558706..f63e7b099476 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -477,7 +477,6 @@ impl<'tcx> GetTypeParameterBounds<'tcx> for ty::GenericPredicates<'tcx> { ty::Predicate::TypeOutlives(ref data) => { data.skip_binder().0.is_param(def.index) } - ty::Predicate::Rfc1592(..) | ty::Predicate::Equate(..) | ty::Predicate::RegionOutlives(..) | ty::Predicate::WellFormed(..) | diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 0af3973f78d2..e4b6a30d5bcb 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -858,7 +858,6 @@ impl<'a> Clean for ty::Predicate<'a> { Predicate::WellFormed(_) => panic!("not user writable"), Predicate::ObjectSafe(_) => panic!("not user writable"), Predicate::ClosureKind(..) => panic!("not user writable"), - Predicate::Rfc1592(..) => panic!("not user writable"), } } } diff --git a/src/test/compile-fail/bad-sized.rs b/src/test/compile-fail/bad-sized.rs index 8aaf75212569..e9d0b986c117 100644 --- a/src/test/compile-fail/bad-sized.rs +++ b/src/test/compile-fail/bad-sized.rs @@ -13,5 +13,7 @@ trait Trait {} pub fn main() { let x: Vec = Vec::new(); //~^ ERROR `Trait + Sized: std::marker::Sized` is not satisfied + //~| ERROR the trait `std::marker::Sized` cannot be made into an object //~| ERROR `Trait + Sized: std::marker::Sized` is not satisfied + //~| ERROR the trait `std::marker::Sized` cannot be made into an object } diff --git a/src/test/compile-fail/issue-32963.rs b/src/test/compile-fail/issue-32963.rs index c4e8f7661175..8ba95d14931e 100644 --- a/src/test/compile-fail/issue-32963.rs +++ b/src/test/compile-fail/issue-32963.rs @@ -17,4 +17,5 @@ fn size_of_copy() -> usize { mem::size_of::() } fn main() { size_of_copy::(); //~^ ERROR `Misc + Copy: std::marker::Copy` is not satisfied + //~| ERROR the trait `std::marker::Copy` cannot be made into an object } diff --git a/src/test/compile-fail/rfc1592-deprecated.rs b/src/test/compile-fail/rfc1592-deprecated.rs deleted file mode 100644 index e766f977200c..000000000000 --- a/src/test/compile-fail/rfc1592-deprecated.rs +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use std::fmt; - -#[deny(warnings)] trait Foo { fn foo(&self) -> (Self, Self); } -//~^ ERROR the trait bound `Self: std::marker::Sized` is not satisfied -//~| WARNING hard error - -impl Foo for T { - fn foo(&self) -> (Self, Self) { - (*self, *self) - } -} - -#[deny(warnings)] -fn main() { - assert_eq!((11).foo(), (11, 11)); - - let junk: Box = Box::new(42); - //~^ ERROR the trait cannot require that `Self : Sized` - //~| WARNING hard error - let f = format!("{:?}", junk); - assert_eq!(f, "42"); -} diff --git a/src/test/compile-fail/unsized6.rs b/src/test/compile-fail/unsized6.rs index d40c12f67a08..462d760a60ce 100644 --- a/src/test/compile-fail/unsized6.rs +++ b/src/test/compile-fail/unsized6.rs @@ -14,9 +14,9 @@ trait T {} fn f1(x: &X) { let _: X; // <-- this is OK, no bindings created, no initializer. - let _: (isize, (X, isize)); + let _: (isize, (X, isize)); //~ERROR `X: std::marker::Sized` is not satisfie let y: X; //~ERROR `X: std::marker::Sized` is not satisfied - let y: (isize, (X, usize)); //~ERROR `X: std::marker::Sized` is not satisfied + let y: (isize, (X, usize)); } fn f2(x: &X) { let y: X; //~ERROR `X: std::marker::Sized` is not satisfied diff --git a/src/test/run-pass/rfc1592-deprecated.rs b/src/test/run-pass/rfc1592-deprecated.rs deleted file mode 100644 index 81bf02587896..000000000000 --- a/src/test/run-pass/rfc1592-deprecated.rs +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use std::fmt; - -trait Foo { - fn foo(&self) -> (Self, Self); -} - -impl Foo for T { - fn foo(&self) -> (Self, Self) { - (*self, *self) - } -} - -fn main() { - assert_eq!((11).foo(), (11, 11)); - - let junk: Box = Box::new(42); - let f = format!("{:?}", junk); - assert_eq!(f, "42"); -} From 7d5fa9edc9b9784cbde3550826cc0f37aa6c1501 Mon Sep 17 00:00:00 2001 From: Mohit Agarwal Date: Thu, 1 Sep 2016 18:49:35 +0530 Subject: [PATCH 069/443] configure: check if any of the arguments contain --help Currently it checks only the first argument. Fixes #31216 --- configure | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/configure b/configure index 44fb3d368d2c..bcc1faea3b5d 100755 --- a/configure +++ b/configure @@ -360,6 +360,13 @@ abs_path() { (unset CDPATH && cd "$_path" > /dev/null && pwd) } +HELP=0 +for arg; do + case "$arg" in + --help) HELP=1;; + esac +done + msg "looking for configure programs" need_cmd cmp need_cmd mkdir @@ -566,11 +573,8 @@ esac OPTIONS="" -HELP=0 -if [ "$1" = "--help" ] +if [ "$HELP" -eq 1 ] then - HELP=1 - shift echo echo "Usage: $CFG_SELF [options]" echo From dd65cb223a3cd1a0fa8d98e9402f8725d606f6b2 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 23 Aug 2016 13:23:58 -0400 Subject: [PATCH 070/443] Add some infrastructure for timing things where time_passes can't be used. --- src/librustc/session/config.rs | 2 ++ src/librustc/session/mod.rs | 33 ++++++++++++++++++ src/librustc/util/common.rs | 35 ++++++++++++++----- src/librustc_driver/driver.rs | 4 +++ src/librustc_trans/back/symbol_names.rs | 45 +++++++++++++------------ 5 files changed, 89 insertions(+), 30 deletions(-) diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 562dce6a1b12..79e14212db42 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -908,6 +908,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "dump MIR state at various points in translation"), dump_mir_dir: Option = (None, parse_opt_string, [UNTRACKED], "the directory the MIR is dumped into"), + perf_stats: bool = (false, parse_bool, [UNTRACKED], + "print some performance-related statistics"), } pub fn default_lib_output() -> CrateType { diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 338c65637995..cc115cbeb85b 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -18,6 +18,7 @@ use session::search_paths::PathKind; use session::config::{DebugInfoLevel, PanicStrategy}; use ty::tls; use util::nodemap::{NodeMap, FnvHashMap}; +use util::common::duration_to_secs_str; use mir::transform as mir_pass; use syntax::ast::{NodeId, Name}; @@ -43,6 +44,7 @@ use std::env; use std::ffi::CString; use std::rc::Rc; use std::fmt; +use std::time::Duration; use libc::c_int; pub mod config; @@ -104,9 +106,23 @@ pub struct Session { incr_comp_session: RefCell, + /// Some measurements that are being gathered during compilation. + pub perf_stats: PerfStats, + next_node_id: Cell, } +pub struct PerfStats { + // The accumulated time needed for computing the SVH of the crate + pub svh_time: Cell, + // The accumulated time spent on computing incr. comp. hashes + pub incr_comp_hashes_time: Cell, + // The number of incr. comp. hash computations performed + pub incr_comp_hashes_count: Cell, + // The accumulated time spent on computing symbol hashes + pub symbol_hash_time: Cell, +} + impl Session { pub fn local_crate_disambiguator(&self) -> token::InternedString { self.crate_disambiguator.borrow().clone() @@ -404,6 +420,17 @@ impl Session { None } } + + pub fn print_perf_stats(&self) { + println!("Total time spent computing SVHs: {}", + duration_to_secs_str(self.perf_stats.svh_time.get())); + println!("Total time spent computing incr. comp. hashes: {}", + duration_to_secs_str(self.perf_stats.incr_comp_hashes_time.get())); + println!("Total number of incr. comp. hashes computed: {}", + self.perf_stats.incr_comp_hashes_count.get()); + println!("Total time spent computing symbol hashes: {}", + duration_to_secs_str(self.perf_stats.symbol_hash_time.get())); + } } pub fn build_session(sopts: config::Options, @@ -520,6 +547,12 @@ pub fn build_session_(sopts: config::Options, available_macros: RefCell::new(HashSet::new()), imported_macro_spans: RefCell::new(HashMap::new()), incr_comp_session: RefCell::new(IncrCompSession::NotInitialized), + perf_stats: PerfStats { + svh_time: Cell::new(Duration::from_secs(0)), + incr_comp_hashes_time: Cell::new(Duration::from_secs(0)), + incr_comp_hashes_count: Cell::new(0), + symbol_hash_time: Cell::new(Duration::from_secs(0)), + } }; init_llvm(&sess); diff --git a/src/librustc/util/common.rs b/src/librustc/util/common.rs index bdfb97549d5d..78f20b77f318 100644 --- a/src/librustc/util/common.rs +++ b/src/librustc/util/common.rs @@ -17,7 +17,7 @@ use std::fmt::Debug; use std::hash::{Hash, BuildHasher}; use std::iter::repeat; use std::path::Path; -use std::time::Instant; +use std::time::{Duration, Instant}; use hir; use hir::intravisit; @@ -47,12 +47,6 @@ pub fn time(do_it: bool, what: &str, f: F) -> T where let rv = f(); let dur = start.elapsed(); - // Hack up our own formatting for the duration to make it easier for scripts - // to parse (always use the same number of decimal places and the same unit). - const NANOS_PER_SEC: f64 = 1_000_000_000.0; - let secs = dur.as_secs() as f64; - let secs = secs + dur.subsec_nanos() as f64 / NANOS_PER_SEC; - let mem_string = match get_resident() { Some(n) => { let mb = n as f64 / 1_000_000.0; @@ -60,14 +54,37 @@ pub fn time(do_it: bool, what: &str, f: F) -> T where } None => "".to_owned(), }; - println!("{}time: {:.3}{}\t{}", repeat(" ").take(old).collect::(), - secs, mem_string, what); + println!("{}time: {}{}\t{}", + repeat(" ").take(old).collect::(), + duration_to_secs_str(dur), + mem_string, + what); DEPTH.with(|slot| slot.set(old)); rv } +// Hack up our own formatting for the duration to make it easier for scripts +// to parse (always use the same number of decimal places and the same unit). +pub fn duration_to_secs_str(dur: Duration) -> String { + const NANOS_PER_SEC: f64 = 1_000_000_000.0; + let secs = dur.as_secs() as f64 + + dur.subsec_nanos() as f64 / NANOS_PER_SEC; + + format!("{:.3}", secs) +} + +pub fn record_time(accu: &Cell, f: F) -> T where + F: FnOnce() -> T, +{ + let start = Instant::now(); + let rv = f(); + let duration = start.elapsed(); + accu.set(duration + accu.get()); + rv +} + // Like std::macros::try!, but for Option<>. macro_rules! option_try( ($e:expr) => (match $e { Some(e) => e, None => return None }) diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 94092be4922b..e8137430a064 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -233,6 +233,10 @@ pub fn compile_input(sess: &Session, // any more, we can finalize it (which involves renaming it) rustc_incremental::finalize_session_directory(sess, trans.link.crate_hash); + if sess.opts.debugging_opts.perf_stats { + sess.print_perf_stats(); + } + controller_entry_point!(compilation_done, sess, CompileState::state_when_compilation_done(input, sess, outdir, output), diff --git a/src/librustc_trans/back/symbol_names.rs b/src/librustc_trans/back/symbol_names.rs index 9b02cbe6721f..00f29b7412ed 100644 --- a/src/librustc_trans/back/symbol_names.rs +++ b/src/librustc_trans/back/symbol_names.rs @@ -108,6 +108,7 @@ use rustc::ty::{Ty, TyCtxt, TypeFoldable}; use rustc::ty::item_path::{self, ItemPathBuffer, RootMode}; use rustc::ty::subst::Substs; use rustc::hir::map::definitions::{DefPath, DefPathData}; +use rustc::util::common::record_time; use syntax::attr; use syntax::parse::token::{self, InternedString}; @@ -138,33 +139,35 @@ fn get_symbol_hash<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, let tcx = scx.tcx(); - let mut hash_state = scx.symbol_hasher().borrow_mut(); + return record_time(&tcx.sess.perf_stats.symbol_hash_time, || { + let mut hash_state = scx.symbol_hasher().borrow_mut(); - hash_state.reset(); + hash_state.reset(); - // the main symbol name is not necessarily unique; hash in the - // compiler's internal def-path, guaranteeing each symbol has a - // truly unique path - hash_state.input_str(&def_path.to_string(tcx)); + // the main symbol name is not necessarily unique; hash in the + // compiler's internal def-path, guaranteeing each symbol has a + // truly unique path + hash_state.input_str(&def_path.to_string(tcx)); - // Include the main item-type. Note that, in this case, the - // assertions about `needs_subst` may not hold, but this item-type - // ought to be the same for every reference anyway. - assert!(!item_type.has_erasable_regions()); - let encoded_item_type = tcx.sess.cstore.encode_type(tcx, item_type, def_id_to_string); - hash_state.input(&encoded_item_type[..]); + // Include the main item-type. Note that, in this case, the + // assertions about `needs_subst` may not hold, but this item-type + // ought to be the same for every reference anyway. + assert!(!item_type.has_erasable_regions()); + let encoded_item_type = tcx.sess.cstore.encode_type(tcx, item_type, def_id_to_string); + hash_state.input(&encoded_item_type[..]); - // also include any type parameters (for generic items) - if let Some(substs) = substs { - for t in substs.types() { - assert!(!t.has_erasable_regions()); - assert!(!t.needs_subst()); - let encoded_type = tcx.sess.cstore.encode_type(tcx, t, def_id_to_string); - hash_state.input(&encoded_type[..]); + // also include any type parameters (for generic items) + if let Some(substs) = substs { + for t in substs.types() { + assert!(!t.has_erasable_regions()); + assert!(!t.needs_subst()); + let encoded_type = tcx.sess.cstore.encode_type(tcx, t, def_id_to_string); + hash_state.input(&encoded_type[..]); + } } - } - return format!("h{}", truncated_hash_result(&mut *hash_state)); + format!("h{}", truncated_hash_result(&mut *hash_state)) + }); fn truncated_hash_result(symbol_hasher: &mut Sha256) -> String { let output = symbol_hasher.result_bytes(); From 8e4f4810dcc7cc21aec13d421d211a94f29e413f Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 23 Aug 2016 13:54:02 -0400 Subject: [PATCH 071/443] Fill some holes in SVH/ICH computation, making it more strict. --- src/librustc_incremental/calculate_svh/mod.rs | 34 +- .../calculate_svh/svh_visitor.rs | 321 +++++++++++++++--- src/librustc_incremental/lib.rs | 1 + 3 files changed, 291 insertions(+), 65 deletions(-) diff --git a/src/librustc_incremental/calculate_svh/mod.rs b/src/librustc_incremental/calculate_svh/mod.rs index b14c20ae8d46..6ad93d8f4733 100644 --- a/src/librustc_incremental/calculate_svh/mod.rs +++ b/src/librustc_incremental/calculate_svh/mod.rs @@ -35,6 +35,8 @@ use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId}; use rustc::hir::intravisit as visit; use rustc::ty::TyCtxt; use rustc_data_structures::fnv::FnvHashMap; +use rustc::util::common::record_time; +use rustc::session::config::DebugInfoLevel::NoDebugInfo; use self::def_path_hash::DefPathHashes; use self::svh_visitor::StrictVersionHashVisitor; @@ -48,12 +50,19 @@ pub fn compute_incremental_hashes_map<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> IncrementalHashesMap { let _ignore = tcx.dep_graph.in_ignore(); let krate = tcx.map.krate(); - let mut visitor = HashItemsVisitor { tcx: tcx, - hashes: FnvHashMap(), - def_path_hashes: DefPathHashes::new(tcx) }; - visitor.calculate_def_id(DefId::local(CRATE_DEF_INDEX), |v| visit::walk_crate(v, krate)); - krate.visit_all_items(&mut visitor); - visitor.compute_crate_hash(); + let hash_spans = tcx.sess.opts.debuginfo != NoDebugInfo; + let mut visitor = HashItemsVisitor { + tcx: tcx, + hashes: FnvHashMap(), + def_path_hashes: DefPathHashes::new(tcx), + hash_spans: hash_spans + }; + record_time(&tcx.sess.perf_stats.incr_comp_hashes_time, || { + visitor.calculate_def_id(DefId::local(CRATE_DEF_INDEX), + |v| visit::walk_crate(v, krate)); + krate.visit_all_items(&mut visitor); + }); + record_time(&tcx.sess.perf_stats.svh_time, || visitor.compute_crate_hash()); visitor.hashes } @@ -61,6 +70,7 @@ struct HashItemsVisitor<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, def_path_hashes: DefPathHashes<'a, 'tcx>, hashes: IncrementalHashesMap, + hash_spans: bool, } impl<'a, 'tcx> HashItemsVisitor<'a, 'tcx> { @@ -81,7 +91,8 @@ impl<'a, 'tcx> HashItemsVisitor<'a, 'tcx> { let mut state = SipHasher::new(); walk_op(&mut StrictVersionHashVisitor::new(&mut state, self.tcx, - &mut self.def_path_hashes)); + &mut self.def_path_hashes, + self.hash_spans)); let item_hash = state.finish(); self.hashes.insert(DepNode::Hir(def_id), item_hash); debug!("calculate_item_hash: def_id={:?} hash={:?}", def_id, item_hash); @@ -117,9 +128,12 @@ impl<'a, 'tcx> HashItemsVisitor<'a, 'tcx> { item_hashes.hash(&mut crate_state); } - for attr in &krate.attrs { - debug!("krate attr {:?}", attr); - attr.meta().hash(&mut crate_state); + { + let mut visitor = StrictVersionHashVisitor::new(&mut crate_state, + self.tcx, + &mut self.def_path_hashes, + self.hash_spans); + visitor.hash_attributes(&krate.attrs); } let crate_hash = crate_state.finish(); diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs index c1158dc2d5fe..de286d68fe98 100644 --- a/src/librustc_incremental/calculate_svh/svh_visitor.rs +++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs @@ -13,10 +13,9 @@ // hash computation, but for many kinds of items the order of // declaration should be irrelevant to the ABI. -pub use self::SawExprComponent::*; -pub use self::SawStmtComponent::*; +use self::SawExprComponent::*; use self::SawAbiComponent::*; -use syntax::ast::{self, Name, NodeId}; +use syntax::ast::{self, Name, NodeId, Attribute}; use syntax::parse::token; use syntax_pos::Span; use rustc::hir; @@ -24,7 +23,6 @@ use rustc::hir::*; use rustc::hir::def::{Def, PathResolution}; use rustc::hir::def_id::DefId; use rustc::hir::intravisit as visit; -use rustc::hir::intravisit::{Visitor, FnKind}; use rustc::ty::TyCtxt; use std::hash::{Hash, SipHasher}; @@ -34,22 +32,41 @@ use super::def_path_hash::DefPathHashes; pub struct StrictVersionHashVisitor<'a, 'hash: 'a, 'tcx: 'hash> { pub tcx: TyCtxt<'hash, 'tcx, 'tcx>, pub st: &'a mut SipHasher, - // collect a deterministic hash of def-ids that we have seen def_path_hashes: &'a mut DefPathHashes<'hash, 'tcx>, + hash_spans: bool, } impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> { pub fn new(st: &'a mut SipHasher, tcx: TyCtxt<'hash, 'tcx, 'tcx>, - def_path_hashes: &'a mut DefPathHashes<'hash, 'tcx>) + def_path_hashes: &'a mut DefPathHashes<'hash, 'tcx>, + hash_spans: bool) -> Self { - StrictVersionHashVisitor { st: st, tcx: tcx, def_path_hashes: def_path_hashes } + StrictVersionHashVisitor { + st: st, + tcx: tcx, + def_path_hashes: def_path_hashes, + hash_spans: hash_spans, + } } fn compute_def_id_hash(&mut self, def_id: DefId) -> u64 { self.def_path_hashes.hash(def_id) } + + #[inline] + fn hash_span(&mut self, span: Span) { + if self.hash_spans { + let _ = span; + } + } + + fn hash_discriminant(&mut self, v: &T) { + unsafe { + ::std::intrinsics::discriminant_value(&v).hash(self.st); + } + } } // To off-load the bulk of the hash-computation on #[derive(Hash)], @@ -80,26 +97,35 @@ enum SawAbiComponent<'a> { SawIdent(token::InternedString), SawStructDef(token::InternedString), - SawLifetime(token::InternedString), - SawLifetimeDef(token::InternedString), + SawLifetime, + SawLifetimeDef(usize), SawMod, SawForeignItem, SawItem, SawTy, SawGenerics, - SawFn, SawTraitItem, SawImplItem, SawStructField, SawVariant, - SawPath, + SawPath(bool), + SawPathSegment, + SawPathParameters, + SawPathListItem, SawBlock, SawPat, SawLocal, SawArm, SawExpr(SawExprComponent<'a>), - SawStmt(SawStmtComponent), + SawStmt, + SawVis, + SawWherePredicate, + SawTyParamBound, + SawPolyTraitRef, + SawAssocTypeBinding, + SawAttribute(ast::AttrStyle, bool), + SawMacroDef, } /// SawExprComponent carries all of the information that we want @@ -117,7 +143,7 @@ enum SawAbiComponent<'a> { /// guarantee of collision-freedom, hash collisions are just /// (hopefully) unlikely.) #[derive(Hash)] -pub enum SawExprComponent<'a> { +enum SawExprComponent<'a> { SawExprLoop(Option), SawExprField(token::InternedString), @@ -185,31 +211,39 @@ fn saw_expr<'a>(node: &'a Expr_) -> SawExprComponent<'a> { } } -/// SawStmtComponent is analogous to SawExprComponent, but for statements. -#[derive(Hash)] -pub enum SawStmtComponent { - SawStmtExpr, - SawStmtSemi, +macro_rules! hash_attrs { + ($visitor:expr, $attrs:expr) => ({ + let attrs = $attrs; + if attrs.len() > 0 { + $visitor.hash_attributes(attrs); + } + }) } -impl<'a, 'hash, 'tcx> Visitor<'tcx> for StrictVersionHashVisitor<'a, 'hash, 'tcx> { +impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'hash, 'tcx> { fn visit_nested_item(&mut self, _: ItemId) { // Each item is hashed independently; ignore nested items. } - fn visit_variant_data(&mut self, s: &'tcx VariantData, name: Name, - g: &'tcx Generics, _: NodeId, _: Span) { + fn visit_variant_data(&mut self, + s: &'tcx VariantData, + name: Name, + _: &'tcx Generics, + _: NodeId, + span: Span) { debug!("visit_variant_data: st={:?}", self.st); SawStructDef(name.as_str()).hash(self.st); - visit::walk_generics(self, g); - visit::walk_struct_def(self, s) + self.hash_span(span); + visit::walk_struct_def(self, s); } - fn visit_variant(&mut self, v: &'tcx Variant, g: &'tcx Generics, item_id: NodeId) { + fn visit_variant(&mut self, + v: &'tcx Variant, + g: &'tcx Generics, + item_id: NodeId) { debug!("visit_variant: st={:?}", self.st); SawVariant.hash(self.st); - // walk_variant does not call walk_generics, so do it here. - visit::walk_generics(self, g); + hash_attrs!(self, &v.node.attrs); visit::walk_variant(self, v, g, item_id) } @@ -227,19 +261,22 @@ impl<'a, 'hash, 'tcx> Visitor<'tcx> for StrictVersionHashVisitor<'a, 'hash, 'tcx // (If you edit a method such that it deviates from the // pattern, please move that method up above this comment.) - fn visit_name(&mut self, _: Span, name: Name) { + fn visit_name(&mut self, span: Span, name: Name) { debug!("visit_name: st={:?}", self.st); SawIdent(name.as_str()).hash(self.st); + self.hash_span(span); } fn visit_lifetime(&mut self, l: &'tcx Lifetime) { debug!("visit_lifetime: st={:?}", self.st); - SawLifetime(l.name.as_str()).hash(self.st); + SawLifetime.hash(self.st); + visit::walk_lifetime(self, l); } fn visit_lifetime_def(&mut self, l: &'tcx LifetimeDef) { debug!("visit_lifetime_def: st={:?}", self.st); - SawLifetimeDef(l.lifetime.name.as_str()).hash(self.st); + SawLifetimeDef(l.bounds.len()).hash(self.st); + visit::walk_lifetime_def(self, l); } // We do recursively walk the bodies of functions/methods @@ -249,7 +286,12 @@ impl<'a, 'hash, 'tcx> Visitor<'tcx> for StrictVersionHashVisitor<'a, 'hash, 'tcx // crates to be recompiled. fn visit_expr(&mut self, ex: &'tcx Expr) { debug!("visit_expr: st={:?}", self.st); - SawExpr(saw_expr(&ex.node)).hash(self.st); visit::walk_expr(self, ex) + SawExpr(saw_expr(&ex.node)).hash(self.st); + // No need to explicitly hash the discriminant here, since we are + // implicitly hashing the discriminant of SawExprComponent. + self.hash_span(ex.span); + hash_attrs!(self, &ex.attrs); + visit::walk_expr(self, ex) } fn visit_stmt(&mut self, s: &'tcx Stmt) { @@ -263,8 +305,16 @@ impl<'a, 'hash, 'tcx> Visitor<'tcx> for StrictVersionHashVisitor<'a, 'hash, 'tcx // rules). match s.node { StmtDecl(..) => (), - StmtExpr(..) => SawStmt(SawStmtExpr).hash(self.st), - StmtSemi(..) => SawStmt(SawStmtSemi).hash(self.st), + StmtExpr(..) => { + SawStmt.hash(self.st); + self.hash_discriminant(&s.node); + self.hash_span(s.span); + } + StmtSemi(..) => { + SawStmt.hash(self.st); + self.hash_discriminant(&s.node); + self.hash_span(s.span); + } } visit::walk_stmt(self, s) @@ -277,17 +327,21 @@ impl<'a, 'hash, 'tcx> Visitor<'tcx> for StrictVersionHashVisitor<'a, 'hash, 'tcx // perhaps reachability) somewhere here, so foreign items // that do not leak into downstream crates would not be // part of the ABI. - SawForeignItem.hash(self.st); visit::walk_foreign_item(self, i) + SawForeignItem.hash(self.st); + self.hash_span(i.span); + hash_attrs!(self, &i.attrs); + visit::walk_foreign_item(self, i) } fn visit_item(&mut self, i: &'tcx Item) { debug!("visit_item: {:?} st={:?}", i, self.st); - // FIXME (#14132) ideally would incorporate reachability - // analysis somewhere here, so items that never leak into - // downstream crates (e.g. via monomorphisation or - // inlining) would not be part of the ABI. - SawItem.hash(self.st); visit::walk_item(self, i) + SawItem.hash(self.st); + // Hash the value of the discriminant of the Item variant. + self.hash_discriminant(&i.node); + self.hash_span(i.span); + hash_attrs!(self, &i.attrs); + visit::walk_item(self, i) } fn visit_mod(&mut self, m: &'tcx Mod, _s: Span, n: NodeId) { @@ -297,63 +351,159 @@ impl<'a, 'hash, 'tcx> Visitor<'tcx> for StrictVersionHashVisitor<'a, 'hash, 'tcx fn visit_ty(&mut self, t: &'tcx Ty) { debug!("visit_ty: st={:?}", self.st); - SawTy.hash(self.st); visit::walk_ty(self, t) + SawTy.hash(self.st); + self.hash_span(t.span); + visit::walk_ty(self, t) } fn visit_generics(&mut self, g: &'tcx Generics) { debug!("visit_generics: st={:?}", self.st); - SawGenerics.hash(self.st); visit::walk_generics(self, g) - } - - fn visit_fn(&mut self, fk: FnKind<'tcx>, fd: &'tcx FnDecl, - b: &'tcx Block, s: Span, n: NodeId) { - debug!("visit_fn: st={:?}", self.st); - SawFn.hash(self.st); visit::walk_fn(self, fk, fd, b, s, n) + SawGenerics.hash(self.st); + // FIXME: nested stuff + visit::walk_generics(self, g) } fn visit_trait_item(&mut self, ti: &'tcx TraitItem) { debug!("visit_trait_item: st={:?}", self.st); - SawTraitItem.hash(self.st); visit::walk_trait_item(self, ti) + SawTraitItem.hash(self.st); + self.hash_discriminant(&ti.node); + self.hash_span(ti.span); + hash_attrs!(self, &ti.attrs); + visit::walk_trait_item(self, ti) } fn visit_impl_item(&mut self, ii: &'tcx ImplItem) { debug!("visit_impl_item: st={:?}", self.st); - SawImplItem.hash(self.st); visit::walk_impl_item(self, ii) + SawImplItem.hash(self.st); + self.hash_discriminant(&ii.node); + self.hash_span(ii.span); + hash_attrs!(self, &ii.attrs); + visit::walk_impl_item(self, ii) } fn visit_struct_field(&mut self, s: &'tcx StructField) { debug!("visit_struct_field: st={:?}", self.st); - SawStructField.hash(self.st); visit::walk_struct_field(self, s) + SawStructField.hash(self.st); + self.hash_span(s.span); + hash_attrs!(self, &s.attrs); + visit::walk_struct_field(self, s) } fn visit_path(&mut self, path: &'tcx Path, _: ast::NodeId) { debug!("visit_path: st={:?}", self.st); - SawPath.hash(self.st); visit::walk_path(self, path) + SawPath(path.global).hash(self.st); + self.hash_span(path.span); + visit::walk_path(self, path) } fn visit_block(&mut self, b: &'tcx Block) { debug!("visit_block: st={:?}", self.st); - SawBlock.hash(self.st); visit::walk_block(self, b) + SawBlock.hash(self.st); + self.hash_span(b.span); + visit::walk_block(self, b) } fn visit_pat(&mut self, p: &'tcx Pat) { debug!("visit_pat: st={:?}", self.st); - SawPat.hash(self.st); visit::walk_pat(self, p) + SawPat.hash(self.st); + self.hash_discriminant(&p.node); + self.hash_span(p.span); + visit::walk_pat(self, p) } fn visit_local(&mut self, l: &'tcx Local) { debug!("visit_local: st={:?}", self.st); - SawLocal.hash(self.st); visit::walk_local(self, l) + SawLocal.hash(self.st); + hash_attrs!(self, &l.attrs); + visit::walk_local(self, l) + // No need to hash span, we are hashing all component spans } fn visit_arm(&mut self, a: &'tcx Arm) { debug!("visit_arm: st={:?}", self.st); - SawArm.hash(self.st); visit::walk_arm(self, a) + SawArm.hash(self.st); + hash_attrs!(self, &a.attrs); + visit::walk_arm(self, a) } fn visit_id(&mut self, id: NodeId) { debug!("visit_id: id={} st={:?}", id, self.st); - self.hash_resolve(id); + self.hash_resolve(id) + } + + fn visit_vis(&mut self, v: &'tcx Visibility) { + debug!("visit_vis: st={:?}", self.st); + SawVis.hash(self.st); + self.hash_discriminant(&v); + visit::walk_vis(self, v) + } + + fn visit_where_predicate(&mut self, predicate: &'tcx WherePredicate) { + debug!("visit_where_predicate: st={:?}", self.st); + SawWherePredicate.hash(self.st); + self.hash_discriminant(predicate); + // Ignoring span. Any important nested components should be visited. + visit::walk_where_predicate(self, predicate) + } + + fn visit_ty_param_bound(&mut self, bounds: &'tcx TyParamBound) { + debug!("visit_ty_param_bound: st={:?}", self.st); + SawTyParamBound.hash(self.st); + self.hash_discriminant(bounds); + // The TraitBoundModifier in TraitTyParamBound will be hash in + // visit_poly_trait_ref() + visit::walk_ty_param_bound(self, bounds) + } + + fn visit_poly_trait_ref(&mut self, t: &'tcx PolyTraitRef, m: &'tcx TraitBoundModifier) { + debug!("visit_poly_trait_ref: st={:?}", self.st); + SawPolyTraitRef.hash(self.st); + m.hash(self.st); + visit::walk_poly_trait_ref(self, t, m) + } + + fn visit_path_list_item(&mut self, prefix: &'tcx Path, item: &'tcx PathListItem) { + debug!("visit_path_list_item: st={:?}", self.st); + SawPathListItem.hash(self.st); + self.hash_discriminant(&item.node); + self.hash_span(item.span); + visit::walk_path_list_item(self, prefix, item) + } + + fn visit_path_segment(&mut self, path_span: Span, path_segment: &'tcx PathSegment) { + debug!("visit_path_segment: st={:?}", self.st); + SawPathSegment.hash(self.st); + visit::walk_path_segment(self, path_span, path_segment) + } + + fn visit_path_parameters(&mut self, path_span: Span, path_parameters: &'tcx PathParameters) { + debug!("visit_path_parameters: st={:?}", self.st); + SawPathParameters.hash(self.st); + self.hash_discriminant(path_parameters); + visit::walk_path_parameters(self, path_span, path_parameters) + } + + fn visit_assoc_type_binding(&mut self, type_binding: &'tcx TypeBinding) { + debug!("visit_assoc_type_binding: st={:?}", self.st); + SawAssocTypeBinding.hash(self.st); + self.hash_span(type_binding.span); + visit::walk_assoc_type_binding(self, type_binding) + } + + fn visit_attribute(&mut self, _: &Attribute) { + // We explicitly do not use this method, since doing that would + // implicitly impose an order on the attributes being hashed, while we + // explicitly don't want their order to matter + } + + fn visit_macro_def(&mut self, macro_def: &'tcx MacroDef) { + debug!("visit_macro_def: st={:?}", self.st); + if macro_def.export { + SawMacroDef.hash(self.st); + hash_attrs!(self, ¯o_def.attrs); + visit::walk_macro_def(self, macro_def) + // FIXME: We should hash the body of the macro too. + } } } @@ -450,4 +600,65 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> { } } } + + fn hash_meta_item(&mut self, meta_item: &ast::MetaItem) { + // ignoring span information, it doesn't matter here + match meta_item.node { + ast::MetaItemKind::Word(ref s) => { + "Word".hash(self.st); + s.len().hash(self.st); + s.hash(self.st); + } + ast::MetaItemKind::NameValue(ref s, ref lit) => { + "NameValue".hash(self.st); + s.len().hash(self.st); + s.hash(self.st); + lit.node.hash(self.st); + } + ast::MetaItemKind::List(ref s, ref items) => { + "List".hash(self.st); + s.len().hash(self.st); + s.hash(self.st); + // Sort subitems so the hash does not depend on their order + let indices = self.indices_sorted_by(&items, |p| { + meta_item_sort_key(&*p) + }); + items.len().hash(self.st); + for (index, &item_index) in indices.iter().enumerate() { + index.hash(self.st); + self.hash_meta_item(&items[item_index]); + } + } + } + } + + pub fn hash_attributes(&mut self, attributes: &[Attribute]) { + let indices = self.indices_sorted_by(attributes, |attr| { + meta_item_sort_key(&attr.node.value) + }); + + for i in indices { + let attr = &attributes[i].node; + SawAttribute(attr.style, attr.is_sugared_doc).hash(self.st); + self.hash_meta_item(&*attr.value); + } + } + + fn indices_sorted_by(&mut self, items: &[T], get_key: F) -> Vec + where K: Ord, + F: Fn(&T) -> K + { + let mut indices = Vec::with_capacity(items.len()); + indices.extend(0 .. items.len()); + indices.sort_by_key(|index| get_key(&items[*index])); + indices + } +} + +fn meta_item_sort_key(item: &ast::MetaItem) -> token::InternedString { + match item.node { + ast::MetaItemKind::Word(ref s) | + ast::MetaItemKind::NameValue(ref s, _) | + ast::MetaItemKind::List(ref s, _) => s.clone() + } } diff --git a/src/librustc_incremental/lib.rs b/src/librustc_incremental/lib.rs index 511ba8ec19cc..feacfdc96731 100644 --- a/src/librustc_incremental/lib.rs +++ b/src/librustc_incremental/lib.rs @@ -23,6 +23,7 @@ #![feature(rustc_private)] #![feature(staged_api)] #![feature(rand)] +#![feature(core_intrinsics)] extern crate graphviz; extern crate rbml; From e355ec1c6a24f8a597a08809b9dad394498dc3dd Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Wed, 24 Aug 2016 17:06:31 -0400 Subject: [PATCH 072/443] incr.comp.: Add stable hashing of HIR spans to ICH. --- .../calculate_svh/svh_visitor.rs | 207 +++++++++++++----- src/libsyntax/codemap.rs | 24 +- src/libsyntax_pos/lib.rs | 64 ++++++ 3 files changed, 226 insertions(+), 69 deletions(-) diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs index de286d68fe98..554a0e0a97cd 100644 --- a/src/librustc_incremental/calculate_svh/svh_visitor.rs +++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs @@ -17,24 +17,99 @@ use self::SawExprComponent::*; use self::SawAbiComponent::*; use syntax::ast::{self, Name, NodeId, Attribute}; use syntax::parse::token; -use syntax_pos::Span; +use syntax::codemap::CodeMap; +use syntax_pos::{Span, NO_EXPANSION, COMMAND_LINE_EXPN, BytePos, FileMap}; use rustc::hir; use rustc::hir::*; use rustc::hir::def::{Def, PathResolution}; use rustc::hir::def_id::DefId; use rustc::hir::intravisit as visit; use rustc::ty::TyCtxt; - +use std::rc::Rc; use std::hash::{Hash, SipHasher}; use super::def_path_hash::DefPathHashes; +const IGNORED_ATTRIBUTES: &'static [&'static str] = &["cfg", + "rustc_clean", + "rustc_dirty"]; + pub struct StrictVersionHashVisitor<'a, 'hash: 'a, 'tcx: 'hash> { pub tcx: TyCtxt<'hash, 'tcx, 'tcx>, pub st: &'a mut SipHasher, // collect a deterministic hash of def-ids that we have seen def_path_hashes: &'a mut DefPathHashes<'hash, 'tcx>, hash_spans: bool, + codemap: CachedCodemapView<'tcx>, +} + +struct CachedCodemapView<'tcx> { + codemap: &'tcx CodeMap, + // Format: (line number, line-start, line_end, file) + line_cache: [(usize, BytePos, BytePos, Rc); 4], + eviction_index: usize, +} + +impl<'tcx> CachedCodemapView<'tcx> { + fn new<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> CachedCodemapView<'tcx> { + let codemap = tcx.sess.codemap(); + let first_file = codemap.files.borrow()[0].clone(); + + CachedCodemapView { + codemap: codemap, + line_cache: [(0, BytePos(0), BytePos(0), first_file.clone()), + (0, BytePos(0), BytePos(0), first_file.clone()), + (0, BytePos(0), BytePos(0), first_file.clone()), + (0, BytePos(0), BytePos(0), first_file.clone())], + eviction_index: 0, + } + } + + fn byte_pos_to_line_and_col(&mut self, + pos: BytePos) + -> (Rc, usize, BytePos) { + // Check if the position is in one of the cached lines + for &(line, start, end, ref file) in self.line_cache.iter() { + if pos >= start && pos < end { + return (file.clone(), line, pos - start); + } + } + + // Check whether we have a cached line in the correct file, so we can + // overwrite it without having to look up the file again. + for &mut (ref mut line, + ref mut start, + ref mut end, + ref file) in self.line_cache.iter_mut() { + if pos >= file.start_pos && pos < file.end_pos { + let line_index = file.lookup_line(pos).unwrap(); + let (line_start, line_end) = file.line_bounds(line_index); + + // Update the cache entry in place + *line = line_index + 1; + *start = line_start; + *end = line_end; + + return (file.clone(), line_index + 1, pos - line_start); + } + } + + // No cache hit ... + let file_index = self.codemap.lookup_filemap_idx(pos); + let file = self.codemap.files.borrow()[file_index].clone(); + let line_index = file.lookup_line(pos).unwrap(); + let (line_start, line_end) = file.line_bounds(line_index); + + // Just overwrite some cache entry. If we got this for, all of them + // point to the wrong file. + self.line_cache[self.eviction_index] = (line_index + 1, + line_start, + line_end, + file.clone()); + self.eviction_index = (self.eviction_index + 1) % self.line_cache.len(); + + return (file, line_index + 1, pos - line_start); + } } impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> { @@ -48,6 +123,7 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> { tcx: tcx, def_path_hashes: def_path_hashes, hash_spans: hash_spans, + codemap: CachedCodemapView::new(tcx), } } @@ -55,10 +131,46 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> { self.def_path_hashes.hash(def_id) } - #[inline] + // Hash a span in a stable way. If we would just hash the spans BytePos + // fields that would be similar hashing pointers since those or just offsets + // into the CodeMap. Instead, we hash the (file name, line, column) triple, + // which stays the same even if the containing FileMap has moved within the + // CodeMap. + // Also note that we are hashing byte offsets for the column, not unicode + // codepoint offsets. For the purpose of the hash that's sufficient. fn hash_span(&mut self, span: Span) { - if self.hash_spans { - let _ = span; + debug_assert!(self.hash_spans); + debug!("hash_span: st={:?}", self.st); + + // If this is not an empty or invalid span, we want to hash the last + // position that belongs to it, as opposed to hashing the first + // position past it. + let span_hi = if span.hi > span.lo { + // We might end up in the middle of a multibyte character here, + // but that's OK, since we are not trying to decode anything at + // this position. + span.hi - BytePos(1) + } else { + span.hi + }; + + let (file1, line1, col1) = self.codemap.byte_pos_to_line_and_col(span.lo); + let (file2, line2, col2) = self.codemap.byte_pos_to_line_and_col(span_hi); + + let expansion_kind = match span.expn_id { + NO_EXPANSION => SawSpanExpnKind::NoExpansion, + COMMAND_LINE_EXPN => SawSpanExpnKind::CommandLine, + _ => SawSpanExpnKind::SomeExpansion, + }; + + expansion_kind.hash(self.st); + + SawSpan(&file1.name[..], line1, col1, + &file2.name[..], line2, col2, + expansion_kind).hash(self.st); + + if expansion_kind == SawSpanExpnKind::SomeExpansion { + self.hash_span(self.codemap.codemap.source_callsite(span)); } } @@ -126,6 +238,7 @@ enum SawAbiComponent<'a> { SawAssocTypeBinding, SawAttribute(ast::AttrStyle, bool), SawMacroDef, + SawSpan(&'a str, usize, BytePos, &'a str, usize, BytePos, SawSpanExpnKind), } /// SawExprComponent carries all of the information that we want @@ -211,6 +324,13 @@ fn saw_expr<'a>(node: &'a Expr_) -> SawExprComponent<'a> { } } +#[derive(Clone, Copy, Hash, Eq, PartialEq)] +enum SawSpanExpnKind { + NoExpansion, + CommandLine, + SomeExpansion, +} + macro_rules! hash_attrs { ($visitor:expr, $attrs:expr) => ({ let attrs = $attrs; @@ -220,6 +340,14 @@ macro_rules! hash_attrs { }) } +macro_rules! hash_span { + ($visitor:expr, $span:expr) => ({ + if $visitor.hash_spans { + $visitor.hash_span($span); + } + }) +} + impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'hash, 'tcx> { fn visit_nested_item(&mut self, _: ItemId) { // Each item is hashed independently; ignore nested items. @@ -233,7 +361,7 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has span: Span) { debug!("visit_variant_data: st={:?}", self.st); SawStructDef(name.as_str()).hash(self.st); - self.hash_span(span); + hash_span!(self, span); visit::walk_struct_def(self, s); } @@ -247,24 +375,10 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has visit::walk_variant(self, v, g, item_id) } - // All of the remaining methods just record (in the hash - // SipHasher) that the visitor saw that particular variant - // (with its payload), and continue walking as the default - // visitor would. - // - // Some of the implementations have some notes as to how one - // might try to make their SVH computation less discerning - // (e.g. by incorporating reachability analysis). But - // currently all of their implementations are uniform and - // uninteresting. - // - // (If you edit a method such that it deviates from the - // pattern, please move that method up above this comment.) - fn visit_name(&mut self, span: Span, name: Name) { debug!("visit_name: st={:?}", self.st); SawIdent(name.as_str()).hash(self.st); - self.hash_span(span); + hash_span!(self, span); } fn visit_lifetime(&mut self, l: &'tcx Lifetime) { @@ -279,17 +393,12 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has visit::walk_lifetime_def(self, l); } - // We do recursively walk the bodies of functions/methods - // (rather than omitting their bodies from the hash) since - // monomorphization and cross-crate inlining generally implies - // that a change to a crate body will require downstream - // crates to be recompiled. fn visit_expr(&mut self, ex: &'tcx Expr) { debug!("visit_expr: st={:?}", self.st); SawExpr(saw_expr(&ex.node)).hash(self.st); // No need to explicitly hash the discriminant here, since we are // implicitly hashing the discriminant of SawExprComponent. - self.hash_span(ex.span); + hash_span!(self, ex.span); hash_attrs!(self, &ex.attrs); visit::walk_expr(self, ex) } @@ -308,12 +417,12 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has StmtExpr(..) => { SawStmt.hash(self.st); self.hash_discriminant(&s.node); - self.hash_span(s.span); + hash_span!(self, s.span); } StmtSemi(..) => { SawStmt.hash(self.st); self.hash_discriminant(&s.node); - self.hash_span(s.span); + hash_span!(self, s.span); } } @@ -323,12 +432,8 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has fn visit_foreign_item(&mut self, i: &'tcx ForeignItem) { debug!("visit_foreign_item: st={:?}", self.st); - // FIXME (#14132) ideally we would incorporate privacy (or - // perhaps reachability) somewhere here, so foreign items - // that do not leak into downstream crates would not be - // part of the ABI. SawForeignItem.hash(self.st); - self.hash_span(i.span); + hash_span!(self, i.span); hash_attrs!(self, &i.attrs); visit::walk_foreign_item(self, i) } @@ -339,7 +444,7 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has SawItem.hash(self.st); // Hash the value of the discriminant of the Item variant. self.hash_discriminant(&i.node); - self.hash_span(i.span); + hash_span!(self, i.span); hash_attrs!(self, &i.attrs); visit::walk_item(self, i) } @@ -352,7 +457,7 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has fn visit_ty(&mut self, t: &'tcx Ty) { debug!("visit_ty: st={:?}", self.st); SawTy.hash(self.st); - self.hash_span(t.span); + hash_span!(self, t.span); visit::walk_ty(self, t) } @@ -367,7 +472,7 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has debug!("visit_trait_item: st={:?}", self.st); SawTraitItem.hash(self.st); self.hash_discriminant(&ti.node); - self.hash_span(ti.span); + hash_span!(self, ti.span); hash_attrs!(self, &ti.attrs); visit::walk_trait_item(self, ti) } @@ -376,7 +481,7 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has debug!("visit_impl_item: st={:?}", self.st); SawImplItem.hash(self.st); self.hash_discriminant(&ii.node); - self.hash_span(ii.span); + hash_span!(self, ii.span); hash_attrs!(self, &ii.attrs); visit::walk_impl_item(self, ii) } @@ -384,7 +489,7 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has fn visit_struct_field(&mut self, s: &'tcx StructField) { debug!("visit_struct_field: st={:?}", self.st); SawStructField.hash(self.st); - self.hash_span(s.span); + hash_span!(self, s.span); hash_attrs!(self, &s.attrs); visit::walk_struct_field(self, s) } @@ -392,14 +497,14 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has fn visit_path(&mut self, path: &'tcx Path, _: ast::NodeId) { debug!("visit_path: st={:?}", self.st); SawPath(path.global).hash(self.st); - self.hash_span(path.span); + hash_span!(self, path.span); visit::walk_path(self, path) } fn visit_block(&mut self, b: &'tcx Block) { debug!("visit_block: st={:?}", self.st); SawBlock.hash(self.st); - self.hash_span(b.span); + hash_span!(self, b.span); visit::walk_block(self, b) } @@ -407,7 +512,7 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has debug!("visit_pat: st={:?}", self.st); SawPat.hash(self.st); self.hash_discriminant(&p.node); - self.hash_span(p.span); + hash_span!(self, p.span); visit::walk_pat(self, p) } @@ -466,7 +571,7 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has debug!("visit_path_list_item: st={:?}", self.st); SawPathListItem.hash(self.st); self.hash_discriminant(&item.node); - self.hash_span(item.span); + hash_span!(self, item.span); visit::walk_path_list_item(self, prefix, item) } @@ -486,7 +591,7 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has fn visit_assoc_type_binding(&mut self, type_binding: &'tcx TypeBinding) { debug!("visit_assoc_type_binding: st={:?}", self.st); SawAssocTypeBinding.hash(self.st); - self.hash_span(type_binding.span); + hash_span!(self, type_binding.span); visit::walk_assoc_type_binding(self, type_binding) } @@ -602,21 +707,21 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> { } fn hash_meta_item(&mut self, meta_item: &ast::MetaItem) { + debug!("hash_meta_item: st={:?}", self.st); + // ignoring span information, it doesn't matter here + self.hash_discriminant(&meta_item.node); match meta_item.node { ast::MetaItemKind::Word(ref s) => { - "Word".hash(self.st); s.len().hash(self.st); s.hash(self.st); } ast::MetaItemKind::NameValue(ref s, ref lit) => { - "NameValue".hash(self.st); s.len().hash(self.st); s.hash(self.st); lit.node.hash(self.st); } ast::MetaItemKind::List(ref s, ref items) => { - "List".hash(self.st); s.len().hash(self.st); s.hash(self.st); // Sort subitems so the hash does not depend on their order @@ -633,14 +738,18 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> { } pub fn hash_attributes(&mut self, attributes: &[Attribute]) { + debug!("hash_attributes: st={:?}", self.st); let indices = self.indices_sorted_by(attributes, |attr| { meta_item_sort_key(&attr.node.value) }); for i in indices { let attr = &attributes[i].node; - SawAttribute(attr.style, attr.is_sugared_doc).hash(self.st); - self.hash_meta_item(&*attr.value); + + if !IGNORED_ATTRIBUTES.contains(&&*meta_item_sort_key(&attr.value)) { + SawAttribute(attr.style, attr.is_sugared_doc).hash(self.st); + self.hash_meta_item(&*attr.value); + } } } diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index b176b8fefc61..cd6f2874954b 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -348,26 +348,10 @@ impl CodeMap { let files = self.files.borrow(); let f = (*files)[idx].clone(); - let len = f.lines.borrow().len(); - if len == 0 { - return Err(f); + match f.lookup_line(pos) { + Some(line) => Ok(FileMapAndLine { fm: f, line: line }), + None => Err(f) } - - let mut a = 0; - { - let lines = f.lines.borrow(); - let mut b = lines.len(); - while b - a > 1 { - let m = (a + b) / 2; - if (*lines)[m] > pos { - b = m; - } else { - a = m; - } - } - assert!(a <= lines.len()); - } - Ok(FileMapAndLine { fm: f, line: a }) } pub fn lookup_char_pos_adj(&self, pos: BytePos) -> LocWithOpt { @@ -691,7 +675,7 @@ impl CodeMap { } // Return the index of the filemap (in self.files) which contains pos. - fn lookup_filemap_idx(&self, pos: BytePos) -> usize { + pub fn lookup_filemap_idx(&self, pos: BytePos) -> usize { let files = self.files.borrow(); let files = &*files; let count = files.len(); diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index b11bbea84abc..d835f8058fa0 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -507,6 +507,39 @@ impl FileMap { pub fn count_lines(&self) -> usize { self.lines.borrow().len() } + + /// Find the line containing the given position. The return value is the + /// index into the `lines` array of this FileMap, not the 1-based line + /// number. If the filemap is empty or the position is located before the + /// first line, None is returned. + pub fn lookup_line(&self, pos: BytePos) -> Option { + let lines = self.lines.borrow(); + if lines.len() == 0 { + return None; + } + + let line_index = lookup_line(&lines[..], pos); + assert!(line_index < lines.len() as isize); + if line_index >= 0 { + Some(line_index as usize) + } else { + None + } + } + + pub fn line_bounds(&self, line_index: usize) -> (BytePos, BytePos) { + if self.start_pos == self.end_pos { + return (self.start_pos, self.end_pos); + } + + let lines = self.lines.borrow(); + assert!(line_index < lines.len()); + if line_index == (lines.len() - 1) { + (lines[line_index], self.end_pos) + } else { + (lines[line_index], lines[line_index + 1]) + } + } } // _____________________________________________________________________________ @@ -688,3 +721,34 @@ pub struct MalformedCodemapPositions { pub end_pos: BytePos } +// Given a slice of line start positions and a position, returns the index of +// the line the position is on. Returns -1 if the position is located before +// the first line. +fn lookup_line(lines: &[BytePos], pos: BytePos) -> isize { + match lines.binary_search(&pos) { + Ok(line) => line as isize, + Err(line) => line as isize - 1 + } +} + +#[cfg(test)] +mod tests { + use super::{lookup_line, BytePos}; + + #[test] + fn test_lookup_line() { + + let lines = &[BytePos(3), BytePos(17), BytePos(28)]; + + assert_eq!(lookup_line(lines, BytePos(0)), -1); + assert_eq!(lookup_line(lines, BytePos(3)), 0); + assert_eq!(lookup_line(lines, BytePos(4)), 0); + + assert_eq!(lookup_line(lines, BytePos(16)), 0); + assert_eq!(lookup_line(lines, BytePos(17)), 1); + assert_eq!(lookup_line(lines, BytePos(18)), 1); + + assert_eq!(lookup_line(lines, BytePos(28)), 2); + assert_eq!(lookup_line(lines, BytePos(29)), 2); + } +} From 8b67ad69a7fb943d79d74b588057b5071c406060 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Fri, 26 Aug 2016 16:31:02 -0400 Subject: [PATCH 073/443] incr.comp. Add tests for stable span hashing. --- src/test/incremental/source_loc_macros.rs | 63 +++++++++++++++++++ .../span_hash_stable/auxiliary/mod.rs | 17 +++++ .../span_hash_stable/auxiliary/sub1.rs | 15 +++++ .../span_hash_stable/auxiliary/sub2.rs | 15 +++++ src/test/incremental/span_hash_stable/main.rs | 34 ++++++++++ .../spans_insignificant_w_o_debuginfo.rs | 25 ++++++++ .../spans_significant_w_debuginfo.rs | 25 ++++++++ 7 files changed, 194 insertions(+) create mode 100644 src/test/incremental/source_loc_macros.rs create mode 100644 src/test/incremental/span_hash_stable/auxiliary/mod.rs create mode 100644 src/test/incremental/span_hash_stable/auxiliary/sub1.rs create mode 100644 src/test/incremental/span_hash_stable/auxiliary/sub2.rs create mode 100644 src/test/incremental/span_hash_stable/main.rs create mode 100644 src/test/incremental/spans_insignificant_w_o_debuginfo.rs create mode 100644 src/test/incremental/spans_significant_w_debuginfo.rs diff --git a/src/test/incremental/source_loc_macros.rs b/src/test/incremental/source_loc_macros.rs new file mode 100644 index 000000000000..f922ac0da41b --- /dev/null +++ b/src/test/incremental/source_loc_macros.rs @@ -0,0 +1,63 @@ +// 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. + +// This test makes sure that different expansions of the file!(), line!(), +// column!() macros get picked up by the incr. comp. hash. + +// revisions:rpass1 rpass2 + +// compile-flags: -Z query-dep-graph + +#![feature(rustc_attrs)] + +#[rustc_clean(label="Hir", cfg="rpass2")] +fn line_same() { + let _ = line!(); +} + +#[rustc_clean(label="Hir", cfg="rpass2")] +fn col_same() { + let _ = column!(); +} + +#[rustc_clean(label="Hir", cfg="rpass2")] +fn file_same() { + let _ = file!(); +} + +#[cfg(rpass1)] +fn line_different() { + let _ = line!(); +} + +#[cfg(rpass2)] +#[rustc_dirty(label="Hir", cfg="rpass2")] +fn line_different() { + let _ = line!(); +} + +#[cfg(rpass1)] +fn col_different() { + let _ = column!(); +} + +#[cfg(rpass2)] +#[rustc_dirty(label="Hir", cfg="rpass2")] +fn col_different() { + let _ = column!(); +} + +fn main() { + line_same(); + line_different(); + col_same(); + col_different(); + file_same(); +} diff --git a/src/test/incremental/span_hash_stable/auxiliary/mod.rs b/src/test/incremental/span_hash_stable/auxiliary/mod.rs new file mode 100644 index 000000000000..dfd2a6610f25 --- /dev/null +++ b/src/test/incremental/span_hash_stable/auxiliary/mod.rs @@ -0,0 +1,17 @@ +// 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. + +#[cfg(rpass1)] +pub mod sub2; + +pub mod sub1; + +#[cfg(rpass2)] +pub mod sub2; diff --git a/src/test/incremental/span_hash_stable/auxiliary/sub1.rs b/src/test/incremental/span_hash_stable/auxiliary/sub1.rs new file mode 100644 index 000000000000..2d042c316833 --- /dev/null +++ b/src/test/incremental/span_hash_stable/auxiliary/sub1.rs @@ -0,0 +1,15 @@ +// 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. + +#[rustc_clean(label="Hir", cfg="rpass2")] +pub struct SomeType { + pub x: u32, + pub y: i64, +} diff --git a/src/test/incremental/span_hash_stable/auxiliary/sub2.rs b/src/test/incremental/span_hash_stable/auxiliary/sub2.rs new file mode 100644 index 000000000000..df7d2f0267d0 --- /dev/null +++ b/src/test/incremental/span_hash_stable/auxiliary/sub2.rs @@ -0,0 +1,15 @@ +// 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. + +#[rustc_clean(label="Hir", cfg="rpass2")] +pub struct SomeOtherType { + pub a: i32, + pub b: u64, +} diff --git a/src/test/incremental/span_hash_stable/main.rs b/src/test/incremental/span_hash_stable/main.rs new file mode 100644 index 000000000000..1512c5dc5378 --- /dev/null +++ b/src/test/incremental/span_hash_stable/main.rs @@ -0,0 +1,34 @@ +// 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. + +// This test makes sure that it doesn't make a difference in which order we are +// adding source files to the codemap. The order affects the BytePos values of +// the spans and this test makes sure that we handle them correctly by hashing +// file:line:column instead of raw byte offset. + +// revisions:rpass1 rpass2 +// compile-flags: -g -Z query-dep-graph + +#![feature(rustc_attrs)] + +mod auxiliary; + +fn main() { + let _ = auxiliary::sub1::SomeType { + x: 0, + y: 1, + }; + + let _ = auxiliary::sub2::SomeOtherType { + a: 2, + b: 3, + }; +} + diff --git a/src/test/incremental/spans_insignificant_w_o_debuginfo.rs b/src/test/incremental/spans_insignificant_w_o_debuginfo.rs new file mode 100644 index 000000000000..9c8b8552498c --- /dev/null +++ b/src/test/incremental/spans_insignificant_w_o_debuginfo.rs @@ -0,0 +1,25 @@ +// 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. + +// This test makes sure that just changing a definition's location in the +// source file does *not* change its incr. comp. hash, if debuginfo is disabled. + +// revisions:rpass1 rpass2 + +// compile-flags: -Z query-dep-graph + +#![feature(rustc_attrs)] + +#[cfg(rpass1)] +pub fn main() {} + +#[cfg(rpass2)] +#[rustc_clean(label="Hir", cfg="rpass2")] +pub fn main() {} diff --git a/src/test/incremental/spans_significant_w_debuginfo.rs b/src/test/incremental/spans_significant_w_debuginfo.rs new file mode 100644 index 000000000000..b0920aa1fa51 --- /dev/null +++ b/src/test/incremental/spans_significant_w_debuginfo.rs @@ -0,0 +1,25 @@ +// 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. + +// This test makes sure that just changing a definition's location in the +// source file also changes its incr. comp. hash, if debuginfo is enabled. + +// revisions:rpass1 rpass2 + +// compile-flags: -g -Z query-dep-graph + +#![feature(rustc_attrs)] + +#[cfg(rpass1)] +pub fn main() {} + +#[cfg(rpass2)] +#[rustc_dirty(label="Hir", cfg="rpass2")] +pub fn main() {} From 1cfd7c36542bfbd68a9808a6fc295e1ffe98a749 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Fri, 26 Aug 2016 18:29:13 -0400 Subject: [PATCH 074/443] incr.comp.: Ignore doc-comments when computing the ICH. --- src/librustc_incremental/calculate_svh/svh_visitor.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs index 554a0e0a97cd..7bc4d0ac4633 100644 --- a/src/librustc_incremental/calculate_svh/svh_visitor.rs +++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs @@ -236,7 +236,7 @@ enum SawAbiComponent<'a> { SawTyParamBound, SawPolyTraitRef, SawAssocTypeBinding, - SawAttribute(ast::AttrStyle, bool), + SawAttribute(ast::AttrStyle), SawMacroDef, SawSpan(&'a str, usize, BytePos, &'a str, usize, BytePos, SawSpanExpnKind), } @@ -746,8 +746,9 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> { for i in indices { let attr = &attributes[i].node; - if !IGNORED_ATTRIBUTES.contains(&&*meta_item_sort_key(&attr.value)) { - SawAttribute(attr.style, attr.is_sugared_doc).hash(self.st); + if !attr.is_sugared_doc && + !IGNORED_ATTRIBUTES.contains(&&*meta_item_sort_key(&attr.value)) { + SawAttribute(attr.style).hash(self.st); self.hash_meta_item(&*attr.value); } } From 5dd36bd48630e925ec617e40db8d23b593814cef Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Mon, 29 Aug 2016 15:28:53 -0400 Subject: [PATCH 075/443] Rename CacheCodemapView to CachingCodemapView. --- .../calculate_svh/svh_visitor.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs index 7bc4d0ac4633..84f4ac4b7457 100644 --- a/src/librustc_incremental/calculate_svh/svh_visitor.rs +++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs @@ -40,22 +40,22 @@ pub struct StrictVersionHashVisitor<'a, 'hash: 'a, 'tcx: 'hash> { // collect a deterministic hash of def-ids that we have seen def_path_hashes: &'a mut DefPathHashes<'hash, 'tcx>, hash_spans: bool, - codemap: CachedCodemapView<'tcx>, + codemap: CachingCodemapView<'tcx>, } -struct CachedCodemapView<'tcx> { +struct CachingCodemapView<'tcx> { codemap: &'tcx CodeMap, // Format: (line number, line-start, line_end, file) line_cache: [(usize, BytePos, BytePos, Rc); 4], eviction_index: usize, } -impl<'tcx> CachedCodemapView<'tcx> { - fn new<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> CachedCodemapView<'tcx> { +impl<'tcx> CachingCodemapView<'tcx> { + fn new<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> CachingCodemapView<'tcx> { let codemap = tcx.sess.codemap(); let first_file = codemap.files.borrow()[0].clone(); - CachedCodemapView { + CachingCodemapView { codemap: codemap, line_cache: [(0, BytePos(0), BytePos(0), first_file.clone()), (0, BytePos(0), BytePos(0), first_file.clone()), @@ -123,7 +123,7 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> { tcx: tcx, def_path_hashes: def_path_hashes, hash_spans: hash_spans, - codemap: CachedCodemapView::new(tcx), + codemap: CachingCodemapView::new(tcx), } } From 6785256557d6a4c21d53806637042871babc7302 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Mon, 29 Aug 2016 15:29:50 -0400 Subject: [PATCH 076/443] ICH: Don't hash span expansion kind twice. --- src/librustc_incremental/calculate_svh/svh_visitor.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs index 84f4ac4b7457..db062d6dca96 100644 --- a/src/librustc_incremental/calculate_svh/svh_visitor.rs +++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs @@ -163,8 +163,6 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> { _ => SawSpanExpnKind::SomeExpansion, }; - expansion_kind.hash(self.st); - SawSpan(&file1.name[..], line1, col1, &file2.name[..], line2, col2, expansion_kind).hash(self.st); From 500ab357c263eaa8ae55ed1323daa946def5b7b6 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Mon, 29 Aug 2016 15:47:44 -0400 Subject: [PATCH 077/443] ICH: Cleanup some comments. --- .../calculate_svh/svh_visitor.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs index db062d6dca96..702eed9d96fc 100644 --- a/src/librustc_incremental/calculate_svh/svh_visitor.rs +++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs @@ -45,7 +45,7 @@ pub struct StrictVersionHashVisitor<'a, 'hash: 'a, 'tcx: 'hash> { struct CachingCodemapView<'tcx> { codemap: &'tcx CodeMap, - // Format: (line number, line-start, line_end, file) + // Format: (line number, line-start, line-end, file) line_cache: [(usize, BytePos, BytePos, Rc); 4], eviction_index: usize, } @@ -100,7 +100,7 @@ impl<'tcx> CachingCodemapView<'tcx> { let line_index = file.lookup_line(pos).unwrap(); let (line_start, line_end) = file.line_bounds(line_index); - // Just overwrite some cache entry. If we got this for, all of them + // Just overwrite some cache entry. If we got this far, all of them // point to the wrong file. self.line_cache[self.eviction_index] = (line_index + 1, line_start, @@ -131,11 +131,11 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> { self.def_path_hashes.hash(def_id) } - // Hash a span in a stable way. If we would just hash the spans BytePos - // fields that would be similar hashing pointers since those or just offsets - // into the CodeMap. Instead, we hash the (file name, line, column) triple, - // which stays the same even if the containing FileMap has moved within the - // CodeMap. + // Hash a span in a stable way. We can't directly hash the span's BytePos + // fields (that would be similar to hashing pointers, since those are just + // offsets into the CodeMap). Instead, we hash the (file name, line, column) + // triple, which stays the same even if the containing FileMap has moved + // within the CodeMap. // Also note that we are hashing byte offsets for the column, not unicode // codepoint offsets. For the purpose of the hash that's sufficient. fn hash_span(&mut self, span: Span) { @@ -462,7 +462,6 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has fn visit_generics(&mut self, g: &'tcx Generics) { debug!("visit_generics: st={:?}", self.st); SawGenerics.hash(self.st); - // FIXME: nested stuff visit::walk_generics(self, g) } @@ -605,7 +604,8 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has SawMacroDef.hash(self.st); hash_attrs!(self, ¯o_def.attrs); visit::walk_macro_def(self, macro_def) - // FIXME: We should hash the body of the macro too. + // FIXME(mw): We should hash the body of the macro too but we don't + // have a stable way of doing so yet. } } } From 0310e3444b6b24da1b542b7c6b2999a1220259c0 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Mon, 29 Aug 2016 16:45:34 -0400 Subject: [PATCH 078/443] ICH: Take CaptureClause of closure expressions into account. --- src/librustc_incremental/calculate_svh/svh_visitor.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs index 702eed9d96fc..23fb211d7c7e 100644 --- a/src/librustc_incremental/calculate_svh/svh_visitor.rs +++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs @@ -275,7 +275,7 @@ enum SawExprComponent<'a> { SawExprIf, SawExprWhile, SawExprMatch, - SawExprClosure, + SawExprClosure(CaptureClause), SawExprBlock, SawExprAssign, SawExprAssignOp(hir::BinOp_), @@ -304,7 +304,7 @@ fn saw_expr<'a>(node: &'a Expr_) -> SawExprComponent<'a> { ExprWhile(..) => SawExprWhile, ExprLoop(_, id) => SawExprLoop(id.map(|id| id.node.as_str())), ExprMatch(..) => SawExprMatch, - ExprClosure(..) => SawExprClosure, + ExprClosure(cc, _, _, _) => SawExprClosure(cc), ExprBlock(..) => SawExprBlock, ExprAssign(..) => SawExprAssign, ExprAssignOp(op, _, _) => SawExprAssignOp(op.node), From a142d2ff025466a69662854255c959f60a31fd8c Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 30 Aug 2016 12:11:43 -0400 Subject: [PATCH 079/443] ICH: Fix bug in hash_discriminant() and visit_vis(). --- src/librustc_incremental/calculate_svh/svh_visitor.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs index 23fb211d7c7e..edfde33b3a15 100644 --- a/src/librustc_incremental/calculate_svh/svh_visitor.rs +++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs @@ -174,7 +174,9 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> { fn hash_discriminant(&mut self, v: &T) { unsafe { - ::std::intrinsics::discriminant_value(&v).hash(self.st); + let disr = ::std::intrinsics::discriminant_value(v); + debug!("hash_discriminant: disr={}, st={:?}", disr, self.st); + disr.hash(self.st); } } } @@ -536,7 +538,7 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has fn visit_vis(&mut self, v: &'tcx Visibility) { debug!("visit_vis: st={:?}", self.st); SawVis.hash(self.st); - self.hash_discriminant(&v); + self.hash_discriminant(v); visit::walk_vis(self, v) } From 2faca22bd31b0deeb38f35dc8d0916fb6ace95c2 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Wed, 31 Aug 2016 16:29:04 -0400 Subject: [PATCH 080/443] ICH: Fix codemap lookup caching. --- .../calculate_svh/svh_visitor.rs | 94 ++++++++++--------- 1 file changed, 52 insertions(+), 42 deletions(-) diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs index edfde33b3a15..e871dd5bcbff 100644 --- a/src/librustc_incremental/calculate_svh/svh_visitor.rs +++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs @@ -43,72 +43,82 @@ pub struct StrictVersionHashVisitor<'a, 'hash: 'a, 'tcx: 'hash> { codemap: CachingCodemapView<'tcx>, } +#[derive(Clone)] +struct CacheEntry { + time_stamp: usize, + line_number: usize, + line_start: BytePos, + line_end: BytePos, + file: Rc, +} + struct CachingCodemapView<'tcx> { codemap: &'tcx CodeMap, - // Format: (line number, line-start, line-end, file) - line_cache: [(usize, BytePos, BytePos, Rc); 4], - eviction_index: usize, + line_cache: [CacheEntry; 3], + time_stamp: usize, } impl<'tcx> CachingCodemapView<'tcx> { fn new<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> CachingCodemapView<'tcx> { let codemap = tcx.sess.codemap(); let first_file = codemap.files.borrow()[0].clone(); + let entry = CacheEntry { + time_stamp: 0, + line_number: 0, + line_start: BytePos(0), + line_end: BytePos(0), + file: first_file, + }; CachingCodemapView { codemap: codemap, - line_cache: [(0, BytePos(0), BytePos(0), first_file.clone()), - (0, BytePos(0), BytePos(0), first_file.clone()), - (0, BytePos(0), BytePos(0), first_file.clone()), - (0, BytePos(0), BytePos(0), first_file.clone())], - eviction_index: 0, + line_cache: [entry.clone(), entry.clone(), entry.clone()], + time_stamp: 0, } } fn byte_pos_to_line_and_col(&mut self, pos: BytePos) -> (Rc, usize, BytePos) { + self.time_stamp += 1; + // Check if the position is in one of the cached lines - for &(line, start, end, ref file) in self.line_cache.iter() { - if pos >= start && pos < end { - return (file.clone(), line, pos - start); - } - } - - // Check whether we have a cached line in the correct file, so we can - // overwrite it without having to look up the file again. - for &mut (ref mut line, - ref mut start, - ref mut end, - ref file) in self.line_cache.iter_mut() { - if pos >= file.start_pos && pos < file.end_pos { - let line_index = file.lookup_line(pos).unwrap(); - let (line_start, line_end) = file.line_bounds(line_index); - - // Update the cache entry in place - *line = line_index + 1; - *start = line_start; - *end = line_end; - - return (file.clone(), line_index + 1, pos - line_start); + for cache_entry in self.line_cache.iter_mut() { + if pos >= cache_entry.line_start && pos < cache_entry.line_end { + cache_entry.time_stamp = self.time_stamp; + return (cache_entry.file.clone(), + cache_entry.line_number, + pos - cache_entry.line_start); } } // No cache hit ... - let file_index = self.codemap.lookup_filemap_idx(pos); - let file = self.codemap.files.borrow()[file_index].clone(); - let line_index = file.lookup_line(pos).unwrap(); - let (line_start, line_end) = file.line_bounds(line_index); + let mut oldest = 0; + for index in 1 .. self.line_cache.len() { + if self.line_cache[index].time_stamp < self.line_cache[oldest].time_stamp { + oldest = index; + } + } - // Just overwrite some cache entry. If we got this far, all of them - // point to the wrong file. - self.line_cache[self.eviction_index] = (line_index + 1, - line_start, - line_end, - file.clone()); - self.eviction_index = (self.eviction_index + 1) % self.line_cache.len(); + let cache_entry = &mut self.line_cache[oldest]; - return (file, line_index + 1, pos - line_start); + // If the entry doesn't point to the correct file, fix it up + if pos < cache_entry.file.start_pos || pos >= cache_entry.file.end_pos { + let file_index = self.codemap.lookup_filemap_idx(pos); + cache_entry.file = self.codemap.files.borrow()[file_index].clone(); + } + + let line_index = cache_entry.file.lookup_line(pos).unwrap(); + let line_bounds = cache_entry.file.line_bounds(line_index); + + cache_entry.line_number = line_index + 1; + cache_entry.line_start = line_bounds.0; + cache_entry.line_end = line_bounds.1; + cache_entry.time_stamp = self.time_stamp; + + return (cache_entry.file.clone(), + cache_entry.line_number, + pos - cache_entry.line_start); } } From 8cbd6fe33155fde25146d2cf03aa26e450086106 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Wed, 31 Aug 2016 16:51:24 -0400 Subject: [PATCH 081/443] ICH: Share codemap cache between subsequent runs of the ICH visitor. --- .../calculate_svh/caching_codemap_view.rs | 97 +++++++++++++++++++ src/librustc_incremental/calculate_svh/mod.rs | 8 +- .../calculate_svh/svh_visitor.rs | 92 ++---------------- 3 files changed, 111 insertions(+), 86 deletions(-) create mode 100644 src/librustc_incremental/calculate_svh/caching_codemap_view.rs diff --git a/src/librustc_incremental/calculate_svh/caching_codemap_view.rs b/src/librustc_incremental/calculate_svh/caching_codemap_view.rs new file mode 100644 index 000000000000..32aa5a427287 --- /dev/null +++ b/src/librustc_incremental/calculate_svh/caching_codemap_view.rs @@ -0,0 +1,97 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use rustc::ty::TyCtxt; +use std::rc::Rc; +use syntax::codemap::CodeMap; +use syntax_pos::{BytePos, FileMap}; + +#[derive(Clone)] +struct CacheEntry { + time_stamp: usize, + line_number: usize, + line_start: BytePos, + line_end: BytePos, + file: Rc, +} + +pub struct CachingCodemapView<'tcx> { + codemap: &'tcx CodeMap, + line_cache: [CacheEntry; 3], + time_stamp: usize, +} + +impl<'tcx> CachingCodemapView<'tcx> { + pub fn new<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> CachingCodemapView<'tcx> { + let codemap = tcx.sess.codemap(); + let first_file = codemap.files.borrow()[0].clone(); + let entry = CacheEntry { + time_stamp: 0, + line_number: 0, + line_start: BytePos(0), + line_end: BytePos(0), + file: first_file, + }; + + CachingCodemapView { + codemap: codemap, + line_cache: [entry.clone(), entry.clone(), entry.clone()], + time_stamp: 0, + } + } + + pub fn codemap(&self) -> &'tcx CodeMap { + self.codemap + } + + pub fn byte_pos_to_line_and_col(&mut self, + pos: BytePos) + -> (Rc, usize, BytePos) { + self.time_stamp += 1; + + // Check if the position is in one of the cached lines + for cache_entry in self.line_cache.iter_mut() { + if pos >= cache_entry.line_start && pos < cache_entry.line_end { + cache_entry.time_stamp = self.time_stamp; + return (cache_entry.file.clone(), + cache_entry.line_number, + pos - cache_entry.line_start); + } + } + + // No cache hit ... + let mut oldest = 0; + for index in 1 .. self.line_cache.len() { + if self.line_cache[index].time_stamp < self.line_cache[oldest].time_stamp { + oldest = index; + } + } + + let cache_entry = &mut self.line_cache[oldest]; + + // If the entry doesn't point to the correct file, fix it up + if pos < cache_entry.file.start_pos || pos >= cache_entry.file.end_pos { + let file_index = self.codemap.lookup_filemap_idx(pos); + cache_entry.file = self.codemap.files.borrow()[file_index].clone(); + } + + let line_index = cache_entry.file.lookup_line(pos).unwrap(); + let line_bounds = cache_entry.file.line_bounds(line_index); + + cache_entry.line_number = line_index + 1; + cache_entry.line_start = line_bounds.0; + cache_entry.line_end = line_bounds.1; + cache_entry.time_stamp = self.time_stamp; + + return (cache_entry.file.clone(), + cache_entry.line_number, + pos - cache_entry.line_start); + } +} diff --git a/src/librustc_incremental/calculate_svh/mod.rs b/src/librustc_incremental/calculate_svh/mod.rs index 6ad93d8f4733..c54fe2114517 100644 --- a/src/librustc_incremental/calculate_svh/mod.rs +++ b/src/librustc_incremental/calculate_svh/mod.rs @@ -40,9 +40,11 @@ use rustc::session::config::DebugInfoLevel::NoDebugInfo; use self::def_path_hash::DefPathHashes; use self::svh_visitor::StrictVersionHashVisitor; +use self::caching_codemap_view::CachingCodemapView; mod def_path_hash; mod svh_visitor; +mod caching_codemap_view; pub type IncrementalHashesMap = FnvHashMap, u64>; @@ -55,7 +57,8 @@ pub fn compute_incremental_hashes_map<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) tcx: tcx, hashes: FnvHashMap(), def_path_hashes: DefPathHashes::new(tcx), - hash_spans: hash_spans + codemap: CachingCodemapView::new(tcx), + hash_spans: hash_spans, }; record_time(&tcx.sess.perf_stats.incr_comp_hashes_time, || { visitor.calculate_def_id(DefId::local(CRATE_DEF_INDEX), @@ -69,6 +72,7 @@ pub fn compute_incremental_hashes_map<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) struct HashItemsVisitor<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, def_path_hashes: DefPathHashes<'a, 'tcx>, + codemap: CachingCodemapView<'tcx>, hashes: IncrementalHashesMap, hash_spans: bool, } @@ -92,6 +96,7 @@ impl<'a, 'tcx> HashItemsVisitor<'a, 'tcx> { walk_op(&mut StrictVersionHashVisitor::new(&mut state, self.tcx, &mut self.def_path_hashes, + &mut self.codemap, self.hash_spans)); let item_hash = state.finish(); self.hashes.insert(DepNode::Hir(def_id), item_hash); @@ -132,6 +137,7 @@ impl<'a, 'tcx> HashItemsVisitor<'a, 'tcx> { let mut visitor = StrictVersionHashVisitor::new(&mut crate_state, self.tcx, &mut self.def_path_hashes, + &mut self.codemap, self.hash_spans); visitor.hash_attributes(&krate.attrs); } diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs index e871dd5bcbff..417f09c1c9d5 100644 --- a/src/librustc_incremental/calculate_svh/svh_visitor.rs +++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs @@ -17,18 +17,17 @@ use self::SawExprComponent::*; use self::SawAbiComponent::*; use syntax::ast::{self, Name, NodeId, Attribute}; use syntax::parse::token; -use syntax::codemap::CodeMap; -use syntax_pos::{Span, NO_EXPANSION, COMMAND_LINE_EXPN, BytePos, FileMap}; +use syntax_pos::{Span, NO_EXPANSION, COMMAND_LINE_EXPN, BytePos}; use rustc::hir; use rustc::hir::*; use rustc::hir::def::{Def, PathResolution}; use rustc::hir::def_id::DefId; use rustc::hir::intravisit as visit; use rustc::ty::TyCtxt; -use std::rc::Rc; use std::hash::{Hash, SipHasher}; use super::def_path_hash::DefPathHashes; +use super::caching_codemap_view::CachingCodemapView; const IGNORED_ATTRIBUTES: &'static [&'static str] = &["cfg", "rustc_clean", @@ -40,92 +39,14 @@ pub struct StrictVersionHashVisitor<'a, 'hash: 'a, 'tcx: 'hash> { // collect a deterministic hash of def-ids that we have seen def_path_hashes: &'a mut DefPathHashes<'hash, 'tcx>, hash_spans: bool, - codemap: CachingCodemapView<'tcx>, -} - -#[derive(Clone)] -struct CacheEntry { - time_stamp: usize, - line_number: usize, - line_start: BytePos, - line_end: BytePos, - file: Rc, -} - -struct CachingCodemapView<'tcx> { - codemap: &'tcx CodeMap, - line_cache: [CacheEntry; 3], - time_stamp: usize, -} - -impl<'tcx> CachingCodemapView<'tcx> { - fn new<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> CachingCodemapView<'tcx> { - let codemap = tcx.sess.codemap(); - let first_file = codemap.files.borrow()[0].clone(); - let entry = CacheEntry { - time_stamp: 0, - line_number: 0, - line_start: BytePos(0), - line_end: BytePos(0), - file: first_file, - }; - - CachingCodemapView { - codemap: codemap, - line_cache: [entry.clone(), entry.clone(), entry.clone()], - time_stamp: 0, - } - } - - fn byte_pos_to_line_and_col(&mut self, - pos: BytePos) - -> (Rc, usize, BytePos) { - self.time_stamp += 1; - - // Check if the position is in one of the cached lines - for cache_entry in self.line_cache.iter_mut() { - if pos >= cache_entry.line_start && pos < cache_entry.line_end { - cache_entry.time_stamp = self.time_stamp; - return (cache_entry.file.clone(), - cache_entry.line_number, - pos - cache_entry.line_start); - } - } - - // No cache hit ... - let mut oldest = 0; - for index in 1 .. self.line_cache.len() { - if self.line_cache[index].time_stamp < self.line_cache[oldest].time_stamp { - oldest = index; - } - } - - let cache_entry = &mut self.line_cache[oldest]; - - // If the entry doesn't point to the correct file, fix it up - if pos < cache_entry.file.start_pos || pos >= cache_entry.file.end_pos { - let file_index = self.codemap.lookup_filemap_idx(pos); - cache_entry.file = self.codemap.files.borrow()[file_index].clone(); - } - - let line_index = cache_entry.file.lookup_line(pos).unwrap(); - let line_bounds = cache_entry.file.line_bounds(line_index); - - cache_entry.line_number = line_index + 1; - cache_entry.line_start = line_bounds.0; - cache_entry.line_end = line_bounds.1; - cache_entry.time_stamp = self.time_stamp; - - return (cache_entry.file.clone(), - cache_entry.line_number, - pos - cache_entry.line_start); - } + codemap: &'a mut CachingCodemapView<'tcx>, } impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> { pub fn new(st: &'a mut SipHasher, tcx: TyCtxt<'hash, 'tcx, 'tcx>, def_path_hashes: &'a mut DefPathHashes<'hash, 'tcx>, + codemap: &'a mut CachingCodemapView<'tcx>, hash_spans: bool) -> Self { StrictVersionHashVisitor { @@ -133,7 +54,7 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> { tcx: tcx, def_path_hashes: def_path_hashes, hash_spans: hash_spans, - codemap: CachingCodemapView::new(tcx), + codemap: codemap, } } @@ -178,7 +99,8 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> { expansion_kind).hash(self.st); if expansion_kind == SawSpanExpnKind::SomeExpansion { - self.hash_span(self.codemap.codemap.source_callsite(span)); + let call_site = self.codemap.codemap().source_callsite(span); + self.hash_span(call_site); } } From 0f8eb81011dcc2f235e74a4f0b7c2d80c1b0b4ab Mon Sep 17 00:00:00 2001 From: Florian Gilcher Date: Mon, 29 Aug 2016 20:05:47 +0200 Subject: [PATCH 082/443] Document try!'s error conversion behaviour --- src/libcore/macros.rs | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index c916ad930ff1..f29a49dd5fe1 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -189,10 +189,19 @@ macro_rules! debug_assert_eq { ($($arg:tt)*) => (if cfg!(debug_assertions) { assert_eq!($($arg)*); }) } -/// Helper macro for unwrapping `Result` values while returning early with an -/// error if the value of the expression is `Err`. Can only be used in -/// functions that return `Result` because of the early return of `Err` that -/// it provides. +/// Helper macro for reducing boilerplate code for matching `Result` together +/// with converting downstream errors. +/// +/// `try!` matches the given `Result`. In case of the `Ok` variant, the +/// expression has the value of the wrapped value. +/// +/// In case of the `Err` variant, it retrieves the inner error. `try!` then +/// performs conversion using `From`. This provides automatic conversion +/// between specialized errors and more general ones. The resulting +/// error is then immediately returned. +/// +/// Because of the early return, `try!` can only be used in functions that +/// return `Result`. /// /// # Examples /// @@ -201,18 +210,28 @@ macro_rules! debug_assert_eq { /// use std::fs::File; /// use std::io::prelude::*; /// -/// fn write_to_file_using_try() -> Result<(), io::Error> { +/// enum MyError { +/// FileWriteError +/// } +/// +/// impl From for MyError { +/// fn from(e: io::Error) -> MyError { +/// MyError::FileWriteError +/// } +/// } +/// +/// fn write_to_file_using_try() -> Result<(), MyError> { /// let mut file = try!(File::create("my_best_friends.txt")); /// try!(file.write_all(b"This is a list of my best friends.")); /// println!("I wrote to the file"); /// Ok(()) /// } /// // This is equivalent to: -/// fn write_to_file_using_match() -> Result<(), io::Error> { +/// fn write_to_file_using_match() -> Result<(), MyError> { /// let mut file = try!(File::create("my_best_friends.txt")); /// match file.write_all(b"This is a list of my best friends.") { /// Ok(v) => v, -/// Err(e) => return Err(e), +/// Err(e) => return Err(From::from(e)), /// } /// println!("I wrote to the file"); /// Ok(()) From 7310a8ffea95400c2c61d4fb27c224eb0e64e244 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Thu, 1 Sep 2016 14:39:31 -0400 Subject: [PATCH 083/443] ICH: Adapt to changes in the MetaItem AST representation. --- src/librustc_data_structures/fnv.rs | 6 ++++ .../calculate_svh/svh_visitor.rs | 35 +++++++++---------- 2 files changed, 23 insertions(+), 18 deletions(-) diff --git a/src/librustc_data_structures/fnv.rs b/src/librustc_data_structures/fnv.rs index 0000c283a7a0..47f623266f3b 100644 --- a/src/librustc_data_structures/fnv.rs +++ b/src/librustc_data_structures/fnv.rs @@ -57,3 +57,9 @@ impl Hasher for FnvHasher { self.0 } } + +pub fn hash(v: &T) -> u64 { + let mut state = FnvHasher::default(); + v.hash(&mut state); + state.finish() +} diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs index 417f09c1c9d5..05a2f751d292 100644 --- a/src/librustc_incremental/calculate_svh/svh_visitor.rs +++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs @@ -15,7 +15,7 @@ use self::SawExprComponent::*; use self::SawAbiComponent::*; -use syntax::ast::{self, Name, NodeId, Attribute}; +use syntax::ast::{self, Name, NodeId}; use syntax::parse::token; use syntax_pos::{Span, NO_EXPANSION, COMMAND_LINE_EXPN, BytePos}; use rustc::hir; @@ -24,6 +24,7 @@ use rustc::hir::def::{Def, PathResolution}; use rustc::hir::def_id::DefId; use rustc::hir::intravisit as visit; use rustc::ty::TyCtxt; +use rustc_data_structures::fnv; use std::hash::{Hash, SipHasher}; use super::def_path_hash::DefPathHashes; @@ -526,7 +527,7 @@ impl<'a, 'hash, 'tcx> visit::Visitor<'tcx> for StrictVersionHashVisitor<'a, 'has visit::walk_assoc_type_binding(self, type_binding) } - fn visit_attribute(&mut self, _: &Attribute) { + fn visit_attribute(&mut self, _: &ast::Attribute) { // We explicitly do not use this method, since doing that would // implicitly impose an order on the attributes being hashed, while we // explicitly don't want their order to matter @@ -658,28 +659,34 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> { s.hash(self.st); // Sort subitems so the hash does not depend on their order let indices = self.indices_sorted_by(&items, |p| { - meta_item_sort_key(&*p) + (p.name(), fnv::hash(&p.literal().map(|i| &i.node))) }); items.len().hash(self.st); for (index, &item_index) in indices.iter().enumerate() { index.hash(self.st); - self.hash_meta_item(&items[item_index]); + let nested_meta_item: &ast::NestedMetaItemKind = &items[item_index].node; + self.hash_discriminant(nested_meta_item); + match *nested_meta_item { + ast::NestedMetaItemKind::MetaItem(ref meta_item) => { + self.hash_meta_item(meta_item); + } + ast::NestedMetaItemKind::Literal(ref lit) => { + lit.node.hash(self.st); + } + } } } } } - pub fn hash_attributes(&mut self, attributes: &[Attribute]) { + pub fn hash_attributes(&mut self, attributes: &[ast::Attribute]) { debug!("hash_attributes: st={:?}", self.st); - let indices = self.indices_sorted_by(attributes, |attr| { - meta_item_sort_key(&attr.node.value) - }); + let indices = self.indices_sorted_by(attributes, |attr| attr.name()); for i in indices { let attr = &attributes[i].node; - if !attr.is_sugared_doc && - !IGNORED_ATTRIBUTES.contains(&&*meta_item_sort_key(&attr.value)) { + !IGNORED_ATTRIBUTES.contains(&&*attr.value.name()) { SawAttribute(attr.style).hash(self.st); self.hash_meta_item(&*attr.value); } @@ -696,11 +703,3 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> { indices } } - -fn meta_item_sort_key(item: &ast::MetaItem) -> token::InternedString { - match item.node { - ast::MetaItemKind::Word(ref s) | - ast::MetaItemKind::NameValue(ref s, _) | - ast::MetaItemKind::List(ref s, _) => s.clone() - } -} From 66ae481055d5379656c420a30534887a31f81404 Mon Sep 17 00:00:00 2001 From: c4rlo Date: Thu, 1 Sep 2016 22:42:51 +0100 Subject: [PATCH 084/443] README.md: fix a "\" in table heading to be "/" --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index dbe48a50cfa7..f2385f315186 100644 --- a/README.md +++ b/README.md @@ -170,7 +170,7 @@ fetch snapshots, and an OS that can execute the available snapshot binaries. Snapshot binaries are currently built and tested on several platforms: -| Platform \ Architecture | x86 | x86_64 | +| Platform / Architecture | x86 | x86_64 | |--------------------------------|-----|--------| | Windows (7, 8, Server 2008 R2) | ✓ | ✓ | | Linux (2.6.18 or later) | ✓ | ✓ | From 48a435a90fb227f0da20b610438618dfc2c49a4e Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Mon, 22 Aug 2016 19:20:08 +0000 Subject: [PATCH 085/443] Fix test `compile-fail/task-rng-isnt-sendable.rs`. --- src/test/compile-fail/task-rng-isnt-sendable.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/compile-fail/task-rng-isnt-sendable.rs b/src/test/compile-fail/task-rng-isnt-sendable.rs index 9c0a2267d7cf..c987d9f2f4e1 100644 --- a/src/test/compile-fail/task-rng-isnt-sendable.rs +++ b/src/test/compile-fail/task-rng-isnt-sendable.rs @@ -10,10 +10,10 @@ // ensure that the ThreadRng isn't/doesn't become accidentally sendable. -use std::rand; //~ ERROR: module `rand` is private +use std::__rand::ThreadRng; fn test_send() {} pub fn main() { - test_send::(); + test_send::(); //~ ERROR std::marker::Send` is not satisfied } From 5dc1196191c2f1edba8baaf841fdc07f9f8eea0b Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Fri, 19 Aug 2016 21:46:28 +0000 Subject: [PATCH 086/443] Refactor away `binding.is_pseudo_public()`. --- src/librustc_resolve/lib.rs | 4 ---- src/librustc_resolve/resolve_imports.rs | 11 +++++------ 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 54efc4ae30a6..e27936b91296 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -885,10 +885,6 @@ impl<'a> NameBinding<'a> { } } - fn is_pseudo_public(&self) -> bool { - self.pseudo_vis() == ty::Visibility::Public - } - // 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 } diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 8c6d89c29bde..eedbccbb039b 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -168,7 +168,7 @@ impl<'a> Resolver<'a> { }; let is_disallowed_private_import = |binding: &NameBinding| { - !allow_private_imports && !binding.is_pseudo_public() && binding.is_import() + !allow_private_imports && binding.vis != ty::Visibility::Public && binding.is_import() }; if let Some(span) = record_used { @@ -338,7 +338,7 @@ impl<'a> Resolver<'a> { }; // Define `new_binding` in `module`s glob importers. - if new_binding.is_importable() && new_binding.is_pseudo_public() { + if new_binding.vis == ty::Visibility::Public { for directive in module.glob_importers.borrow_mut().iter() { let imported_binding = self.import(new_binding, directive); let _ = self.try_define(directive.parent, name, ns, imported_binding); @@ -656,9 +656,8 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { if let Some(Def::Trait(_)) = module.def { self.session.span_err(directive.span, "items in traits are not importable."); - } - - if module.def_id() == directive.parent.def_id() { + return; + } else if module.def_id() == directive.parent.def_id() { return; } else if let GlobImport { is_prelude: true } = directive.subclass { self.prelude = Some(module); @@ -674,7 +673,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { resolution.borrow().binding().map(|binding| (*name, binding)) }).collect::>(); for ((name, ns), binding) in bindings { - if binding.is_importable() && binding.is_pseudo_public() { + if binding.pseudo_vis() == ty::Visibility::Public { let imported_binding = self.import(binding, directive); let _ = self.try_define(directive.parent, name, ns, imported_binding); } From 691d10c3c947761ea00df87bd1b1fd532da248e0 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Sat, 20 Aug 2016 07:22:32 +0000 Subject: [PATCH 087/443] Rename `new_binding` -> `binding`. --- src/librustc_resolve/resolve_imports.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index eedbccbb039b..81f99e2240b6 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -324,7 +324,7 @@ impl<'a> Resolver<'a> { { // Ensure that `resolution` isn't borrowed when defining in the module's glob importers, // during which the resolution might end up getting re-defined via a glob cycle. - let (new_binding, t) = { + let (binding, t) = { let mut resolution = &mut *self.resolution(module, name, ns).borrow_mut(); let was_known = resolution.binding().is_some(); @@ -337,10 +337,10 @@ impl<'a> Resolver<'a> { } }; - // Define `new_binding` in `module`s glob importers. - if new_binding.vis == ty::Visibility::Public { + // Define `binding` in `module`s glob importers. + if binding.vis == ty::Visibility::Public { for directive in module.glob_importers.borrow_mut().iter() { - let imported_binding = self.import(new_binding, directive); + let imported_binding = self.import(binding, directive); let _ = self.try_define(directive.parent, name, ns, imported_binding); } } From 87ae68c1d6e55a62e1faf4ceccb5e884aa6a95d5 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Sat, 20 Aug 2016 07:26:26 +0000 Subject: [PATCH 088/443] Refactor `binding.def()` to return a `Def` instead of an `Option`. --- src/librustc_resolve/lib.rs | 34 ++++++++++++------------- src/librustc_resolve/resolve_imports.rs | 8 +++--- 2 files changed, 20 insertions(+), 22 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index e27936b91296..8a7a22988cb5 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -459,7 +459,7 @@ fn resolve_struct_error<'b, 'a: 'b, 'c>(resolver: &'b Resolver<'a>, err } ResolutionError::BindingShadowsSomethingUnacceptable(what_binding, name, binding) => { - let shadows_what = PathResolution::new(binding.def().unwrap()).kind_name(); + let shadows_what = PathResolution::new(binding.def()).kind_name(); let mut err = struct_span_err!(resolver.session, span, E0530, @@ -739,7 +739,7 @@ impl<'a> LexicalScopeBinding<'a> { fn local_def(self) -> LocalDef { match self { LexicalScopeBinding::LocalDef(local_def) => local_def, - LexicalScopeBinding::Item(binding) => LocalDef::from_def(binding.def().unwrap()), + LexicalScopeBinding::Item(binding) => LocalDef::from_def(binding.def()), } } @@ -877,10 +877,10 @@ impl<'a> NameBinding<'a> { } } - fn def(&self) -> Option { + fn def(&self) -> Def { match self.kind { - NameBindingKind::Def(def) => Some(def), - NameBindingKind::Module(module) => module.def, + NameBindingKind::Def(def) => def, + NameBindingKind::Module(module) => module.def.unwrap(), NameBindingKind::Import { binding, .. } => binding.def(), } } @@ -916,7 +916,7 @@ impl<'a> NameBinding<'a> { } fn is_importable(&self) -> bool { - match self.def().unwrap() { + match self.def() { Def::AssociatedConst(..) | Def::Method(..) | Def::AssociatedTy(..) => false, _ => true, } @@ -1097,7 +1097,7 @@ impl<'a> hir::lowering::Resolver for Resolver<'a> { fn resolve_generated_global_path(&mut self, path: &hir::Path, is_value: bool) -> Def { let namespace = if is_value { ValueNS } else { TypeNS }; match self.resolve_crate_relative_path(path.span, &path.segments, namespace) { - Ok(binding) => binding.def().unwrap(), + Ok(binding) => binding.def(), Err(true) => Def::Err, Err(false) => { let path_name = &format!("{}", path); @@ -1693,7 +1693,7 @@ impl<'a> Resolver<'a> { &prefix.segments, TypeNS) { Ok(binding) => { - let def = binding.def().unwrap(); + let def = binding.def(); self.record_def(item.id, PathResolution::new(def)); } Err(true) => self.record_def(item.id, err_path_resolution()), @@ -2309,7 +2309,7 @@ impl<'a> Resolver<'a> { // entity, then fall back to a fresh binding. let binding = self.resolve_ident_in_lexical_scope(ident.node, ValueNS, None) .and_then(LexicalScopeBinding::item); - let resolution = binding.and_then(NameBinding::def).and_then(|def| { + let resolution = binding.map(NameBinding::def).and_then(|def| { let always_binding = !pat_src.is_refutable() || opt_pat.is_some() || bmode != BindingMode::ByValue(Mutability::Immutable); match def { @@ -2443,7 +2443,7 @@ impl<'a> Resolver<'a> { if path.global { let binding = self.resolve_crate_relative_path(span, segments, namespace); - return binding.map(|binding| mk_res(binding.def().unwrap())); + return binding.map(|binding| mk_res(binding.def())); } // Try to find a path to an item in a module. @@ -2481,7 +2481,7 @@ impl<'a> Resolver<'a> { let unqualified_def = resolve_identifier_with_fallback(self, None); let qualified_binding = self.resolve_module_relative_path(span, segments, namespace); match (qualified_binding, unqualified_def) { - (Ok(binding), Some(ref ud)) if binding.def().unwrap() == ud.def => { + (Ok(binding), Some(ref ud)) if binding.def() == ud.def => { self.session .add_lint(lint::builtin::UNUSED_QUALIFICATIONS, id, @@ -2491,7 +2491,7 @@ impl<'a> Resolver<'a> { _ => {} } - qualified_binding.map(|binding| mk_res(binding.def().unwrap())) + qualified_binding.map(|binding| mk_res(binding.def())) } // Resolve a single identifier @@ -3114,7 +3114,7 @@ impl<'a> Resolver<'a> { let mut collected_traits = Vec::new(); module.for_each_child(|name, ns, binding| { if ns != TypeNS { return } - if let Some(Def::Trait(_)) = binding.def() { + if let Def::Trait(_) = binding.def() { collected_traits.push((name, binding)); } }); @@ -3122,7 +3122,7 @@ impl<'a> Resolver<'a> { } for &(trait_name, binding) in traits.as_ref().unwrap().iter() { - let trait_def_id = binding.def().unwrap().def_id(); + let trait_def_id = binding.def().def_id(); if this.trait_item_map.contains_key(&(name, trait_def_id)) { let mut import_id = None; if let NameBindingKind::Import { directive, .. } = binding.kind { @@ -3181,8 +3181,8 @@ impl<'a> Resolver<'a> { if name_binding.is_import() { return; } // collect results based on the filter function - if let Some(def) = name_binding.def() { - if name == lookup_name && ns == namespace && filter_fn(def) { + if name == lookup_name && ns == namespace { + if filter_fn(name_binding.def()) { // create the path let ident = ast::Ident::with_empty_ctxt(name); let params = PathParameters::none(); @@ -3302,7 +3302,7 @@ impl<'a> Resolver<'a> { let msg = format!("extern crate `{}` is private", name); self.session.add_lint(lint::builtin::INACCESSIBLE_EXTERN_CRATE, node_id, span, msg); } else { - let def = binding.def().unwrap(); + let def = binding.def(); self.session.span_err(span, &format!("{} `{}` is private", def.kind_name(), name)); } } diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 81f99e2240b6..e00c736138d3 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -639,9 +639,9 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { // Record what this import resolves to for later uses in documentation, // this may resolve to either a value or a type, but for documentation // purposes it's good enough to just favor one over the other. - let def = match type_result.ok().and_then(NameBinding::def) { + let def = match type_result.ok().map(NameBinding::def) { Some(def) => def, - None => value_result.ok().and_then(NameBinding::def).unwrap(), + None => value_result.ok().map(NameBinding::def).unwrap(), }; let path_resolution = PathResolution::new(def); self.def_map.insert(directive.id, path_resolution); @@ -714,9 +714,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { if binding.vis == ty::Visibility::Public && (binding.is_import() || binding.is_extern_crate()) { - if let Some(def) = binding.def() { - reexports.push(Export { name: name, def_id: def.def_id() }); - } + reexports.push(Export { name: name, def_id: binding.def().def_id() }); } if let NameBindingKind::Import { binding: orig_binding, directive, .. } = binding.kind { From 1e4c8173e182d6254c7faafb3d1e1020eac194c8 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Sat, 20 Aug 2016 07:59:47 +0000 Subject: [PATCH 089/443] Improve diagnostics and remove dead code. --- src/librustc_resolve/lib.rs | 46 +++++++++++------------------ src/test/compile-fail/bad-module.rs | 8 +++-- 2 files changed, 23 insertions(+), 31 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 8a7a22988cb5..6cf53f877fb6 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1287,7 +1287,7 @@ impl<'a> Resolver<'a> { while index < module_path_len { let name = module_path[index]; match self.resolve_name_in_module(search_module, name, TypeNS, false, span) { - Failed(None) => { + Failed(_) => { let segment_name = name.as_str(); let module_name = module_to_string(search_module); let msg = if "???" == &module_name { @@ -1314,7 +1314,6 @@ impl<'a> Resolver<'a> { return Failed(span.map(|span| (span, msg))); } - Failed(err) => return Failed(err), Indeterminate => { debug!("(resolving module path for import) module resolution is \ indeterminate: {}", @@ -1383,7 +1382,11 @@ impl<'a> Resolver<'a> { let ident = ast::Ident::with_empty_ctxt(module_path[0]); match self.resolve_ident_in_lexical_scope(ident, TypeNS, span) .and_then(LexicalScopeBinding::module) { - None => return Failed(None), + None => { + let msg = + format!("Use of undeclared type or module `{}`", ident.name); + return Failed(span.map(|span| (span, msg))); + } Some(containing_module) => { search_module = containing_module; start_index = 1; @@ -2614,16 +2617,9 @@ impl<'a> Resolver<'a> { let containing_module; match self.resolve_module_path(&module_path, UseLexicalScope, Some(span)) { Failed(err) => { - let (span, msg) = match err { - Some((span, msg)) => (span, msg), - None => { - let msg = format!("Use of undeclared type or module `{}`", - names_to_string(&module_path)); - (span, msg) - } - }; - - resolve_error(self, span, ResolutionError::FailedToResolve(&msg)); + if let Some((span, msg)) = err { + resolve_error(self, span, ResolutionError::FailedToResolve(&msg)); + } return Err(true); } Indeterminate => return Err(false), @@ -2651,16 +2647,9 @@ impl<'a> Resolver<'a> { let containing_module; match self.resolve_module_path_from_root(root_module, &module_path, 0, Some(span)) { Failed(err) => { - let (span, msg) = match err { - Some((span, msg)) => (span, msg), - None => { - let msg = format!("Use of undeclared module `::{}`", - names_to_string(&module_path)); - (span, msg) - } - }; - - resolve_error(self, span, ResolutionError::FailedToResolve(&msg)); + if let Some((span, msg)) = err { + resolve_error(self, span, ResolutionError::FailedToResolve(&msg)); + } return Err(true); } @@ -3270,12 +3259,11 @@ impl<'a> Resolver<'a> { path_resolution = PathResolution::new(def); ty::Visibility::Restricted(self.definitions.as_local_node_id(def.def_id()).unwrap()) } - Failed(Some((span, msg))) => { - self.session.span_err(span, &format!("failed to resolve module path. {}", msg)); - ty::Visibility::Public - } - _ => { - self.session.span_err(path.span, "unresolved module path"); + Indeterminate => unreachable!(), + Failed(err) => { + if let Some((span, msg)) = err { + self.session.span_err(span, &format!("failed to resolve module path. {}", msg)); + } ty::Visibility::Public } }; diff --git a/src/test/compile-fail/bad-module.rs b/src/test/compile-fail/bad-module.rs index 0cd3a8853185..6987d06ef12c 100644 --- a/src/test/compile-fail/bad-module.rs +++ b/src/test/compile-fail/bad-module.rs @@ -8,6 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern: failed to resolve. Use of undeclared type or module `thing` +fn main() { + let foo = thing::len(Vec::new()); + //~^ ERROR failed to resolve. Use of undeclared type or module `thing` -fn main() { let foo = thing::len(Vec::new()); } + let foo = foo::bar::baz(); + //~^ ERROR failed to resolve. Use of undeclared type or module `foo` +} From 95528d1a9839066a29cc1cb50b097d5f84633148 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Mon, 22 Aug 2016 00:24:11 +0000 Subject: [PATCH 090/443] Refactor away `resolver.current_vis` and add `module.normal_ancestor_id`. --- src/librustc_resolve/build_reduced_graph.rs | 18 ++-- src/librustc_resolve/lib.rs | 106 +++++++------------- src/librustc_resolve/resolve_imports.rs | 12 +-- 3 files changed, 47 insertions(+), 89 deletions(-) diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 71b00218e7cc..83d35095f351 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -30,7 +30,7 @@ use syntax::ast::Name; use syntax::attr; use syntax::parse::token; -use syntax::ast::{Block, Crate}; +use syntax::ast::{Block, Crate, DUMMY_NODE_ID}; use syntax::ast::{ForeignItem, ForeignItemKind, Item, ItemKind}; use syntax::ast::{Mutability, StmtKind, TraitItemKind}; use syntax::ast::{Variant, ViewPathGlob, ViewPathList, ViewPathSimple}; @@ -81,7 +81,6 @@ impl<'b> Resolver<'b> { /// Constructs the reduced graph for one item. fn build_reduced_graph_for_item(&mut self, item: &Item) { let parent = self.current_module; - let parent_vis = self.current_vis; let name = item.ident.name; let sp = item.span; let vis = self.resolve_visibility(&item.vis); @@ -204,7 +203,7 @@ impl<'b> Resolver<'b> { ItemKind::Mod(..) => { let parent_link = ModuleParentLink(parent, name); let def = Def::Mod(self.definitions.local_def_id(item.id)); - let module = self.new_module(parent_link, Some(def), false); + let module = self.new_module(parent_link, Some(def), item.id); module.no_implicit_prelude.set({ parent.no_implicit_prelude.get() || attr::contains_name(&item.attrs, "no_implicit_prelude") @@ -214,7 +213,6 @@ impl<'b> Resolver<'b> { // Descend into the module. self.current_module = module; - self.current_vis = ty::Visibility::Restricted(item.id); } ItemKind::ForeignMod(..) => {} @@ -243,7 +241,7 @@ impl<'b> Resolver<'b> { ItemKind::Enum(ref enum_definition, _) => { let parent_link = ModuleParentLink(parent, name); let def = Def::Enum(self.definitions.local_def_id(item.id)); - let module = self.new_module(parent_link, Some(def), false); + let module = self.new_module(parent_link, Some(def), parent.normal_ancestor_id); self.define(parent, name, TypeNS, (module, sp, vis)); for variant in &(*enum_definition).variants { @@ -285,7 +283,8 @@ impl<'b> Resolver<'b> { // Add all the items within to a new module. let parent_link = ModuleParentLink(parent, name); let def = Def::Trait(def_id); - let module_parent = self.new_module(parent_link, Some(def), false); + let module_parent = + self.new_module(parent_link, Some(def), parent.normal_ancestor_id); self.define(parent, name, TypeNS, (module_parent, sp, vis)); // Add the names of all the items to the trait info. @@ -312,7 +311,6 @@ impl<'b> Resolver<'b> { visit::walk_item(&mut BuildReducedGraphVisitor { resolver: self }, item); self.current_module = parent; - self.current_vis = parent_vis; } // Constructs the reduced graph for one variant. Variants exist in the @@ -363,7 +361,7 @@ impl<'b> Resolver<'b> { block_id); let parent_link = BlockParentLink(parent, block_id); - let new_module = self.new_module(parent_link, None, false); + let new_module = self.new_module(parent_link, None, parent.normal_ancestor_id); self.module_map.insert(block_id, new_module); self.current_module = new_module; // Descend into the block. } @@ -395,7 +393,7 @@ impl<'b> Resolver<'b> { debug!("(building reduced graph for external crate) building module {} {:?}", name, vis); let parent_link = ModuleParentLink(parent, name); - let module = self.new_module(parent_link, Some(def), true); + let module = self.new_module(parent_link, Some(def), DUMMY_NODE_ID); let _ = self.try_define(parent, name, TypeNS, (module, DUMMY_SP, vis)); } Def::Variant(_, variant_id) => { @@ -437,7 +435,7 @@ impl<'b> Resolver<'b> { } let parent_link = ModuleParentLink(parent, name); - let module = self.new_module(parent_link, Some(def), true); + let module = self.new_module(parent_link, Some(def), DUMMY_NODE_ID); let _ = self.try_define(parent, name, TypeNS, (module, DUMMY_SP, vis)); } Def::TyAlias(..) | Def::AssociatedTy(..) => { diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 6cf53f877fb6..b17687e17575 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -54,7 +54,7 @@ use rustc::util::nodemap::{NodeMap, NodeSet, FnvHashMap, FnvHashSet}; use syntax::ext::hygiene::Mark; use syntax::ast::{self, FloatTy}; -use syntax::ast::{CRATE_NODE_ID, Name, NodeId, CrateNum, IntTy, UintTy}; +use syntax::ast::{CRATE_NODE_ID, DUMMY_NODE_ID, Name, NodeId, CrateNum, IntTy, UintTy}; use syntax::parse::token::{self, keywords}; use syntax::util::lev_distance::find_best_match_for_name; @@ -768,6 +768,9 @@ pub struct ModuleS<'a> { parent_link: ParentLink<'a>, def: Option, + // The node id of the closest normal module (`mod`) ancestor (including this module). + normal_ancestor_id: NodeId, + // If the module is an extern crate, `def` is root of the external crate and `extern_crate_id` // is the NodeId of the local `extern crate` item (otherwise, `extern_crate_id` is None). extern_crate_id: Option, @@ -791,17 +794,18 @@ pub struct ModuleS<'a> { pub type Module<'a> = &'a ModuleS<'a>; impl<'a> ModuleS<'a> { - fn new(parent_link: ParentLink<'a>, def: Option, external: bool) -> Self { + fn new(parent_link: ParentLink<'a>, def: Option, normal_ancestor_id: NodeId) -> Self { ModuleS { parent_link: parent_link, def: def, + normal_ancestor_id: normal_ancestor_id, extern_crate_id: None, resolutions: RefCell::new(FnvHashMap()), no_implicit_prelude: Cell::new(false), glob_importers: RefCell::new(Vec::new()), globs: RefCell::new((Vec::new())), traits: RefCell::new(None), - populated: Cell::new(!external), + populated: Cell::new(normal_ancestor_id != DUMMY_NODE_ID), } } @@ -829,6 +833,13 @@ impl<'a> ModuleS<'a> { _ => false, } } + + fn parent(&self) -> Option<&'a Self> { + match self.parent_link { + ModuleParentLink(parent, _) | BlockParentLink(parent, _) => Some(parent), + NoParentLink => None, + } + } } impl<'a> fmt::Debug for ModuleS<'a> { @@ -983,10 +994,6 @@ pub struct Resolver<'a> { // The module that represents the current item scope. current_module: Module<'a>, - // The visibility of `pub(self)` items in the current scope. - // Equivalently, the visibility required for an item to be accessible from the current scope. - current_vis: ty::Visibility, - // The current set of local scopes, for values. // FIXME #4948: Reuse ribs to avoid allocation. value_ribs: Vec>, @@ -1079,15 +1086,12 @@ impl<'a> ResolverArenas<'a> { } impl<'a> ty::NodeIdTree for Resolver<'a> { - fn is_descendant_of(&self, node: NodeId, ancestor: NodeId) -> bool { - let ancestor = self.definitions.local_def_id(ancestor); - let mut module = *self.module_map.get(&node).unwrap(); - while module.def_id() != Some(ancestor) { - let module_parent = match self.get_nearest_normal_module_parent(module) { - Some(parent) => parent, + fn is_descendant_of(&self, mut node: NodeId, ancestor: NodeId) -> bool { + while node != ancestor { + node = match self.module_map[&node].parent() { + Some(parent) => parent.normal_ancestor_id, None => return false, - }; - module = module_parent; + } } true } @@ -1149,8 +1153,7 @@ impl<'a> Resolver<'a> { pub fn new(session: &'a Session, make_glob_map: MakeGlobMap, arenas: &'a ResolverArenas<'a>) -> Resolver<'a> { let root_def_id = DefId::local(CRATE_DEF_INDEX); - let graph_root = - ModuleS::new(NoParentLink, Some(Def::Mod(root_def_id)), false); + let graph_root = ModuleS::new(NoParentLink, Some(Def::Mod(root_def_id)), CRATE_NODE_ID); let graph_root = arenas.alloc_module(graph_root); let mut module_map = NodeMap(); module_map.insert(CRATE_NODE_ID, graph_root); @@ -1173,7 +1176,6 @@ impl<'a> Resolver<'a> { indeterminate_imports: Vec::new(), current_module: graph_root, - current_vis: ty::Visibility::Restricted(ast::CRATE_NODE_ID), value_ribs: vec![Rib::new(ModuleRibKind(graph_root))], type_ribs: vec![Rib::new(ModuleRibKind(graph_root))], label_ribs: Vec::new(), @@ -1217,21 +1219,20 @@ impl<'a> Resolver<'a> { /// Entry point to crate resolution. pub fn resolve_crate(&mut self, krate: &Crate) { self.current_module = self.graph_root; - self.current_vis = ty::Visibility::Restricted(ast::CRATE_NODE_ID); visit::walk_crate(self, krate); check_unused::check_crate(self, krate); self.report_privacy_errors(); } - fn new_module(&self, parent_link: ParentLink<'a>, def: Option, external: bool) + fn new_module(&self, parent_link: ParentLink<'a>, def: Option, normal_ancestor_id: NodeId) -> Module<'a> { - self.arenas.alloc_module(ModuleS::new(parent_link, def, external)) + self.arenas.alloc_module(ModuleS::new(parent_link, def, normal_ancestor_id)) } fn new_extern_crate_module(&self, parent_link: ParentLink<'a>, def: Def, local_node_id: NodeId) -> Module<'a> { - let mut module = ModuleS::new(parent_link, Some(def), false); + let mut module = ModuleS::new(parent_link, Some(def), local_node_id); module.extern_crate_id = Some(local_node_id); self.arenas.modules.alloc(module) } @@ -1473,35 +1474,6 @@ impl<'a> Resolver<'a> { None } - /// Returns the nearest normal module parent of the given module. - fn get_nearest_normal_module_parent(&self, mut module: Module<'a>) -> Option> { - loop { - match module.parent_link { - NoParentLink => return None, - ModuleParentLink(new_module, _) | - BlockParentLink(new_module, _) => { - let new_module = new_module; - if new_module.is_normal() { - return Some(new_module); - } - module = new_module; - } - } - } - } - - /// Returns the nearest normal module parent of the given module, or the - /// module itself if it is a normal module. - fn get_nearest_normal_module_parent_or_self(&self, module: Module<'a>) -> Module<'a> { - if module.is_normal() { - return module; - } - match self.get_nearest_normal_module_parent(module) { - None => module, - Some(new_module) => new_module, - } - } - /// Resolves a "module prefix". A module prefix is one or both of (a) `self::`; /// (b) some chain of `super::`. /// grammar: (SELF MOD_SEP ) ? (SUPER MOD_SEP) * @@ -1514,22 +1486,19 @@ impl<'a> Resolver<'a> { "super" => 0, _ => return Success(NoPrefixFound), }; - let mut containing_module = - self.get_nearest_normal_module_parent_or_self(self.current_module); + + let mut containing_module = self.module_map[&self.current_module.normal_ancestor_id]; // Now loop through all the `super`s we find. while i < module_path.len() && "super" == module_path[i].as_str() { debug!("(resolving module prefix) resolving `super` at {}", module_to_string(&containing_module)); - match self.get_nearest_normal_module_parent(containing_module) { - None => { - let msg = "There are too many initial `super`s.".into(); - return Failed(span.map(|span| (span, msg))); - } - Some(new_module) => { - containing_module = new_module; - i += 1; - } + if let Some(parent) = containing_module.parent() { + containing_module = self.module_map[&parent.normal_ancestor_id]; + i += 1; + } else { + let msg = "There are too many initial `super`s.".into(); + return Failed(span.map(|span| (span, msg))); } } @@ -1564,14 +1533,12 @@ impl<'a> Resolver<'a> { if let Some(module) = module { // Move down in the graph. let orig_module = replace(&mut self.current_module, module); - let orig_vis = replace(&mut self.current_vis, ty::Visibility::Restricted(id)); self.value_ribs.push(Rib::new(ModuleRibKind(module))); self.type_ribs.push(Rib::new(ModuleRibKind(module))); f(self); self.current_module = orig_module; - self.current_vis = orig_vis; self.value_ribs.pop(); self.type_ribs.pop(); } else { @@ -3248,16 +3215,17 @@ impl<'a> Resolver<'a> { ast::Visibility::Public => return ty::Visibility::Public, ast::Visibility::Crate(_) => return ty::Visibility::Restricted(ast::CRATE_NODE_ID), ast::Visibility::Restricted { ref path, id } => (path, id), - ast::Visibility::Inherited => return self.current_vis, + ast::Visibility::Inherited => { + return ty::Visibility::Restricted(self.current_module.normal_ancestor_id); + } }; let segments: Vec<_> = path.segments.iter().map(|seg| seg.identifier.name).collect(); let mut path_resolution = err_path_resolution(); let vis = match self.resolve_module_path(&segments, DontUseLexicalScope, Some(path.span)) { Success(module) => { - let def = module.def.unwrap(); - path_resolution = PathResolution::new(def); - ty::Visibility::Restricted(self.definitions.as_local_node_id(def.def_id()).unwrap()) + path_resolution = PathResolution::new(module.def.unwrap()); + ty::Visibility::Restricted(module.normal_ancestor_id) } Indeterminate => unreachable!(), Failed(err) => { @@ -3276,7 +3244,7 @@ impl<'a> Resolver<'a> { } fn is_accessible(&self, vis: ty::Visibility) -> bool { - vis.is_at_least(self.current_vis, self) + vis.is_accessible_from(self.current_module.normal_ancestor_id, self) } fn report_privacy_errors(&self) { diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index e00c736138d3..a0aab53c58f0 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -381,14 +381,6 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { // remain or unsuccessfully when no forward progress in resolving imports // is made. - fn set_current_module(&mut self, module: Module<'b>) { - self.current_module = module; - self.current_vis = ty::Visibility::Restricted({ - let normal_module = self.get_nearest_normal_module_parent_or_self(module); - self.definitions.as_local_node_id(normal_module.def_id().unwrap()).unwrap() - }); - } - /// Resolves all imports for the crate. This method performs the fixed- /// point iteration. fn resolve_imports(&mut self) { @@ -472,7 +464,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { names_to_string(&directive.module_path), module_to_string(self.current_module)); - self.set_current_module(directive.parent); + self.current_module = directive.parent; let module = if let Some(module) = directive.imported_module.get() { module @@ -548,7 +540,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { } fn finalize_import(&mut self, directive: &'b ImportDirective<'b>) -> ResolveResult<()> { - self.set_current_module(directive.parent); + self.current_module = directive.parent; let ImportDirective { ref module_path, span, .. } = *directive; let module_result = self.resolve_module_path(&module_path, DontUseLexicalScope, Some(span)); From 513e955a1891d12819ba642331eb436d00861f3d Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Mon, 22 Aug 2016 04:05:49 +0000 Subject: [PATCH 091/443] Add field `dummy_binding` to `Resolver`. --- src/librustc_resolve/lib.rs | 8 +++++++- src/librustc_resolve/resolve_imports.rs | 9 ++------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index b17687e17575..124a748be326 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -65,7 +65,7 @@ use syntax::ast::{Item, ItemKind, ImplItem, ImplItemKind}; use syntax::ast::{Local, Mutability, Pat, PatKind, Path}; use syntax::ast::{PathSegment, PathParameters, QSelf, TraitItemKind, TraitRef, Ty, TyKind}; -use syntax_pos::Span; +use syntax_pos::{Span, DUMMY_SP}; use errors::DiagnosticBuilder; use std::cell::{Cell, RefCell}; @@ -1052,6 +1052,7 @@ pub struct Resolver<'a> { privacy_errors: Vec>, arenas: &'a ResolverArenas<'a>, + dummy_binding: &'a NameBinding<'a>, } pub struct ResolverArenas<'a> { @@ -1203,6 +1204,11 @@ impl<'a> Resolver<'a> { privacy_errors: Vec::new(), arenas: arenas, + dummy_binding: arenas.alloc_name_binding(NameBinding { + kind: NameBindingKind::Def(Def::Err), + span: DUMMY_SP, + vis: ty::Visibility::Public, + }), } } diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index a0aab53c58f0..f02e9b048dea 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -27,7 +27,7 @@ use rustc::hir::def::*; use syntax::ast::{NodeId, Name}; use syntax::util::lev_distance::find_best_match_for_name; -use syntax_pos::{Span, DUMMY_SP}; +use syntax_pos::Span; use std::cell::{Cell, RefCell}; @@ -442,13 +442,8 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { // failed resolution fn import_dummy_binding(&mut self, directive: &'b ImportDirective<'b>) { if let SingleImport { target, .. } = directive.subclass { - let dummy_binding = self.arenas.alloc_name_binding(NameBinding { - kind: NameBindingKind::Def(Def::Err), - span: DUMMY_SP, - vis: ty::Visibility::Public, - }); + let dummy_binding = self.dummy_binding; let dummy_binding = self.import(dummy_binding, directive); - let _ = self.try_define(directive.parent, target, ValueNS, dummy_binding.clone()); let _ = self.try_define(directive.parent, target, TypeNS, dummy_binding); } From 5ba22c0ed68ed4b46c9db2ceac2e5cc96728411a Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Tue, 16 Aug 2016 06:03:36 +0000 Subject: [PATCH 092/443] Add `item_like_imports` feature. --- src/librustc_resolve/lib.rs | 2 ++ src/libsyntax/feature_gate.rs | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 124a748be326..8428507e686d 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1053,6 +1053,7 @@ pub struct Resolver<'a> { arenas: &'a ResolverArenas<'a>, dummy_binding: &'a NameBinding<'a>, + new_import_semantics: bool, // true if `#![feature(item_like_imports)]` } pub struct ResolverArenas<'a> { @@ -1209,6 +1210,7 @@ impl<'a> Resolver<'a> { span: DUMMY_SP, vis: ty::Visibility::Public, }), + new_import_semantics: session.features.borrow().item_like_imports, } } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index e224e30b1a2a..02c44c3a56d7 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -285,7 +285,10 @@ declare_features! ( // Allows the sysV64 ABI to be specified on all platforms // instead of just the platforms on which it is the C ABI - (active, abi_sysv64, "1.13.0", Some(36167)) + (active, abi_sysv64, "1.13.0", Some(36167)), + + // Use the import semantics from RFC 1560. + (active, item_like_imports, "1.13.0", Some(35120)) ); declare_features! ( From efc0bea687a6c412b7d11acab12ada8e33050089 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Sat, 20 Aug 2016 00:57:19 +0000 Subject: [PATCH 093/443] item_like_imports: Treat private imports like private items. --- src/librustc_resolve/resolve_imports.rs | 4 +++- src/test/run-pass/imports.rs | 24 ++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 src/test/run-pass/imports.rs diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index f02e9b048dea..d6aae23947f2 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -167,8 +167,10 @@ impl<'a> Resolver<'a> { _ => return Failed(None), // This happens when there is a cycle of imports }; + let new_import_semantics = self.new_import_semantics; let is_disallowed_private_import = |binding: &NameBinding| { - !allow_private_imports && binding.vis != ty::Visibility::Public && binding.is_import() + !new_import_semantics && !allow_private_imports && // disallowed + binding.vis != ty::Visibility::Public && binding.is_import() // non-`pub` import }; if let Some(span) = record_used { diff --git a/src/test/run-pass/imports.rs b/src/test/run-pass/imports.rs new file mode 100644 index 000000000000..900e0b69ebba --- /dev/null +++ b/src/test/run-pass/imports.rs @@ -0,0 +1,24 @@ +// 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. + +#![feature(item_like_imports)] +#![allow(unused)] + +// Like other items, private imports can be imported and used non-lexically in paths. +mod a { + use a as foo; + use self::foo::foo as bar; + + mod b { + use super::bar; + } +} + +fn main() {} From aad1f3cbf3340afd0685b79981a59f0ba3e83116 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Thu, 18 Aug 2016 20:33:24 +0000 Subject: [PATCH 094/443] item_like_imports: Allow glob imports to be shadowed by items and single imports. --- src/librustc_resolve/resolve_imports.rs | 20 +++++++----- src/test/run-pass/imports.rs | 42 +++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 7 deletions(-) diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index d6aae23947f2..c7cb3a351784 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -690,15 +690,21 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { }; // Report conflicts - for duplicate_glob in resolution.duplicate_globs.iter() { - // FIXME #31337: We currently allow items to shadow glob-imported re-exports. - if !binding.is_import() { - if let NameBindingKind::Import { binding, .. } = duplicate_glob.kind { - if binding.is_import() { continue } + if !self.new_import_semantics { + for duplicate_glob in resolution.duplicate_globs.iter() { + // FIXME #31337: We currently allow items to shadow glob-imported re-exports. + if !binding.is_import() { + if let NameBindingKind::Import { binding, .. } = duplicate_glob.kind { + if binding.is_import() { continue } + } } - } - self.report_conflict(module, name, ns, duplicate_glob, binding); + self.report_conflict(module, name, ns, duplicate_glob, binding); + } + } else if binding.is_glob_import() { + for duplicate_glob in resolution.duplicate_globs.iter() { + self.report_conflict(module, name, ns, duplicate_glob, binding); + } } if binding.vis == ty::Visibility::Public && diff --git a/src/test/run-pass/imports.rs b/src/test/run-pass/imports.rs index 900e0b69ebba..df4961c074ae 100644 --- a/src/test/run-pass/imports.rs +++ b/src/test/run-pass/imports.rs @@ -21,4 +21,46 @@ mod a { } } +mod foo { pub fn f() {} } +mod bar { pub fn f() {} } + +pub fn f() -> bool { true } + +// Items and explicit imports shadow globs. +fn g() { + use foo::*; + use bar::*; + fn f() -> bool { true } + let _: bool = f(); +} + +fn h() { + use foo::*; + use bar::*; + use f; + let _: bool = f(); +} + +// Here, there appears to be shadowing but isn't because of namespaces. +mod b { + use foo::*; // This imports `f` in the value namespace. + use super::b as f; // This imports `f` only in the type namespace, + fn test() { self::f(); } // so the glob isn't shadowed. +} + +// Here, there is shadowing in one namespace, but not the other. +mod c { + mod test { + pub fn f() {} + pub mod f {} + } + use self::test::*; // This glob-imports `f` in both namespaces. + mod f { pub fn f() {} } // This shadows the glob only in the value namespace. + + fn test() { + self::f(); // Check that the glob-imported value isn't shadowed. + self::f::f(); // Check that the glob-imported module is shadowed. + } +} + fn main() {} From c56a5afd4d1c4717770efa693e69eead13abee34 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Fri, 19 Aug 2016 22:52:26 +0000 Subject: [PATCH 095/443] item_like_imports: Allow single imports with a given visibility to reexport some (but not all) namespaces with less visibility. --- src/librustc_resolve/resolve_imports.rs | 51 +++++++++++++++++----- src/test/compile-fail/imports/reexports.rs | 37 ++++++++++++++++ 2 files changed, 77 insertions(+), 11 deletions(-) create mode 100644 src/test/compile-fail/imports/reexports.rs diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index c7cb3a351784..7084aa685aec 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -285,13 +285,20 @@ impl<'a> Resolver<'a> { // return the corresponding binding defined by the import directive. fn import(&mut self, binding: &'a NameBinding<'a>, directive: &'a ImportDirective<'a>) -> NameBinding<'a> { + let vis = if binding.pseudo_vis().is_at_least(directive.vis.get(), self) || + !directive.is_glob() && binding.is_extern_crate() { // c.f. `PRIVATE_IN_PUBLIC` + directive.vis.get() + } else { + binding.pseudo_vis() + }; + NameBinding { kind: NameBindingKind::Import { binding: binding, directive: directive, }, span: directive.span, - vis: directive.vis.get(), + vis: vis, } } @@ -597,22 +604,44 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { } } + let session = self.session; + let reexport_error = || { + let msg = format!("`{}` is private, and cannot be reexported", name); + let note_msg = + format!("consider marking `{}` as `pub` in the imported module", name); + struct_span_err!(session, directive.span, E0364, "{}", &msg) + .span_note(directive.span, ¬e_msg) + .emit(); + }; + + let extern_crate_lint = || { + let msg = format!("extern crate `{}` is private, and cannot be reexported \ + (error E0364), consider declaring with `pub`", + name); + session.add_lint(PRIVATE_IN_PUBLIC, directive.id, directive.span, msg); + }; + match (value_result, type_result) { + // With `#![feature(item_like_imports)]`, all namespaces + // must be re-exported with extra visibility for an error to occur. + (Ok(value_binding), Ok(type_binding)) if self.new_import_semantics => { + let vis = directive.vis.get(); + if !value_binding.pseudo_vis().is_at_least(vis, self) && + !type_binding.pseudo_vis().is_at_least(vis, self) { + reexport_error(); + } else if type_binding.is_extern_crate() && + !type_binding.vis.is_at_least(vis, self) { + extern_crate_lint(); + } + } + (Ok(binding), _) if !binding.pseudo_vis().is_at_least(directive.vis.get(), self) => { - let msg = format!("`{}` is private, and cannot be reexported", name); - let note_msg = - format!("consider marking `{}` as `pub` in the imported module", name); - struct_span_err!(self.session, directive.span, E0364, "{}", &msg) - .span_note(directive.span, ¬e_msg) - .emit(); + reexport_error(); } (_, Ok(binding)) if !binding.pseudo_vis().is_at_least(directive.vis.get(), self) => { if binding.is_extern_crate() { - let msg = format!("extern crate `{}` is private, and cannot be reexported \ - (error E0364), consider declaring with `pub`", - name); - self.session.add_lint(PRIVATE_IN_PUBLIC, directive.id, directive.span, msg); + extern_crate_lint(); } else { struct_span_err!(self.session, directive.span, E0365, "`{}` is private, and cannot be reexported", name) diff --git a/src/test/compile-fail/imports/reexports.rs b/src/test/compile-fail/imports/reexports.rs new file mode 100644 index 000000000000..f8dbb4d44488 --- /dev/null +++ b/src/test/compile-fail/imports/reexports.rs @@ -0,0 +1,37 @@ +// 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. + +#![feature(item_like_imports)] + +mod a { + fn foo() {} + mod foo {} + + mod a { + pub use super::foo; //~ ERROR cannot be reexported + } +} + +mod b { + pub fn foo() {} + mod foo { pub struct S; } + + pub mod a { + pub use super::foo; // This is OK since the value `foo` is visible enough. + fn f(_: foo::S) {} // `foo` is imported in the type namespace (but not `pub` reexported). + } +} + +mod c { + // Test that `foo` is not reexported. + use b::a::foo::S; //~ ERROR `foo` +} + +fn main() {} From 097b6d62fc7431b322b46b3a0e9f36134c13dd82 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Sat, 20 Aug 2016 00:23:32 +0000 Subject: [PATCH 096/443] item_like_imports: Allow glob imports with a given visibility to reexport some (but not all) names with less visibility. --- src/librustc_resolve/build_reduced_graph.rs | 7 +++++- src/librustc_resolve/resolve_imports.rs | 25 +++++++++++++++++---- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 83d35095f351..0c7c97037187 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -26,6 +26,8 @@ use rustc::hir::def::*; use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId}; use rustc::ty::{self, VariantKind}; +use std::cell::Cell; + use syntax::ast::Name; use syntax::attr; use syntax::parse::token; @@ -176,7 +178,10 @@ impl<'b> Resolver<'b> { } } ViewPathGlob(_) => { - let subclass = GlobImport { is_prelude: is_prelude }; + let subclass = GlobImport { + is_prelude: is_prelude, + max_vis: Cell::new(ty::Visibility::PrivateExternal), + }; let span = view_path.span; self.add_import_directive(module_path, subclass, span, item.id, vis); } diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 7084aa685aec..189253348b0a 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -52,7 +52,10 @@ pub enum ImportDirectiveSubclass<'a> { value_result: Cell, Determinacy>>, type_result: Cell, Determinacy>>, }, - GlobImport { is_prelude: bool }, + GlobImport { + is_prelude: bool, + max_vis: Cell, // The visibility of the greatest reexport. + }, } impl<'a> ImportDirectiveSubclass<'a> { @@ -276,7 +279,7 @@ impl<'a> Resolver<'a> { } // We don't add prelude imports to the globs since they only affect lexical scopes, // which are not relevant to import resolution. - GlobImport { is_prelude: true } => {} + GlobImport { is_prelude: true, .. } => {} GlobImport { .. } => self.current_module.globs.borrow_mut().push(directive), } } @@ -292,6 +295,12 @@ impl<'a> Resolver<'a> { binding.pseudo_vis() }; + if let GlobImport { ref max_vis, .. } = directive.subclass { + if vis == directive.vis.get() || vis.is_at_least(max_vis.get(), self) { + max_vis.set(vis) + } + } + NameBinding { kind: NameBindingKind::Import { binding: binding, @@ -562,7 +571,15 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { let msg = "Cannot glob-import a module into itself.".into(); return Failed(Some((directive.span, msg))); } - GlobImport { .. } => return Success(()), + GlobImport { is_prelude, ref max_vis } => { + if !is_prelude && + max_vis.get() != ty::Visibility::PrivateExternal && // Allow empty globs. + !max_vis.get().is_at_least(directive.vis.get(), self) { + let msg = "A non-empty glob must import something with the glob's visibility"; + self.session.span_err(directive.span, msg); + } + return Success(()); + } }; for &(ns, result) in &[(ValueNS, value_result), (TypeNS, type_result)] { @@ -677,7 +694,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { return; } else if module.def_id() == directive.parent.def_id() { return; - } else if let GlobImport { is_prelude: true } = directive.subclass { + } else if let GlobImport { is_prelude: true, .. } = directive.subclass { self.prelude = Some(module); return; } From 245a0c5530f8d4d251bcef2d7b8de2fa19f442bf Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Sat, 20 Aug 2016 00:33:06 +0000 Subject: [PATCH 097/443] item_like_imports: Make all visible items glob importable. --- src/librustc_resolve/lib.rs | 4 ++++ src/librustc_resolve/resolve_imports.rs | 10 +++++++--- src/test/compile-fail/imports/reexports.rs | 7 +++++++ 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 8428507e686d..12b708fa1a16 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -3255,6 +3255,10 @@ impl<'a> Resolver<'a> { vis.is_accessible_from(self.current_module.normal_ancestor_id, self) } + fn is_accessible_from(&self, vis: ty::Visibility, module: Module<'a>) -> bool { + vis.is_accessible_from(module.normal_ancestor_id, self) + } + fn report_privacy_errors(&self) { if self.privacy_errors.len() == 0 { return } let mut reported_spans = FnvHashSet(); diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 189253348b0a..4ab4ec4789d0 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -356,8 +356,11 @@ impl<'a> Resolver<'a> { }; // Define `binding` in `module`s glob importers. - if binding.vis == ty::Visibility::Public { - for directive in module.glob_importers.borrow_mut().iter() { + for directive in module.glob_importers.borrow_mut().iter() { + if match self.new_import_semantics { + true => self.is_accessible_from(binding.vis, directive.parent), + false => binding.vis == ty::Visibility::Public, + } { let imported_binding = self.import(binding, directive); let _ = self.try_define(directive.parent, name, ns, imported_binding); } @@ -708,7 +711,8 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { resolution.borrow().binding().map(|binding| (*name, binding)) }).collect::>(); for ((name, ns), binding) in bindings { - if binding.pseudo_vis() == ty::Visibility::Public { + if binding.pseudo_vis() == ty::Visibility::Public || + self.new_import_semantics && self.is_accessible(binding.vis) { let imported_binding = self.import(binding, directive); let _ = self.try_define(directive.parent, name, ns, imported_binding); } diff --git a/src/test/compile-fail/imports/reexports.rs b/src/test/compile-fail/imports/reexports.rs index f8dbb4d44488..fc46b23351ad 100644 --- a/src/test/compile-fail/imports/reexports.rs +++ b/src/test/compile-fail/imports/reexports.rs @@ -16,6 +16,7 @@ mod a { mod a { pub use super::foo; //~ ERROR cannot be reexported + pub use super::*; //~ ERROR must import something with the glob's visibility } } @@ -27,11 +28,17 @@ mod b { pub use super::foo; // This is OK since the value `foo` is visible enough. fn f(_: foo::S) {} // `foo` is imported in the type namespace (but not `pub` reexported). } + + pub mod b { + pub use super::*; // This is also OK since the value `foo` is visible enough. + fn f(_: foo::S) {} // Again, the module `foo` is imported (but not `pub` reexported). + } } mod c { // Test that `foo` is not reexported. use b::a::foo::S; //~ ERROR `foo` + use b::b::foo::S as T; //~ ERROR `foo` } fn main() {} From f582fa327e210ea5bf91d6b8f174f35fc9006054 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Sat, 20 Aug 2016 03:28:35 +0000 Subject: [PATCH 098/443] item_like_imports: Allow multiple glob imports of the same item. --- src/librustc_resolve/resolve_imports.rs | 20 +++++++++--- src/test/compile-fail/imports/duplicate.rs | 38 ++++++++++++++++++++++ 2 files changed, 53 insertions(+), 5 deletions(-) create mode 100644 src/test/compile-fail/imports/duplicate.rs diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 4ab4ec4789d0..495bdcb7dfd2 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -317,10 +317,17 @@ impl<'a> Resolver<'a> { where T: ToNameBinding<'a> { let binding = self.arenas.alloc_name_binding(binding.to_name_binding()); - self.update_resolution(module, name, ns, |_, resolution| { + self.update_resolution(module, name, ns, |this, resolution| { if let Some(old_binding) = resolution.binding { if binding.is_glob_import() { - resolution.duplicate_globs.push(binding); + if !this.new_import_semantics || !old_binding.is_glob_import() { + resolution.duplicate_globs.push(binding); + } else if binding.def() != old_binding.def() { + resolution.duplicate_globs.push(binding); + } else if !old_binding.vis.is_at_least(binding.vis, this) { + // We are glob-importing the same item but with greater visibility. + resolution.binding = Some(binding); + } } else if old_binding.is_glob_import() { resolution.duplicate_globs.push(old_binding); resolution.binding = Some(binding); @@ -344,14 +351,17 @@ impl<'a> Resolver<'a> { // during which the resolution might end up getting re-defined via a glob cycle. let (binding, t) = { let mut resolution = &mut *self.resolution(module, name, ns).borrow_mut(); - let was_known = resolution.binding().is_some(); + let old_binding = resolution.binding(); let t = f(self, resolution); - if was_known { return t; } match resolution.binding() { - Some(binding) => (binding, t), + _ if !self.new_import_semantics && old_binding.is_some() => return t, None => return t, + Some(binding) => match old_binding { + Some(old_binding) if old_binding as *const _ == binding as *const _ => return t, + _ => (binding, t), + } } }; diff --git a/src/test/compile-fail/imports/duplicate.rs b/src/test/compile-fail/imports/duplicate.rs new file mode 100644 index 000000000000..0b5963dd8931 --- /dev/null +++ b/src/test/compile-fail/imports/duplicate.rs @@ -0,0 +1,38 @@ +// 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. + +#![feature(item_like_imports)] + +mod a { + pub fn foo() {} +} + +mod b { + pub fn foo() {} +} + +mod c { + pub use a::foo; +} + +mod d { + use a::foo; //~ NOTE previous import + use a::foo; //~ ERROR `foo` has already been imported + //~| NOTE already imported +} + +mod e { + pub use a::*; + pub use c::*; // ok +} + +fn main() { + e::foo(); +} From 681a14f29b5e8d8745bda4fc7ba4d4ccb634ddb9 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Sat, 20 Aug 2016 05:23:19 +0000 Subject: [PATCH 099/443] item_like_imports: Allow unused ambiguous glob imports. --- src/librustc_resolve/lib.rs | 34 ++++++++++++++++++++-- src/librustc_resolve/resolve_imports.rs | 31 +++++++++++++++----- src/test/compile-fail/imports/duplicate.rs | 14 +++++++++ src/test/run-pass/imports.rs | 10 +++++++ 4 files changed, 79 insertions(+), 10 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 12b708fa1a16..d77258f44eb9 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -874,6 +874,10 @@ enum NameBindingKind<'a> { binding: &'a NameBinding<'a>, directive: &'a ImportDirective<'a>, }, + Ambiguity { + b1: &'a NameBinding<'a>, + b2: &'a NameBinding<'a>, + } } #[derive(Clone, Debug)] @@ -885,6 +889,7 @@ impl<'a> NameBinding<'a> { NameBindingKind::Module(module) => Some(module), NameBindingKind::Def(_) => None, NameBindingKind::Import { binding, .. } => binding.module(), + NameBindingKind::Ambiguity { .. } => None, } } @@ -893,6 +898,7 @@ impl<'a> NameBinding<'a> { NameBindingKind::Def(def) => def, NameBindingKind::Module(module) => module.def.unwrap(), NameBindingKind::Import { binding, .. } => binding.def(), + NameBindingKind::Ambiguity { .. } => Def::Err, } } @@ -922,6 +928,7 @@ impl<'a> NameBinding<'a> { fn is_glob_import(&self) -> bool { match self.kind { NameBindingKind::Import { directive, .. } => directive.is_glob(), + NameBindingKind::Ambiguity { .. } => true, _ => false, } } @@ -932,6 +939,14 @@ impl<'a> NameBinding<'a> { _ => true, } } + + fn ambiguity(&self) -> Option<(&'a NameBinding<'a>, &'a NameBinding<'a>)> { + match self.kind { + NameBindingKind::Ambiguity { b1, b2 } => Some((b1, b2)), + NameBindingKind::Import { binding, .. } => binding.ambiguity(), + _ => None, + } + } } /// Interns the names of the primitive types. @@ -1249,7 +1264,8 @@ impl<'a> Resolver<'a> { match ns { ValueNS => &mut self.value_ribs, TypeNS => &mut self.type_ribs } } - fn record_use(&mut self, name: Name, ns: Namespace, binding: &'a NameBinding<'a>) { + fn record_use(&mut self, name: Name, ns: Namespace, binding: &'a NameBinding<'a>, span: Span) + -> bool /* true if an error was reported */ { // track extern crates for unused_extern_crate lint if let Some(DefId { krate, .. }) = binding.module().and_then(ModuleS::def_id) { self.used_crates.insert(krate); @@ -1259,6 +1275,19 @@ impl<'a> Resolver<'a> { self.used_imports.insert((directive.id, ns)); self.add_to_glob_map(directive.id, name); } + + if let Some((b1, b2)) = binding.ambiguity() { + let msg1 = format!("`{}` could resolve to the name imported here", name); + let msg2 = format!("`{}` could also resolve to the name imported here", name); + self.session.struct_span_err(span, &format!("`{}` is ambiguous", name)) + .span_note(b1.span, &msg1) + .span_note(b2.span, &msg2) + .note(&format!("Consider adding an explicit import of `{}` to disambiguate", name)) + .emit(); + return true; + } + + false } fn add_to_glob_map(&mut self, id: NodeId, name: Name) { @@ -2294,7 +2323,8 @@ impl<'a> Resolver<'a> { Def::Struct(..) | Def::Variant(..) | Def::Const(..) | Def::AssociatedConst(..) if !always_binding => { // A constant, unit variant, etc pattern. - self.record_use(ident.node.name, ValueNS, binding.unwrap()); + let name = ident.node.name; + self.record_use(name, ValueNS, binding.unwrap(), ident.span); Some(PathResolution::new(def)) } Def::Struct(..) | Def::Variant(..) | diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 495bdcb7dfd2..cb89231fc055 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -181,7 +181,9 @@ impl<'a> Resolver<'a> { if is_disallowed_private_import(binding) { return Failed(None); } - self.record_use(name, ns, binding); + if self.record_use(name, ns, binding, span) { + return Success(self.dummy_binding); + } if !self.is_accessible(binding.vis) { self.privacy_errors.push(PrivacyError(span, name, binding)); } @@ -323,7 +325,18 @@ impl<'a> Resolver<'a> { if !this.new_import_semantics || !old_binding.is_glob_import() { resolution.duplicate_globs.push(binding); } else if binding.def() != old_binding.def() { - resolution.duplicate_globs.push(binding); + resolution.binding = Some(this.arenas.alloc_name_binding(NameBinding { + kind: NameBindingKind::Ambiguity { + b1: old_binding, + b2: binding, + }, + vis: if old_binding.vis.is_at_least(binding.vis, this) { + old_binding.vis + } else { + binding.vis + }, + span: old_binding.span, + })); } else if !old_binding.vis.is_at_least(binding.vis, this) { // We are glob-importing the same item but with greater visibility. resolution.binding = Some(binding); @@ -597,7 +610,10 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { for &(ns, result) in &[(ValueNS, value_result), (TypeNS, type_result)] { if let Ok(binding) = result { - self.record_use(name, ns, binding); + if self.record_use(name, ns, binding, directive.span) { + self.resolution(module, name, ns).borrow_mut().binding = + Some(self.dummy_binding); + } } } @@ -759,17 +775,16 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { } } - self.report_conflict(module, name, ns, duplicate_glob, binding); - } - } else if binding.is_glob_import() { - for duplicate_glob in resolution.duplicate_globs.iter() { self.report_conflict(module, name, ns, duplicate_glob, binding); } } if binding.vis == ty::Visibility::Public && (binding.is_import() || binding.is_extern_crate()) { - reexports.push(Export { name: name, def_id: binding.def().def_id() }); + let def = binding.def(); + if def != Def::Err { + reexports.push(Export { name: name, def_id: def.def_id() }); + } } if let NameBindingKind::Import { binding: orig_binding, directive, .. } = binding.kind { diff --git a/src/test/compile-fail/imports/duplicate.rs b/src/test/compile-fail/imports/duplicate.rs index 0b5963dd8931..05c0d9cd38e8 100644 --- a/src/test/compile-fail/imports/duplicate.rs +++ b/src/test/compile-fail/imports/duplicate.rs @@ -33,6 +33,20 @@ mod e { pub use c::*; // ok } +mod f { + pub use a::*; //~ NOTE `foo` could resolve to the name imported here + pub use b::*; //~ NOTE `foo` could also resolve to the name imported here +} + +mod g { + pub use a::*; //~ NOTE `foo` could resolve to the name imported here + pub use f::*; //~ NOTE `foo` could also resolve to the name imported here +} + fn main() { e::foo(); + f::foo(); //~ ERROR `foo` is ambiguous + //~| NOTE Consider adding an explicit import of `foo` to disambiguate + g::foo(); //~ ERROR `foo` is ambiguous + //~| NOTE Consider adding an explicit import of `foo` to disambiguate } diff --git a/src/test/run-pass/imports.rs b/src/test/run-pass/imports.rs index df4961c074ae..195b99c9788e 100644 --- a/src/test/run-pass/imports.rs +++ b/src/test/run-pass/imports.rs @@ -63,4 +63,14 @@ mod c { } } +// Unused names can be ambiguous. +mod d { + pub use foo::*; // This imports `f` in the value namespace. + pub use bar::*; // This also imports `f` in the value namespace. +} + +mod e { + pub use d::*; // n.b. Since `e::f` is not used, this is not considered to be a use of `d::f`. +} + fn main() {} From 32a0cfeb485f2c1bbfe52eaa9e119e974e38f21f Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Mon, 22 Aug 2016 08:30:07 +0000 Subject: [PATCH 100/443] Avoid reporting multiple ambiguity errors for a single use of a name. --- src/librustc_resolve/lib.rs | 30 ++++++++++++++-------- src/test/compile-fail/imports/duplicate.rs | 13 ++++++++++ 2 files changed, 32 insertions(+), 11 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index d77258f44eb9..a881feaa4d35 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1065,6 +1065,7 @@ pub struct Resolver<'a> { pub maybe_unused_trait_imports: NodeSet, privacy_errors: Vec>, + ambiguity_errors: Vec<(Span, Name, &'a NameBinding<'a>)>, arenas: &'a ResolverArenas<'a>, dummy_binding: &'a NameBinding<'a>, @@ -1218,6 +1219,7 @@ impl<'a> Resolver<'a> { maybe_unused_trait_imports: NodeSet(), privacy_errors: Vec::new(), + ambiguity_errors: Vec::new(), arenas: arenas, dummy_binding: arenas.alloc_name_binding(NameBinding { @@ -1245,7 +1247,7 @@ impl<'a> Resolver<'a> { visit::walk_crate(self, krate); check_unused::check_crate(self, krate); - self.report_privacy_errors(); + self.report_errors(); } fn new_module(&self, parent_link: ParentLink<'a>, def: Option, normal_ancestor_id: NodeId) @@ -1276,14 +1278,8 @@ impl<'a> Resolver<'a> { self.add_to_glob_map(directive.id, name); } - if let Some((b1, b2)) = binding.ambiguity() { - let msg1 = format!("`{}` could resolve to the name imported here", name); - let msg2 = format!("`{}` could also resolve to the name imported here", name); - self.session.struct_span_err(span, &format!("`{}` is ambiguous", name)) - .span_note(b1.span, &msg1) - .span_note(b2.span, &msg2) - .note(&format!("Consider adding an explicit import of `{}` to disambiguate", name)) - .emit(); + if binding.ambiguity().is_some() { + self.ambiguity_errors.push((span, name, binding)); return true; } @@ -3289,9 +3285,21 @@ impl<'a> Resolver<'a> { vis.is_accessible_from(module.normal_ancestor_id, self) } - fn report_privacy_errors(&self) { - if self.privacy_errors.len() == 0 { return } + fn report_errors(&self) { let mut reported_spans = FnvHashSet(); + + for &(span, name, binding) in &self.ambiguity_errors { + if !reported_spans.insert(span) { continue } + let (b1, b2) = binding.ambiguity().unwrap(); + let msg1 = format!("`{}` could resolve to the name imported here", name); + let msg2 = format!("`{}` could also resolve to the name imported here", name); + self.session.struct_span_err(span, &format!("`{}` is ambiguous", name)) + .span_note(b1.span, &msg1) + .span_note(b2.span, &msg2) + .note(&format!("Consider adding an explicit import of `{}` to disambiguate", name)) + .emit(); + } + for &PrivacyError(span, name, binding) in &self.privacy_errors { if !reported_spans.insert(span) { continue } if binding.is_extern_crate() { diff --git a/src/test/compile-fail/imports/duplicate.rs b/src/test/compile-fail/imports/duplicate.rs index 05c0d9cd38e8..70936b254464 100644 --- a/src/test/compile-fail/imports/duplicate.rs +++ b/src/test/compile-fail/imports/duplicate.rs @@ -50,3 +50,16 @@ fn main() { g::foo(); //~ ERROR `foo` is ambiguous //~| NOTE Consider adding an explicit import of `foo` to disambiguate } + +mod ambiguous_module_errors { + pub mod m1 { pub use super::m1 as foo; } + pub mod m2 { pub use super::m2 as foo; } + + use self::m1::*; //~ NOTE + use self::m2::*; //~ NOTE + + fn f() { + foo::bar(); //~ ERROR `foo` is ambiguous + //~| NOTE + } +} From 4f5616e3c43f866f4758a21f67d98da52b89ee20 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Mon, 22 Aug 2016 07:12:13 +0000 Subject: [PATCH 101/443] Avoid cascading name resolution errors caused by an ambiguous module. --- src/librustc_resolve/lib.rs | 68 +++++++++++++--------- src/librustc_resolve/resolve_imports.rs | 2 +- src/test/compile-fail/imports/duplicate.rs | 5 ++ 3 files changed, 45 insertions(+), 30 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index a881feaa4d35..0fe7f9ed2154 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -749,10 +749,6 @@ impl<'a> LexicalScopeBinding<'a> { _ => None, } } - - fn module(self) -> Option> { - self.item().and_then(NameBinding::module) - } } /// The link from a module up to its nearest parent node. @@ -884,12 +880,13 @@ enum NameBindingKind<'a> { struct PrivacyError<'a>(Span, Name, &'a NameBinding<'a>); impl<'a> NameBinding<'a> { - fn module(&self) -> Option> { + fn module(&self) -> Result, bool /* true if an error has already been reported */> { match self.kind { - NameBindingKind::Module(module) => Some(module), - NameBindingKind::Def(_) => None, + NameBindingKind::Module(module) => Ok(module), NameBindingKind::Import { binding, .. } => binding.module(), - NameBindingKind::Ambiguity { .. } => None, + NameBindingKind::Def(Def::Err) => Err(true), + NameBindingKind::Def(_) => Err(false), + NameBindingKind::Ambiguity { .. } => Err(false), } } @@ -915,7 +912,7 @@ impl<'a> NameBinding<'a> { } fn is_extern_crate(&self) -> bool { - self.module().and_then(|module| module.extern_crate_id).is_some() + self.module().ok().and_then(|module| module.extern_crate_id).is_some() } fn is_import(&self) -> bool { @@ -1269,7 +1266,7 @@ impl<'a> Resolver<'a> { fn record_use(&mut self, name: Name, ns: Namespace, binding: &'a NameBinding<'a>, span: Span) -> bool /* true if an error was reported */ { // track extern crates for unused_extern_crate lint - if let Some(DefId { krate, .. }) = binding.module().and_then(ModuleS::def_id) { + if let Some(DefId { krate, .. }) = binding.module().ok().and_then(ModuleS::def_id) { self.used_crates.insert(krate); } @@ -1292,6 +1289,18 @@ impl<'a> Resolver<'a> { } } + fn expect_module(&mut self, name: Name, binding: &'a NameBinding<'a>, span: Option) + -> ResolveResult> { + match binding.module() { + Ok(module) => Success(module), + Err(true) => Failed(None), + Err(false) => { + let msg = format!("Not a module `{}`", name); + Failed(span.map(|span| (span, msg))) + } + } + } + /// Resolves the given module path from the given root `search_module`. fn resolve_module_path_from_root(&mut self, mut search_module: Module<'a>, @@ -1357,11 +1366,9 @@ impl<'a> Resolver<'a> { Success(binding) => { // Check to see whether there are type bindings, and, if // so, whether there is a module within. - if let Some(module_def) = binding.module() { - search_module = module_def; - } else { - let msg = format!("Not a module `{}`", name); - return Failed(span.map(|span| (span, msg))); + match self.expect_module(name, binding, span) { + Success(module) => search_module = module, + result @ _ => return result, } } } @@ -1414,17 +1421,20 @@ impl<'a> Resolver<'a> { // first component of the path in the current lexical // scope and then proceed to resolve below that. let ident = ast::Ident::with_empty_ctxt(module_path[0]); - match self.resolve_ident_in_lexical_scope(ident, TypeNS, span) - .and_then(LexicalScopeBinding::module) { - None => { - let msg = - format!("Use of undeclared type or module `{}`", ident.name); - return Failed(span.map(|span| (span, msg))); - } - Some(containing_module) => { - search_module = containing_module; - start_index = 1; + let lexical_binding = + self.resolve_ident_in_lexical_scope(ident, TypeNS, span); + if let Some(binding) = lexical_binding.and_then(LexicalScopeBinding::item) { + match self.expect_module(ident.name, binding, span) { + Success(containing_module) => { + search_module = containing_module; + start_index = 1; + } + result @ _ => return result, } + } else { + let msg = + format!("Use of undeclared type or module `{}`", ident.name); + return Failed(span.map(|span| (span, msg))); } } } @@ -3202,7 +3212,7 @@ impl<'a> Resolver<'a> { } // collect submodules to explore - if let Some(module) = name_binding.module() { + if let Ok(module) = name_binding.module() { // form the path let path_segments = match module.parent_link { NoParentLink => path_segments.clone(), @@ -3341,9 +3351,9 @@ impl<'a> Resolver<'a> { let msg = { let kind = match (ns, old_binding.module()) { (ValueNS, _) => "a value", - (TypeNS, Some(module)) if module.extern_crate_id.is_some() => "an extern crate", - (TypeNS, Some(module)) if module.is_normal() => "a module", - (TypeNS, Some(module)) if module.is_trait() => "a trait", + (TypeNS, Ok(module)) if module.extern_crate_id.is_some() => "an extern crate", + (TypeNS, Ok(module)) if module.is_normal() => "a module", + (TypeNS, Ok(module)) if module.is_trait() => "a trait", (TypeNS, _) => "a type", }; format!("{} named `{}` has already been {} in this {}", diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index cb89231fc055..c8982d95d4e0 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -460,7 +460,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { errors = true; let (span, help) = match err { Some((span, msg)) => (span, msg), - None => (import.span, String::new()), + None => continue, }; // If the error is a single failed import then create a "fake" import diff --git a/src/test/compile-fail/imports/duplicate.rs b/src/test/compile-fail/imports/duplicate.rs index 70936b254464..fb61bb8e489b 100644 --- a/src/test/compile-fail/imports/duplicate.rs +++ b/src/test/compile-fail/imports/duplicate.rs @@ -56,7 +56,12 @@ mod ambiguous_module_errors { pub mod m2 { pub use super::m2 as foo; } use self::m1::*; //~ NOTE + //~| NOTE use self::m2::*; //~ NOTE + //~| NOTE + + use self::foo::bar; //~ ERROR `foo` is ambiguous + //~| NOTE fn f() { foo::bar(); //~ ERROR `foo` is ambiguous From 7cd4e7ff0b2e0872ed5dac00f3b680e7dbc3d24b Mon Sep 17 00:00:00 2001 From: Eugene R Gonzalez Date: Thu, 1 Sep 2016 18:46:30 -0400 Subject: [PATCH 102/443] Fixed E0528 label and unit test --- src/librustc_typeck/check/_match.rs | 9 ++++++--- src/test/compile-fail/E0528.rs | 4 +++- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 225468cb9f40..e1ce89f0ab5d 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -248,9 +248,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } else if let Some(rest) = size.checked_sub(min_len) { (inner_ty, tcx.mk_array(inner_ty, rest)) } else { - span_err!(tcx.sess, pat.span, E0528, - "pattern requires at least {} elements but array has {}", - min_len, size); + struct_span_err!(tcx.sess, pat.span, E0528, + "pattern requires at least {} elements but array has {}", + min_len, size) + .span_label(pat.span, + &format!("pattern cannot match array of {} elements", size)) + .emit(); (inner_ty, tcx.types.err) } } diff --git a/src/test/compile-fail/E0528.rs b/src/test/compile-fail/E0528.rs index 27187bb5aba0..e912650f1129 100644 --- a/src/test/compile-fail/E0528.rs +++ b/src/test/compile-fail/E0528.rs @@ -13,7 +13,9 @@ fn main() { let r = &[1, 2]; match r { - &[a, b, c, rest..] => { //~ ERROR E0528 + &[a, b, c, rest..] => { + //~^ ERROR E0528 + //~| NOTE pattern cannot match array of 2 elements } } } From 96283fc08367ae8c3d344f2342c4ebe11d799092 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 1 Sep 2016 10:52:44 -0700 Subject: [PATCH 103/443] test: Add a min-llvm-version directive We've got tests which require a particular version of LLVM to run as they're testing bug fixes. Our build system, however, supports multiple LLVM versions, so we can't run these tests on all LLVM versions. This adds a new `min-llvm-version` directive for tests so they can opt out of being run on older versions of LLVM. This then namely applies that logic to the `issue-36023.rs` test case and... Closes #36138 --- mk/main.mk | 1 + mk/tests.mk | 1 + src/bootstrap/check.rs | 4 +++- src/test/run-pass/issue-36023.rs | 2 ++ src/tools/compiletest/src/common.rs | 3 +++ src/tools/compiletest/src/header.rs | 22 +++++++++++++++++++++- src/tools/compiletest/src/main.rs | 2 ++ 7 files changed, 33 insertions(+), 2 deletions(-) diff --git a/mk/main.mk b/mk/main.mk index 5a849af9856f..6130b5813875 100644 --- a/mk/main.mk +++ b/mk/main.mk @@ -348,6 +348,7 @@ LLVM_AS_$(1)=$$(CFG_LLVM_INST_DIR_$(1))/bin/llvm-as$$(X_$(1)) LLC_$(1)=$$(CFG_LLVM_INST_DIR_$(1))/bin/llc$$(X_$(1)) LLVM_ALL_COMPONENTS_$(1)=$$(shell "$$(LLVM_CONFIG_$(1))" --components) +LLVM_VERSION_$(1)=$$(shell "$$(LLVM_CONFIG_$(1))" --version) endef diff --git a/mk/tests.mk b/mk/tests.mk index 201e4cae51d6..c135aa9b8fb9 100644 --- a/mk/tests.mk +++ b/mk/tests.mk @@ -649,6 +649,7 @@ CTEST_COMMON_ARGS$(1)-T-$(2)-H-$(3) = \ --lldb-python $$(CFG_LLDB_PYTHON) \ --gdb-version="$(CFG_GDB_VERSION)" \ --lldb-version="$(CFG_LLDB_VERSION)" \ + --llvm-version="$$(LLVM_VERSION_$(3))" \ --android-cross-path=$(CFG_ARM_LINUX_ANDROIDEABI_NDK) \ --adb-path=$(CFG_ADB) \ --adb-test-dir=$(CFG_ADB_TEST_DIR) \ diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index 3d8b1438125e..2b9d717cbd48 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -148,6 +148,9 @@ pub fn compiletest(build: &Build, if let Some(ref dir) = build.lldb_python_dir { cmd.arg("--lldb-python-dir").arg(dir); } + let llvm_config = build.llvm_config(target); + let llvm_version = output(Command::new(&llvm_config).arg("--version")); + cmd.arg("--llvm-version").arg(llvm_version); cmd.args(&build.flags.args); @@ -158,7 +161,6 @@ pub fn compiletest(build: &Build, // Only pass correct values for these flags for the `run-make` suite as it // requires that a C++ compiler was configured which isn't always the case. if suite == "run-make" { - let llvm_config = build.llvm_config(target); let llvm_components = output(Command::new(&llvm_config).arg("--components")); let llvm_cxxflags = output(Command::new(&llvm_config).arg("--cxxflags")); cmd.arg("--cc").arg(build.cc(target)) diff --git a/src/test/run-pass/issue-36023.rs b/src/test/run-pass/issue-36023.rs index f6c03b384f23..53a8a403b641 100644 --- a/src/test/run-pass/issue-36023.rs +++ b/src/test/run-pass/issue-36023.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// min-llvm-version 3.9 + use std::ops::Deref; fn main() { diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 6090cb4f5272..5d522736089e 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -152,6 +152,9 @@ pub struct Config { // Version of LLDB pub lldb_version: Option, + // Version of LLVM + pub llvm_version: Option, + // Path to the android tools pub android_cross_path: PathBuf, diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index af33d76be1b0..899a366a4bb7 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -44,7 +44,9 @@ impl EarlyProps { (config.mode == common::Pretty && parse_name_directive(ln, "ignore-pretty")) || (config.target != config.host && parse_name_directive(ln, "ignore-cross-compile")) || - ignore_gdb(config, ln) || ignore_lldb(config, ln); + ignore_gdb(config, ln) || + ignore_lldb(config, ln) || + ignore_llvm(config, ln); props.should_fail = props.should_fail || parse_name_directive(ln, "should-fail"); }); @@ -115,6 +117,24 @@ impl EarlyProps { false } } + + fn ignore_llvm(config: &Config, line: &str) -> bool { + if let Some(ref actual_version) = config.llvm_version { + if line.contains("min-llvm-version") { + let min_version = line.trim() + .split(' ') + .last() + .expect("Malformed llvm version directive"); + // Ignore if actual version is smaller the minimum required + // version + &actual_version[..] < min_version + } else { + false + } + } else { + false + } + } } } diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs index 90641b5c476d..4afeb3613319 100644 --- a/src/tools/compiletest/src/main.rs +++ b/src/tools/compiletest/src/main.rs @@ -99,6 +99,7 @@ pub fn parse_config(args: Vec ) -> Config { optopt("", "host", "the host to build for", "HOST"), optopt("", "gdb-version", "the version of GDB used", "VERSION STRING"), optopt("", "lldb-version", "the version of LLDB used", "VERSION STRING"), + optopt("", "llvm-version", "the version of LLVM used", "VERSION STRING"), optopt("", "android-cross-path", "Android NDK standalone path", "PATH"), optopt("", "adb-path", "path to the android debugger", "PATH"), optopt("", "adb-test-dir", "path to tests for the android debugger", "PATH"), @@ -170,6 +171,7 @@ pub fn parse_config(args: Vec ) -> Config { host: opt_str2(matches.opt_str("host")), gdb_version: extract_gdb_version(matches.opt_str("gdb-version")), lldb_version: extract_lldb_version(matches.opt_str("lldb-version")), + llvm_version: matches.opt_str("llvm-version"), android_cross_path: opt_path(matches, "android-cross-path"), adb_path: opt_str2(matches.opt_str("adb-path")), adb_test_dir: format!("{}/{}", From 90ce504c1c3dc014ca8e0aa91e21c46569a9d4ab Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Mon, 29 Aug 2016 05:29:01 +0000 Subject: [PATCH 104/443] Address comments. --- src/librustc_resolve/build_reduced_graph.rs | 8 ++--- src/librustc_resolve/lib.rs | 34 ++++++++++++--------- src/librustc_resolve/resolve_imports.rs | 1 + src/test/run-pass/imports.rs | 2 ++ 4 files changed, 27 insertions(+), 18 deletions(-) diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 0c7c97037187..3e9b37f0a95a 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -32,7 +32,7 @@ use syntax::ast::Name; use syntax::attr; use syntax::parse::token; -use syntax::ast::{Block, Crate, DUMMY_NODE_ID}; +use syntax::ast::{Block, Crate}; use syntax::ast::{ForeignItem, ForeignItemKind, Item, ItemKind}; use syntax::ast::{Mutability, StmtKind, TraitItemKind}; use syntax::ast::{Variant, ViewPathGlob, ViewPathList, ViewPathSimple}; @@ -208,7 +208,7 @@ impl<'b> Resolver<'b> { ItemKind::Mod(..) => { let parent_link = ModuleParentLink(parent, name); let def = Def::Mod(self.definitions.local_def_id(item.id)); - let module = self.new_module(parent_link, Some(def), item.id); + let module = self.new_module(parent_link, Some(def), Some(item.id)); module.no_implicit_prelude.set({ parent.no_implicit_prelude.get() || attr::contains_name(&item.attrs, "no_implicit_prelude") @@ -398,7 +398,7 @@ impl<'b> Resolver<'b> { debug!("(building reduced graph for external crate) building module {} {:?}", name, vis); let parent_link = ModuleParentLink(parent, name); - let module = self.new_module(parent_link, Some(def), DUMMY_NODE_ID); + let module = self.new_module(parent_link, Some(def), None); let _ = self.try_define(parent, name, TypeNS, (module, DUMMY_SP, vis)); } Def::Variant(_, variant_id) => { @@ -440,7 +440,7 @@ impl<'b> Resolver<'b> { } let parent_link = ModuleParentLink(parent, name); - let module = self.new_module(parent_link, Some(def), DUMMY_NODE_ID); + let module = self.new_module(parent_link, Some(def), None); let _ = self.try_define(parent, name, TypeNS, (module, DUMMY_SP, vis)); } Def::TyAlias(..) | Def::AssociatedTy(..) => { diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 0fe7f9ed2154..1224c694a4e6 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -54,7 +54,7 @@ use rustc::util::nodemap::{NodeMap, NodeSet, FnvHashMap, FnvHashSet}; use syntax::ext::hygiene::Mark; use syntax::ast::{self, FloatTy}; -use syntax::ast::{CRATE_NODE_ID, DUMMY_NODE_ID, Name, NodeId, CrateNum, IntTy, UintTy}; +use syntax::ast::{CRATE_NODE_ID, Name, NodeId, CrateNum, IntTy, UintTy}; use syntax::parse::token::{self, keywords}; use syntax::util::lev_distance::find_best_match_for_name; @@ -765,7 +765,7 @@ pub struct ModuleS<'a> { def: Option, // The node id of the closest normal module (`mod`) ancestor (including this module). - normal_ancestor_id: NodeId, + normal_ancestor_id: Option, // If the module is an extern crate, `def` is root of the external crate and `extern_crate_id` // is the NodeId of the local `extern crate` item (otherwise, `extern_crate_id` is None). @@ -790,7 +790,8 @@ pub struct ModuleS<'a> { pub type Module<'a> = &'a ModuleS<'a>; impl<'a> ModuleS<'a> { - fn new(parent_link: ParentLink<'a>, def: Option, normal_ancestor_id: NodeId) -> Self { + fn new(parent_link: ParentLink<'a>, def: Option, normal_ancestor_id: Option) + -> Self { ModuleS { parent_link: parent_link, def: def, @@ -801,7 +802,7 @@ impl<'a> ModuleS<'a> { glob_importers: RefCell::new(Vec::new()), globs: RefCell::new((Vec::new())), traits: RefCell::new(None), - populated: Cell::new(normal_ancestor_id != DUMMY_NODE_ID), + populated: Cell::new(normal_ancestor_id.is_some()), } } @@ -1104,7 +1105,7 @@ impl<'a> ty::NodeIdTree for Resolver<'a> { fn is_descendant_of(&self, mut node: NodeId, ancestor: NodeId) -> bool { while node != ancestor { node = match self.module_map[&node].parent() { - Some(parent) => parent.normal_ancestor_id, + Some(parent) => parent.normal_ancestor_id.unwrap(), None => return false, } } @@ -1168,7 +1169,8 @@ impl<'a> Resolver<'a> { pub fn new(session: &'a Session, make_glob_map: MakeGlobMap, arenas: &'a ResolverArenas<'a>) -> Resolver<'a> { let root_def_id = DefId::local(CRATE_DEF_INDEX); - let graph_root = ModuleS::new(NoParentLink, Some(Def::Mod(root_def_id)), CRATE_NODE_ID); + let graph_root = + ModuleS::new(NoParentLink, Some(Def::Mod(root_def_id)), Some(CRATE_NODE_ID)); let graph_root = arenas.alloc_module(graph_root); let mut module_map = NodeMap(); module_map.insert(CRATE_NODE_ID, graph_root); @@ -1247,14 +1249,17 @@ impl<'a> Resolver<'a> { self.report_errors(); } - fn new_module(&self, parent_link: ParentLink<'a>, def: Option, normal_ancestor_id: NodeId) + fn new_module(&self, + parent_link: ParentLink<'a>, + def: Option, + normal_ancestor_id: Option) -> Module<'a> { self.arenas.alloc_module(ModuleS::new(parent_link, def, normal_ancestor_id)) } fn new_extern_crate_module(&self, parent_link: ParentLink<'a>, def: Def, local_node_id: NodeId) -> Module<'a> { - let mut module = ModuleS::new(parent_link, Some(def), local_node_id); + let mut module = ModuleS::new(parent_link, Some(def), Some(local_node_id)); module.extern_crate_id = Some(local_node_id); self.arenas.modules.alloc(module) } @@ -1530,14 +1535,15 @@ impl<'a> Resolver<'a> { _ => return Success(NoPrefixFound), }; - let mut containing_module = self.module_map[&self.current_module.normal_ancestor_id]; + let mut containing_module = + self.module_map[&self.current_module.normal_ancestor_id.unwrap()]; // Now loop through all the `super`s we find. while i < module_path.len() && "super" == module_path[i].as_str() { debug!("(resolving module prefix) resolving `super` at {}", module_to_string(&containing_module)); if let Some(parent) = containing_module.parent() { - containing_module = self.module_map[&parent.normal_ancestor_id]; + containing_module = self.module_map[&parent.normal_ancestor_id.unwrap()]; i += 1; } else { let msg = "There are too many initial `super`s.".into(); @@ -3260,7 +3266,7 @@ impl<'a> Resolver<'a> { ast::Visibility::Crate(_) => return ty::Visibility::Restricted(ast::CRATE_NODE_ID), ast::Visibility::Restricted { ref path, id } => (path, id), ast::Visibility::Inherited => { - return ty::Visibility::Restricted(self.current_module.normal_ancestor_id); + return ty::Visibility::Restricted(self.current_module.normal_ancestor_id.unwrap()); } }; @@ -3269,7 +3275,7 @@ impl<'a> Resolver<'a> { let vis = match self.resolve_module_path(&segments, DontUseLexicalScope, Some(path.span)) { Success(module) => { path_resolution = PathResolution::new(module.def.unwrap()); - ty::Visibility::Restricted(module.normal_ancestor_id) + ty::Visibility::Restricted(module.normal_ancestor_id.unwrap()) } Indeterminate => unreachable!(), Failed(err) => { @@ -3288,11 +3294,11 @@ impl<'a> Resolver<'a> { } fn is_accessible(&self, vis: ty::Visibility) -> bool { - vis.is_accessible_from(self.current_module.normal_ancestor_id, self) + vis.is_accessible_from(self.current_module.normal_ancestor_id.unwrap(), self) } fn is_accessible_from(&self, vis: ty::Visibility, module: Module<'a>) -> bool { - vis.is_accessible_from(module.normal_ancestor_id, self) + vis.is_accessible_from(module.normal_ancestor_id.unwrap(), self) } fn report_errors(&self) { diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index c8982d95d4e0..875d6745f6b2 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -55,6 +55,7 @@ pub enum ImportDirectiveSubclass<'a> { GlobImport { is_prelude: bool, max_vis: Cell, // The visibility of the greatest reexport. + // n.b. `max_vis` is only used in `finalize_import` to check for reexport errors. }, } diff --git a/src/test/run-pass/imports.rs b/src/test/run-pass/imports.rs index 195b99c9788e..9851dfe0262f 100644 --- a/src/test/run-pass/imports.rs +++ b/src/test/run-pass/imports.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-pretty : (#23623) problems when ending with // comments + #![feature(item_like_imports)] #![allow(unused)] From 7f95bb0dbd70e838d7cc12520135b08853c8b192 Mon Sep 17 00:00:00 2001 From: Eugene R Gonzalez Date: Thu, 1 Sep 2016 22:35:25 -0400 Subject: [PATCH 105/443] Fixed E0529's label and unit test --- src/librustc_typeck/check/_match.rs | 5 ++++- src/test/compile-fail/E0529.rs | 4 +++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 225468cb9f40..1027a3207f0a 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -270,7 +270,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { _ => {} } } - err.emit(); + + err.span_label( pat.span, + &format!("pattern cannot match with input type `{}`", expected_ty) + ).emit(); } (tcx.types.err, tcx.types.err) } diff --git a/src/test/compile-fail/E0529.rs b/src/test/compile-fail/E0529.rs index 488fe7c7763a..18d3e68816aa 100644 --- a/src/test/compile-fail/E0529.rs +++ b/src/test/compile-fail/E0529.rs @@ -13,7 +13,9 @@ fn main() { let r: f32 = 1.0; match r { - [a, b] => { //~ ERROR E0529 + [a, b] => { + //~^ ERROR E0529 + //~| NOTE pattern cannot match with input type `f32` } } } From cd8f0aa7f228fa37084817baba8aba1d96387d89 Mon Sep 17 00:00:00 2001 From: Ahmed Charles Date: Sat, 27 Aug 2016 01:52:32 -0700 Subject: [PATCH 106/443] Remove --{enable|disable}-orbit from configure. Fixes #35956. --- configure | 1 - 1 file changed, 1 deletion(-) diff --git a/configure b/configure index 44fb3d368d2c..c6b6e4da5291 100755 --- a/configure +++ b/configure @@ -609,7 +609,6 @@ opt dist-host-only 0 "only install bins for the host architecture" opt inject-std-version 1 "inject the current compiler version of libstd into programs" opt llvm-version-check 1 "check if the LLVM version is supported, build anyway" opt rustbuild 0 "use the rust and cargo based build system" -opt orbit 1 "get MIR where it belongs - everywhere; most importantly, in orbit" opt codegen-tests 1 "run the src/test/codegen tests" opt option-checking 1 "complain about unrecognized options in this configure script" opt ninja 0 "build LLVM using the Ninja generator (for MSVC, requires building in the correct environment)" From ed5e5df596aff90b4147869e3464330f7833f81e Mon Sep 17 00:00:00 2001 From: Federico Ravasio Date: Fri, 2 Sep 2016 11:44:46 +0200 Subject: [PATCH 107/443] E0493: showing a label where the destructor is defined. --- src/librustc_mir/transform/qualify_consts.rs | 29 ++++++++++++++++++++ src/test/compile-fail/E0493.rs | 9 ++++++ 2 files changed, 38 insertions(+) diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index a6f6faf24696..14a432cbb895 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -18,6 +18,7 @@ use rustc_data_structures::bitvec::BitVector; use rustc_data_structures::indexed_vec::{IndexVec, Idx}; use rustc::dep_graph::DepNode; use rustc::hir; +use rustc::hir::map as hir_map; use rustc::hir::def_id::DefId; use rustc::hir::intravisit::FnKind; use rustc::hir::map::blocks::FnLikeNode; @@ -258,12 +259,40 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> { "in Nightly builds, add `#![feature(drop_types_in_const)]` \ to the crate attributes to enable"); } else { + self.find_drop_implementation_method_span() + .map(|span| err.span_label(span, &format!("destructor defined here"))); + err.span_label(self.span, &format!("constants cannot have destructors")); } err.emit(); } + fn find_drop_implementation_method_span(&self) -> Option { + self.tcx.lang_items + .drop_trait() + .and_then(|drop_trait_id| { + let mut span = None; + + self.tcx + .lookup_trait_def(drop_trait_id) + .for_each_relevant_impl(self.tcx, self.mir.return_ty, |impl_did| { + self.tcx.map + .as_local_node_id(impl_did) + .and_then(|impl_node_id| self.tcx.map.find(impl_node_id)) + .map(|node| { + if let hir_map::NodeItem(item) = node { + if let hir::ItemImpl(_, _, _, _, _, ref methods) = item.node { + span = methods.first().map(|method| method.span); + } + } + }); + }); + + span + }) + } + /// Check if an Lvalue with the current qualifications could /// be consumed, by either an operand or a Deref projection. fn try_consume(&mut self) -> bool { diff --git a/src/test/compile-fail/E0493.rs b/src/test/compile-fail/E0493.rs index d5b29a628f0b..e06da5ca7c55 100644 --- a/src/test/compile-fail/E0493.rs +++ b/src/test/compile-fail/E0493.rs @@ -14,6 +14,15 @@ struct Foo { impl Drop for Foo { fn drop(&mut self) {} + //~^ NOTE destructor defined here +} + +struct Bar { + a: u32 +} + +impl Drop for Bar { + fn drop(&mut self) {} } const F : Foo = Foo { a : 0 }; From 3a96fe32753f0308002e18d165f52d54e5ac64cb Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Wed, 31 Aug 2016 19:10:24 -0400 Subject: [PATCH 108/443] Transition Travis CI to use rustbuild. --- .travis.yml | 4 ++-- src/bootstrap/compile.rs | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 0abd858d8228..c5d8a94f39b0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,9 +15,9 @@ before_install: script: - docker run -v `pwd`:/build rust sh -c " - ./configure --llvm-root=/usr/lib/llvm-3.7 && + ./configure --enable-rustbuild --llvm-root=/usr/lib/llvm-3.7 && make tidy && - make check-notidy -j4 + make check -j4 " # Real testing happens on http://buildbot.rust-lang.org/ diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 155848901cdb..302ac68460c6 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -203,6 +203,10 @@ pub fn rustc<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) { cargo.env("LLVM_RUSTLLVM", "1"); } cargo.env("LLVM_CONFIG", build.llvm_config(target)); + let target_config = build.config.target_config.get(target); + if let Some(s) = target_config.and_then(|c| c.llvm_config.as_ref()) { + cargo.env("CFG_LLVM_ROOT", s); + } if build.config.llvm_static_stdcpp { cargo.env("LLVM_STATIC_STDCPP", compiler_file(build.cxx(target), "libstdc++.a")); From b778f7fa0192ac6863f3ce0ab49d9c4001bf5503 Mon Sep 17 00:00:00 2001 From: Sean McArthur Date: Wed, 31 Aug 2016 16:02:55 -0700 Subject: [PATCH 109/443] core: add likely and unlikely intrinsics --- src/libcore/intrinsics.rs | 14 +++++++++ src/librustc_trans/intrinsic.rs | 8 +++++ src/librustc_typeck/check/intrinsic.rs | 2 ++ src/test/codegen/likely.rs | 41 ++++++++++++++++++++++++++ 4 files changed, 65 insertions(+) create mode 100644 src/test/codegen/likely.rs diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 8271b85b01a3..619656f4d713 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -194,6 +194,20 @@ extern "rust-intrinsic" { /// own, or if it does not enable any significant optimizations. pub fn assume(b: bool); + #[cfg(not(stage0))] + /// Hints to the compiler that branch condition is likely to be true. + /// Returns the value passed to it. + /// + /// Any use other than with `if` statements will probably not have an effect. + pub fn likely(b: bool) -> bool; + + #[cfg(not(stage0))] + /// Hints to the compiler that branch condition is likely to be false. + /// Returns the value passed to it. + /// + /// Any use other than with `if` statements will probably not have an effect. + pub fn unlikely(b: bool) -> bool; + /// Executes a breakpoint trap, for inspection by a debugger. pub fn breakpoint(); diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs index 8bef7584db9e..1ee5db7eafc5 100644 --- a/src/librustc_trans/intrinsic.rs +++ b/src/librustc_trans/intrinsic.rs @@ -136,6 +136,14 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, (Some(llfn), _) => { Call(bcx, llfn, &llargs, call_debug_location) } + (_, "likely") => { + let expect = ccx.get_intrinsic(&("llvm.expect.i1")); + Call(bcx, expect, &[llargs[0], C_bool(ccx, true)], call_debug_location) + } + (_, "unlikely") => { + let expect = ccx.get_intrinsic(&("llvm.expect.i1")); + Call(bcx, expect, &[llargs[0], C_bool(ccx, false)], call_debug_location) + } (_, "try") => { bcx = try_intrinsic(bcx, llargs[0], llargs[1], llargs[2], llresult, call_debug_location); diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index bde7f20f5e6e..ea4b3e924b3b 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -285,6 +285,8 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &hir::ForeignItem) { (1, vec![param(ccx, 0), param(ccx, 0)], param(ccx, 0)), "assume" => (0, vec![tcx.types.bool], tcx.mk_nil()), + "likely" => (0, vec![tcx.types.bool], tcx.types.bool), + "unlikely" => (0, vec![tcx.types.bool], tcx.types.bool), "discriminant_value" => (1, vec![ tcx.mk_imm_ref(tcx.mk_region(ty::ReLateBound(ty::DebruijnIndex::new(1), diff --git a/src/test/codegen/likely.rs b/src/test/codegen/likely.rs new file mode 100644 index 000000000000..acaec0350bfb --- /dev/null +++ b/src/test/codegen/likely.rs @@ -0,0 +1,41 @@ +// 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. + +// compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] +#![feature(core_intrinsics)] + +use std::intrinsics::{likely,unlikely}; + +#[no_mangle] +pub fn check_likely(x: i32, y: i32) -> Option { + unsafe { + // CHECK: call i1 @llvm.expect.i1(i1 %{{.*}}, i1 true) + if likely(x == y) { + None + } else { + Some(x + y) + } + } +} + +#[no_mangle] +pub fn check_unlikely(x: i32, y: i32) -> Option { + unsafe { + // CHECK: call i1 @llvm.expect.i1(i1 %{{.*}}, i1 false) + if unlikely(x == y) { + None + } else { + Some(x + y) + } + } +} + From 059094f3f264a683e624ae57b475264b5ce8511c Mon Sep 17 00:00:00 2001 From: Federico Ravasio Date: Fri, 2 Sep 2016 19:55:14 +0200 Subject: [PATCH 110/443] Moved test on E0493 from compile-fail to ui. --- src/test/{compile-fail => ui/span}/E0493.rs | 3 --- src/test/ui/span/E0493.stderr | 11 +++++++++++ 2 files changed, 11 insertions(+), 3 deletions(-) rename src/test/{compile-fail => ui/span}/E0493.rs (81%) create mode 100644 src/test/ui/span/E0493.stderr diff --git a/src/test/compile-fail/E0493.rs b/src/test/ui/span/E0493.rs similarity index 81% rename from src/test/compile-fail/E0493.rs rename to src/test/ui/span/E0493.rs index e06da5ca7c55..ea4526b70f6a 100644 --- a/src/test/compile-fail/E0493.rs +++ b/src/test/ui/span/E0493.rs @@ -14,7 +14,6 @@ struct Foo { impl Drop for Foo { fn drop(&mut self) {} - //~^ NOTE destructor defined here } struct Bar { @@ -26,8 +25,6 @@ impl Drop for Bar { } const F : Foo = Foo { a : 0 }; -//~^ ERROR constants are not allowed to have destructors [E0493] -//~| NOTE constants cannot have destructors fn main() { } diff --git a/src/test/ui/span/E0493.stderr b/src/test/ui/span/E0493.stderr new file mode 100644 index 000000000000..afcc9a240eb4 --- /dev/null +++ b/src/test/ui/span/E0493.stderr @@ -0,0 +1,11 @@ +error[E0493]: constants are not allowed to have destructors + --> $DIR/E0493.rs:27:17 + | +16 | fn drop(&mut self) {} + | --------------------- destructor defined here +... +27 | const F : Foo = Foo { a : 0 }; + | ^^^^^^^^^^^^^ constants cannot have destructors + +error: aborting due to previous error + From f18c99072e6b9ec0075d913ea6454f0c5e75881c Mon Sep 17 00:00:00 2001 From: Jared Roesch Date: Tue, 16 Aug 2016 18:41:27 -0700 Subject: [PATCH 111/443] Add tests for #29859 --- src/test/compile-fail/issue-29859-2.rs | 25 +++++++++++++++++++++++++ src/test/compile-fail/issue-29859.rs | 25 +++++++++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 src/test/compile-fail/issue-29859-2.rs create mode 100644 src/test/compile-fail/issue-29859.rs diff --git a/src/test/compile-fail/issue-29859-2.rs b/src/test/compile-fail/issue-29859-2.rs new file mode 100644 index 000000000000..c0e50185f939 --- /dev/null +++ b/src/test/compile-fail/issue-29859-2.rs @@ -0,0 +1,25 @@ +// 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. + +#![feature(optin_builtin_traits)] + +trait Magic: Copy {} +impl Magic for .. {} +impl Magic for T {} + +fn copy(x: T) -> (T, T) { (x, x) } + +#[derive(Debug)] +struct NoClone; + +fn main() { + let (a, b) = copy(NoClone); //~ ERROR E0277 + println!("{:?} {:?}", a, b); +} diff --git a/src/test/compile-fail/issue-29859.rs b/src/test/compile-fail/issue-29859.rs new file mode 100644 index 000000000000..c0e50185f939 --- /dev/null +++ b/src/test/compile-fail/issue-29859.rs @@ -0,0 +1,25 @@ +// 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. + +#![feature(optin_builtin_traits)] + +trait Magic: Copy {} +impl Magic for .. {} +impl Magic for T {} + +fn copy(x: T) -> (T, T) { (x, x) } + +#[derive(Debug)] +struct NoClone; + +fn main() { + let (a, b) = copy(NoClone); //~ ERROR E0277 + println!("{:?} {:?}", a, b); +} From 352fac95ad5305bf8b0e482b8255b2b0057adf09 Mon Sep 17 00:00:00 2001 From: Jared Roesch Date: Tue, 16 Aug 2016 22:48:09 -0700 Subject: [PATCH 112/443] Reject certain auto trait declarations Fixes #29859 --- src/librustc/ty/mod.rs | 10 +++++ src/librustc_typeck/check/wfcheck.rs | 53 ++++++++++++++++++++++++++ src/librustc_typeck/diagnostics.rs | 2 + src/test/compile-fail/issue-29859-2.rs | 15 +------- src/test/compile-fail/issue-29859.rs | 6 +-- 5 files changed, 70 insertions(+), 16 deletions(-) diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index e9c01f5bad66..414e7b71f7cf 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -762,6 +762,16 @@ pub struct GenericPredicates<'tcx> { } impl<'a, 'gcx, 'tcx> GenericPredicates<'tcx> { + pub fn empty() -> GenericPredicates<'tcx> { + GenericPredicates { + predicates: VecPerParamSpace::empty(), + } + } + + pub fn is_empty(&self) -> bool { + self.predicates.is_empty() + } + pub fn instantiate(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, substs: &Substs<'tcx>) -> InstantiatedPredicates<'tcx> { let mut instantiated = InstantiatedPredicates::empty(); diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 435442bd30a6..0117dfa67300 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -251,6 +251,36 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { }); } + fn check_auto_trait(&mut self, + trait_def_id: DefId, + span: Span) + { + let predicates = self.tcx().lookup_predicates(trait_def_id); + + // If we must exclude the Self : Trait predicate contained by all + // traits. + let no_refl_predicates : Vec<_> = + predicates.predicates.iter().filter(|predicate| { + match *predicate { + &ty::Predicate::Trait(ref poly_trait_ref) => + poly_trait_ref.def_id() != trait_def_id, + _ => true, + } + }).collect(); + + let trait_def = self.tcx().lookup_trait_def(trait_def_id); + + // We use an if-else here, since the generics will also trigger + // an extraneous error message when we find predicates like + // `T : Sized` for a trait like: `trait Magic`. + if !trait_def.generics.types.get_slice(ParamSpace::TypeSpace).is_empty() { + error_566(self.ccx, span); + } else if !no_refl_predicates.is_empty() { + error_565(self.ccx, span); + } + + } + fn check_trait(&mut self, item: &hir::Item, items: &[hir::TraitItem]) @@ -258,9 +288,18 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { let trait_def_id = self.tcx().map.local_def_id(item.id); if self.tcx().trait_has_default_impl(trait_def_id) { + // We want to both ensure: + // 1) that there are no items contained within + // the trait defintion + // + // 2) that the definition doesn't violate the no-super trait rule + // for auto traits. + if !items.is_empty() { error_380(self.ccx, item.span); } + + self.check_auto_trait(trait_def_id, item.span); } self.for_item(item).with_fcx(|fcx, this| { @@ -272,6 +311,8 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { }); } + + fn check_item_fn(&mut self, item: &hir::Item, body: &hir::Block) @@ -637,6 +678,18 @@ fn error_380(ccx: &CrateCtxt, span: Span) { Trait for ..`) must have no methods or associated items") } +fn error_565(ccx: &CrateCtxt, span: Span) { + span_err!(ccx.tcx.sess, span, E0565, + "traits with default impls (`e.g. unsafe impl \ + Trait for ..`) can not have predicates") +} + +fn error_566(ccx: &CrateCtxt, span: Span) { + span_err!(ccx.tcx.sess, span, E0566, + "traits with default impls (`e.g. unsafe impl \ + Trait for ..`) can not have type parameters") +} + fn error_392<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, span: Span, param_name: ast::Name) -> DiagnosticBuilder<'tcx> { let mut err = struct_span_err!(ccx.tcx.sess, span, E0392, diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 3f1374db3693..7b7b4d2aa00f 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -4072,4 +4072,6 @@ register_diagnostics! { E0563, // cannot determine a type for this `impl Trait`: {} E0564, // only named lifetimes are allowed in `impl Trait`, // but `{}` was found in the type `{}` + E0565, // auto-traits can not have predicates, + E0566, // auto traits can not have type parameters } diff --git a/src/test/compile-fail/issue-29859-2.rs b/src/test/compile-fail/issue-29859-2.rs index c0e50185f939..258aafb15baf 100644 --- a/src/test/compile-fail/issue-29859-2.rs +++ b/src/test/compile-fail/issue-29859-2.rs @@ -10,16 +10,5 @@ #![feature(optin_builtin_traits)] -trait Magic: Copy {} -impl Magic for .. {} -impl Magic for T {} - -fn copy(x: T) -> (T, T) { (x, x) } - -#[derive(Debug)] -struct NoClone; - -fn main() { - let (a, b) = copy(NoClone); //~ ERROR E0277 - println!("{:?} {:?}", a, b); -} +trait Magic {} //~ E0566 +impl Magic for .. {} diff --git a/src/test/compile-fail/issue-29859.rs b/src/test/compile-fail/issue-29859.rs index c0e50185f939..3419e66af139 100644 --- a/src/test/compile-fail/issue-29859.rs +++ b/src/test/compile-fail/issue-29859.rs @@ -10,8 +10,8 @@ #![feature(optin_builtin_traits)] -trait Magic: Copy {} -impl Magic for .. {} +trait Magic: Copy {} //~ ERROR E0565 +impl Magic for .. {} impl Magic for T {} fn copy(x: T) -> (T, T) { (x, x) } @@ -20,6 +20,6 @@ fn copy(x: T) -> (T, T) { (x, x) } struct NoClone; fn main() { - let (a, b) = copy(NoClone); //~ ERROR E0277 + let (a, b) = copy(NoClone); println!("{:?} {:?}", a, b); } From 90d1a535510dfa098c908a76234d7b0db72eadf8 Mon Sep 17 00:00:00 2001 From: Jared Roesch Date: Thu, 18 Aug 2016 11:29:35 -0700 Subject: [PATCH 113/443] Address feedback, and remove invalid tests --- src/librustc/ty/mod.rs | 10 -- src/librustc_typeck/check/wfcheck.rs | 95 +++++++++++-------- ...its-inductive-overflow-auto-normal-auto.rs | 32 ------- ...its-inductive-overflow-supertrait-oibit.rs | 4 +- ... => typeck-auto-trait-no-supertraits-2.rs} | 2 +- .../typeck-auto-trait-no-supertraits.rs | 49 ++++++++++ ....rs => typeck-auto-trait-no-typeparams.rs} | 2 +- .../typeck-default-trait-impl-superregion.rs | 27 ------ .../typeck-default-trait-impl-supertrait.rs | 29 ------ ...default-trait-impl-trait-where-clause-2.rs | 36 ------- ...k-default-trait-impl-trait-where-clause.rs | 36 ------- 11 files changed, 108 insertions(+), 214 deletions(-) delete mode 100644 src/test/compile-fail/traits-inductive-overflow-auto-normal-auto.rs rename src/test/compile-fail/{issue-29859.rs => typeck-auto-trait-no-supertraits-2.rs} (91%) create mode 100644 src/test/compile-fail/typeck-auto-trait-no-supertraits.rs rename src/test/compile-fail/{issue-29859-2.rs => typeck-auto-trait-no-typeparams.rs} (93%) delete mode 100644 src/test/compile-fail/typeck-default-trait-impl-superregion.rs delete mode 100644 src/test/compile-fail/typeck-default-trait-impl-supertrait.rs delete mode 100644 src/test/compile-fail/typeck-default-trait-impl-trait-where-clause-2.rs delete mode 100644 src/test/compile-fail/typeck-default-trait-impl-trait-where-clause.rs diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 414e7b71f7cf..e9c01f5bad66 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -762,16 +762,6 @@ pub struct GenericPredicates<'tcx> { } impl<'a, 'gcx, 'tcx> GenericPredicates<'tcx> { - pub fn empty() -> GenericPredicates<'tcx> { - GenericPredicates { - predicates: VecPerParamSpace::empty(), - } - } - - pub fn is_empty(&self) -> bool { - self.predicates.is_empty() - } - pub fn instantiate(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, substs: &Substs<'tcx>) -> InstantiatedPredicates<'tcx> { let mut instantiated = InstantiatedPredicates::empty(); diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 0117dfa67300..4576fc9ffdc7 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -252,33 +252,71 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { } fn check_auto_trait(&mut self, - trait_def_id: DefId, - span: Span) + trait_def_id: DefId, + items: &[hir::TraitItem], + span: Span) { + // We want to ensure: + // + // 1) that there are no items contained within + // the trait defintion + // + // 2) that the definition doesn't violate the no-super trait rule + // for auto traits. + // + // 3) that the trait definition does not have any type parameters + let predicates = self.tcx().lookup_predicates(trait_def_id); - // If we must exclude the Self : Trait predicate contained by all + // We must exclude the Self : Trait predicate contained by all // traits. - let no_refl_predicates : Vec<_> = - predicates.predicates.iter().filter(|predicate| { - match *predicate { - &ty::Predicate::Trait(ref poly_trait_ref) => - poly_trait_ref.def_id() != trait_def_id, + let has_predicates = + predicates.predicates.iter().any(|predicate| { + match predicate { + &ty::Predicate::Trait(ref poly_trait_ref) => { + let self_ty = poly_trait_ref.0.self_ty(); + !(self_ty.is_self() && poly_trait_ref.def_id() == trait_def_id) + }, _ => true, - } - }).collect(); + } + }); let trait_def = self.tcx().lookup_trait_def(trait_def_id); + let has_ty_params = + trait_def.generics + .types + .len() > 1; + // We use an if-else here, since the generics will also trigger // an extraneous error message when we find predicates like // `T : Sized` for a trait like: `trait Magic`. - if !trait_def.generics.types.get_slice(ParamSpace::TypeSpace).is_empty() { - error_566(self.ccx, span); - } else if !no_refl_predicates.is_empty() { - error_565(self.ccx, span); + // + // We also put the check on the number of items here, + // as it seems confusing to report an error about + // extraneous predicates created by things like + // an associated type inside the trait. + + if !items.is_empty() { + error_380(self.ccx, span); + } else if has_ty_params { + span_err!(self.tcx().sess, span, E0566, + "traits with auto impls (`e.g. unsafe impl \ + Trait for ..`) can not have type parameters") + } else if has_predicates { + span_err!(self.tcx().sess, span, E0565, + "traits with auto impls (`e.g. unsafe impl \ + Trait for ..`) can not have predicates") } + // Finally if either of the above conditions apply we should add a note + // indicating that this error is the result of a recent soundness fix. + if has_ty_params || has_predicates { + self.tcx().sess.span_note_without_error( + span, + "the new auto trait rules are the result of a \ + recent soundness fix; see #29859 for more details") + } } fn check_trait(&mut self, @@ -287,19 +325,10 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { { let trait_def_id = self.tcx().map.local_def_id(item.id); + // TODO: in a second pass, globally rename to auto_trait, + // from default_impl. if self.tcx().trait_has_default_impl(trait_def_id) { - // We want to both ensure: - // 1) that there are no items contained within - // the trait defintion - // - // 2) that the definition doesn't violate the no-super trait rule - // for auto traits. - - if !items.is_empty() { - error_380(self.ccx, item.span); - } - - self.check_auto_trait(trait_def_id, item.span); + self.check_auto_trait(trait_def_id, items, item.span); } self.for_item(item).with_fcx(|fcx, this| { @@ -311,8 +340,6 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { }); } - - fn check_item_fn(&mut self, item: &hir::Item, body: &hir::Block) @@ -678,18 +705,6 @@ fn error_380(ccx: &CrateCtxt, span: Span) { Trait for ..`) must have no methods or associated items") } -fn error_565(ccx: &CrateCtxt, span: Span) { - span_err!(ccx.tcx.sess, span, E0565, - "traits with default impls (`e.g. unsafe impl \ - Trait for ..`) can not have predicates") -} - -fn error_566(ccx: &CrateCtxt, span: Span) { - span_err!(ccx.tcx.sess, span, E0566, - "traits with default impls (`e.g. unsafe impl \ - Trait for ..`) can not have type parameters") -} - fn error_392<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, span: Span, param_name: ast::Name) -> DiagnosticBuilder<'tcx> { let mut err = struct_span_err!(ccx.tcx.sess, span, E0392, diff --git a/src/test/compile-fail/traits-inductive-overflow-auto-normal-auto.rs b/src/test/compile-fail/traits-inductive-overflow-auto-normal-auto.rs deleted file mode 100644 index cdf4b405fd83..000000000000 --- a/src/test/compile-fail/traits-inductive-overflow-auto-normal-auto.rs +++ /dev/null @@ -1,32 +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. - -// Test for a potential corner case in current impl where you have an -// auto trait (Magic1) that depends on a normal trait (Magic2) which -// in turn depends on the auto trait (Magic1). This was incorrectly -// being considered coinductive, but because of the normal trait -// interfering, it should not be. - -#![feature(optin_builtin_traits)] - -trait Magic1: Magic2 { } -impl Magic1 for .. {} - -trait Magic2 { } -impl Magic2 for T { } - -fn is_magic1() { } - -#[derive(Debug)] -struct NoClone; - -fn main() { - is_magic1::(); //~ ERROR E0275 -} diff --git a/src/test/compile-fail/traits-inductive-overflow-supertrait-oibit.rs b/src/test/compile-fail/traits-inductive-overflow-supertrait-oibit.rs index ec8db996600d..168148b92fe4 100644 --- a/src/test/compile-fail/traits-inductive-overflow-supertrait-oibit.rs +++ b/src/test/compile-fail/traits-inductive-overflow-supertrait-oibit.rs @@ -14,7 +14,7 @@ #![feature(optin_builtin_traits)] -trait Magic: Copy {} +trait Magic: Copy {} //~ ERROR E0565 impl Magic for .. {} fn copy(x: T) -> (T, T) { (x, x) } @@ -23,6 +23,6 @@ fn copy(x: T) -> (T, T) { (x, x) } struct NoClone; fn main() { - let (a, b) = copy(NoClone); //~ ERROR E0277 + let (a, b) = copy(NoClone); println!("{:?} {:?}", a, b); } diff --git a/src/test/compile-fail/issue-29859.rs b/src/test/compile-fail/typeck-auto-trait-no-supertraits-2.rs similarity index 91% rename from src/test/compile-fail/issue-29859.rs rename to src/test/compile-fail/typeck-auto-trait-no-supertraits-2.rs index 3419e66af139..60da647f6824 100644 --- a/src/test/compile-fail/issue-29859.rs +++ b/src/test/compile-fail/typeck-auto-trait-no-supertraits-2.rs @@ -10,7 +10,7 @@ #![feature(optin_builtin_traits)] -trait Magic: Copy {} //~ ERROR E0565 +trait Magic : Sized where Option : Magic {} //~ ERROR E0565 impl Magic for .. {} impl Magic for T {} diff --git a/src/test/compile-fail/typeck-auto-trait-no-supertraits.rs b/src/test/compile-fail/typeck-auto-trait-no-supertraits.rs new file mode 100644 index 000000000000..177d594da18a --- /dev/null +++ b/src/test/compile-fail/typeck-auto-trait-no-supertraits.rs @@ -0,0 +1,49 @@ +// 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. + +// This test is for #29859, we need to ensure auto traits, +// (also known previously as default traits), do not have +// supertraits. Since the compiler synthesizes these +// instances on demand, we are essentially enabling +// users to write axioms if we view trait selection, +// as a proof system. +// +// For example the below test allows us to add the rule: +// forall (T : Type), T : Copy +// +// Providing a copy instance for *any* type, which +// is most definitely unsound. Imagine copying a +// type that contains a mutable reference, enabling +// mutable aliasing. +// +// You can imagine an even more dangerous test, +// which currently compiles on nightly. +// +// fn main() { +// let mut i = 10; +// let (a, b) = copy(&mut i); +// println!("{:?} {:?}", a, b); +// } + +#![feature(optin_builtin_traits)] + +trait Magic: Copy {} //~ ERROR E0565 +impl Magic for .. {} +impl Magic for T {} + +fn copy(x: T) -> (T, T) { (x, x) } + +#[derive(Debug)] +struct NoClone; + +fn main() { + let (a, b) = copy(NoClone); + println!("{:?} {:?}", a, b); +} diff --git a/src/test/compile-fail/issue-29859-2.rs b/src/test/compile-fail/typeck-auto-trait-no-typeparams.rs similarity index 93% rename from src/test/compile-fail/issue-29859-2.rs rename to src/test/compile-fail/typeck-auto-trait-no-typeparams.rs index 258aafb15baf..f2841a413db9 100644 --- a/src/test/compile-fail/issue-29859-2.rs +++ b/src/test/compile-fail/typeck-auto-trait-no-typeparams.rs @@ -10,5 +10,5 @@ #![feature(optin_builtin_traits)] -trait Magic {} //~ E0566 +trait Magic {} //~ ERROR E0566 impl Magic for .. {} diff --git a/src/test/compile-fail/typeck-default-trait-impl-superregion.rs b/src/test/compile-fail/typeck-default-trait-impl-superregion.rs deleted file mode 100644 index aa918119fbce..000000000000 --- a/src/test/compile-fail/typeck-default-trait-impl-superregion.rs +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// Test that when a `..` impl applies, we also check that any -// supertrait conditions are met. - -#![feature(optin_builtin_traits)] - -trait MyTrait : 'static {} - -impl MyTrait for .. {} - -fn foo() { } - -fn bar<'a>() { - foo::<&'a ()>(); //~ ERROR does not fulfill the required lifetime -} - -fn main() { -} diff --git a/src/test/compile-fail/typeck-default-trait-impl-supertrait.rs b/src/test/compile-fail/typeck-default-trait-impl-supertrait.rs deleted file mode 100644 index 0b071a9acd09..000000000000 --- a/src/test/compile-fail/typeck-default-trait-impl-supertrait.rs +++ /dev/null @@ -1,29 +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. - -// Test that when a `..` impl applies, we also check that any -// supertrait conditions are met. - -#![feature(optin_builtin_traits)] - -trait NotImplemented { } - -trait MyTrait : NotImplemented {} - -impl MyTrait for .. {} - -fn foo() { bar::() } - -fn bar() { } - -fn main() { - foo::(); //~ ERROR `i32: NotImplemented` is not satisfied - bar::(); //~ ERROR `i64: NotImplemented` is not satisfied -} diff --git a/src/test/compile-fail/typeck-default-trait-impl-trait-where-clause-2.rs b/src/test/compile-fail/typeck-default-trait-impl-trait-where-clause-2.rs deleted file mode 100644 index 3085f45a83dd..000000000000 --- a/src/test/compile-fail/typeck-default-trait-impl-trait-where-clause-2.rs +++ /dev/null @@ -1,36 +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. - -// ignore-tidy-linelength - -// Test that when a `..` impl applies, we also check that any -// supertrait conditions are met. - -#![feature(optin_builtin_traits)] - -trait NotImplemented { } - -trait MyTrait: Sized - where Option : NotImplemented -{} - -impl NotImplemented for i32 {} - -impl MyTrait for .. {} - -fn bar() { } - -fn test() { - bar::>(); - //~^ ERROR `std::option::Option: NotImplemented` is not satisfied -} - -fn main() { -} diff --git a/src/test/compile-fail/typeck-default-trait-impl-trait-where-clause.rs b/src/test/compile-fail/typeck-default-trait-impl-trait-where-clause.rs deleted file mode 100644 index 47e87c09d12b..000000000000 --- a/src/test/compile-fail/typeck-default-trait-impl-trait-where-clause.rs +++ /dev/null @@ -1,36 +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. - -// ignore-tidy-linelength - -// Test that when a `..` impl applies, we also check that any -// supertrait conditions are met. - -#![feature(optin_builtin_traits)] - -trait NotImplemented { } - -trait MyTrait: Sized - where Option : NotImplemented -{} - -impl NotImplemented for i32 {} - -impl MyTrait for .. {} - -fn foo() { - //~^ ERROR `std::option::Option: NotImplemented` is not satisfied - // This should probably typecheck. This is #20671. -} - -fn bar() { } - -fn main() { -} From ed5843bcc64c156f69b05c1cf2c8cdf4674e262d Mon Sep 17 00:00:00 2001 From: Jared Roesch Date: Thu, 18 Aug 2016 11:47:33 -0700 Subject: [PATCH 114/443] Address feedback on secondary changes --- src/librustc_typeck/check/wfcheck.rs | 30 ++++++++++++++-------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 4576fc9ffdc7..6e39e33c9a8d 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -296,26 +296,28 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { // as it seems confusing to report an error about // extraneous predicates created by things like // an associated type inside the trait. - + let mut err = None; if !items.is_empty() { error_380(self.ccx, span); } else if has_ty_params { - span_err!(self.tcx().sess, span, E0566, - "traits with auto impls (`e.g. unsafe impl \ - Trait for ..`) can not have type parameters") + err = Some(struct_span_err!(self.tcx().sess, span, E0566, + "traits with auto impls (`e.g. impl \ + Trait for ..`) can not have type parameters")); } else if has_predicates { - span_err!(self.tcx().sess, span, E0565, - "traits with auto impls (`e.g. unsafe impl \ - Trait for ..`) can not have predicates") + err = Some(struct_span_err!(self.tcx().sess, span, E0565, + "traits with auto impls (`e.g. impl \ + Trait for ..`) cannot have predicates")); } // Finally if either of the above conditions apply we should add a note // indicating that this error is the result of a recent soundness fix. - if has_ty_params || has_predicates { - self.tcx().sess.span_note_without_error( - span, - "the new auto trait rules are the result of a \ - recent soundness fix; see #29859 for more details") + match err { + None => {}, + Some(mut e) => { + e.note("the new auto trait rules are the result of a \ + recent soundness fix; see #29859 for more details"); + e.emit(); + } } } @@ -325,8 +327,6 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { { let trait_def_id = self.tcx().map.local_def_id(item.id); - // TODO: in a second pass, globally rename to auto_trait, - // from default_impl. if self.tcx().trait_has_default_impl(trait_def_id) { self.check_auto_trait(trait_def_id, items, item.span); } @@ -701,7 +701,7 @@ fn error_192(ccx: &CrateCtxt, span: Span) { fn error_380(ccx: &CrateCtxt, span: Span) { span_err!(ccx.tcx.sess, span, E0380, - "traits with default impls (`e.g. unsafe impl \ + "traits with default impls (`e.g. impl \ Trait for ..`) must have no methods or associated items") } From 6eb06e67708614763932c17de5d08a0c1818ce05 Mon Sep 17 00:00:00 2001 From: Jared Roesch Date: Thu, 18 Aug 2016 12:46:20 -0700 Subject: [PATCH 115/443] Forget to update tests to use new error message --- src/test/compile-fail/issue-23080-2.rs | 2 +- src/test/compile-fail/issue-23080.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/compile-fail/issue-23080-2.rs b/src/test/compile-fail/issue-23080-2.rs index b77230a8b340..9d20c17674bc 100644 --- a/src/test/compile-fail/issue-23080-2.rs +++ b/src/test/compile-fail/issue-23080-2.rs @@ -13,7 +13,7 @@ #![feature(optin_builtin_traits)] unsafe trait Trait { -//~^ error: traits with default impls (`e.g. unsafe impl Trait for ..`) must have no methods or associated items +//~^ ERROR E0380 type Output; } diff --git a/src/test/compile-fail/issue-23080.rs b/src/test/compile-fail/issue-23080.rs index 99373a69697a..2e8cba87be51 100644 --- a/src/test/compile-fail/issue-23080.rs +++ b/src/test/compile-fail/issue-23080.rs @@ -13,7 +13,7 @@ #![feature(optin_builtin_traits)] unsafe trait Trait { -//~^ error: traits with default impls (`e.g. unsafe impl Trait for ..`) must have no methods or associated items +//~^ ERROR E0380 fn method(&self) { println!("Hello"); } From 9510add6a3148f753776d6f6ac324690dba4a5d5 Mon Sep 17 00:00:00 2001 From: Jared Roesch Date: Mon, 29 Aug 2016 01:54:10 -0700 Subject: [PATCH 116/443] Remove illegal bound from doc test --- src/test/rustdoc/auxiliary/rustdoc-default-impl.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/rustdoc/auxiliary/rustdoc-default-impl.rs b/src/test/rustdoc/auxiliary/rustdoc-default-impl.rs index c2ff7a0054f1..52bd386ba595 100644 --- a/src/test/rustdoc/auxiliary/rustdoc-default-impl.rs +++ b/src/test/rustdoc/auxiliary/rustdoc-default-impl.rs @@ -14,7 +14,7 @@ pub mod bar { use std::marker; - pub trait Bar: 'static {} + pub trait Bar {} impl Bar for .. {} From eb1c7161dd79b55e022cd0c661f9018d406b3fe4 Mon Sep 17 00:00:00 2001 From: johnthagen Date: Fri, 2 Sep 2016 15:32:13 -0400 Subject: [PATCH 117/443] Update supported Windows versions to match Getting Started page. --- src/doc/book/nightly-rust.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/book/nightly-rust.md b/src/doc/book/nightly-rust.md index b3be71038a99..25570cb5503c 100644 --- a/src/doc/book/nightly-rust.md +++ b/src/doc/book/nightly-rust.md @@ -54,7 +54,7 @@ binary downloads][install-page]. Oh, we should also mention the officially supported platforms: -* Windows (7, 8, Server 2008 R2) +* Windows (7+) * Linux (2.6.18 or later, various distributions), x86 and x86-64 * OSX 10.7 (Lion) or greater, x86 and x86-64 From ecc6c39e876b69496bc88ef47ff3a339662346b1 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 22 Aug 2016 17:07:11 -0700 Subject: [PATCH 118/443] rustc: Implement custom derive (macros 1.1) This commit is an implementation of [RFC 1681] which adds support to the compiler for first-class user-define custom `#[derive]` modes with a far more stable API than plugins have today. [RFC 1681]: https://github.com/rust-lang/rfcs/blob/master/text/1681-macros-1.1.md The main features added by this commit are: * A new `rustc-macro` crate-type. This crate type represents one which will provide custom `derive` implementations and perhaps eventually flower into the implementation of macros 2.0 as well. * A new `rustc_macro` crate in the standard distribution. This crate will provide the runtime interface between macro crates and the compiler. The API here is particularly conservative right now but has quite a bit of room to expand into any manner of APIs required by macro authors. * The ability to load new derive modes through the `#[macro_use]` annotations on other crates. All support added here is gated behind the `rustc_macro` feature gate, both for the library support (the `rustc_macro` crate) as well as the language features. There are a few minor differences from the implementation outlined in the RFC, such as the `rustc_macro` crate being available as a dylib and all symbols are `dlsym`'d directly instead of having a shim compiled. These should only affect the implementation, however, not the public interface. This commit also ended up touching a lot of code related to `#[derive]`, making a few notable changes: * Recognized derive attributes are no longer desugared to `derive_Foo`. Wasn't sure how to keep this behavior and *not* expose it to custom derive. * Derive attributes no longer have access to unstable features by default, they have to opt in on a granular level. * The `derive(Copy,Clone)` optimization is now done through another "obscure attribute" which is just intended to ferry along in the compiler that such an optimization is possible. The `derive(PartialEq,Eq)` optimization was also updated to do something similar. --- One part of this PR which needs to be improved before stabilizing are the errors and exact interfaces here. The error messages are relatively poor quality and there are surprising spects of this such as `#[derive(PartialEq, Eq, MyTrait)]` not working by default. The custom attributes added by the compiler end up becoming unstable again when going through a custom impl. Hopefully though this is enough to start allowing experimentation on crates.io! syntax-[breaking-change] --- mk/crates.mk | 10 +- src/librustc/middle/dependency_format.rs | 9 +- src/librustc/middle/reachable.rs | 3 +- src/librustc/middle/weak_lang_items.rs | 1 + src/librustc/session/config.rs | 6 + src/librustc/session/mod.rs | 8 + src/librustc/ty/context.rs | 5 + src/librustc_driver/derive_registrar.rs | 37 +++ src/librustc_driver/driver.rs | 18 ++ src/librustc_driver/lib.rs | 2 +- src/librustc_macro/Cargo.toml | 12 + src/librustc_macro/lib.rs | 169 ++++++++++ src/librustc_metadata/Cargo.toml | 4 +- src/librustc_metadata/common.rs | 2 + src/librustc_metadata/creader.rs | 204 ++++++++---- src/librustc_metadata/cstore.rs | 14 +- src/librustc_metadata/decoder.rs | 5 + src/librustc_metadata/encoder.rs | 13 +- src/librustc_metadata/lib.rs | 6 +- src/librustc_metadata/macro_import.rs | 101 +++++- src/librustc_plugin/registry.rs | 1 - src/librustc_trans/back/link.rs | 8 +- src/librustc_trans/back/linker.rs | 32 +- src/librustc_trans/back/symbol_names.rs | 5 + src/libsyntax/ext/base.rs | 33 +- src/libsyntax/ext/expand.rs | 11 +- src/libsyntax/feature_gate.rs | 24 +- src/libsyntax_ext/Cargo.toml | 3 +- src/libsyntax_ext/deriving/clone.rs | 17 +- src/libsyntax_ext/deriving/custom.rs | 97 ++++++ src/libsyntax_ext/deriving/mod.rs | 300 ++++++++++-------- src/libsyntax_ext/lib.rs | 5 + src/libsyntax_ext/rustc_macro_registrar.rs | 280 ++++++++++++++++ src/rustc/Cargo.lock | 10 + .../rustc-macro/append-impl.rs | 33 ++ .../rustc-macro/at-the-root.rs | 25 ++ .../rustc-macro/attribute.rs | 46 +++ .../rustc-macro/auxiliary/append-impl.rs | 31 ++ .../rustc-macro/auxiliary/derive-a-2.rs | 25 ++ .../rustc-macro/auxiliary/derive-a.rs | 25 ++ .../rustc-macro/auxiliary/derive-bad.rs | 26 ++ .../rustc-macro/auxiliary/derive-panic.rs | 25 ++ .../auxiliary/derive-unstable-2.rs | 29 ++ .../rustc-macro/auxiliary/derive-unstable.rs | 26 ++ .../rustc-macro/cannot-link.rs | 16 + .../rustc-macro/define-two.rs | 28 ++ .../rustc-macro/derive-bad.rs | 25 ++ .../rustc-macro/derive-still-gated.rs | 22 ++ .../rustc-macro/expand-to-unstable-2.rs | 25 ++ .../rustc-macro/expand-to-unstable.rs | 25 ++ .../rustc-macro/export-macro.rs | 19 ++ .../rustc-macro/exports.rs | 22 ++ .../rustc-macro/feature-gate-1.rs | 13 + .../rustc-macro/feature-gate-2.rs | 13 + .../rustc-macro/feature-gate-3.rs} | 13 +- .../rustc-macro/feature-gate-4.rs | 15 + .../rustc-macro/feature-gate-5.rs | 12 + .../rustc-macro/import.rs | 22 ++ .../rustc-macro/load-panic.rs | 23 ++ .../require-rustc-macro-crate-type.rs | 21 ++ .../rustc-macro/shadow-builtin.rs | 22 ++ .../rustc-macro/shadow.rs | 21 ++ .../rustc-macro/signature.rs | 24 ++ .../rustc-macro/two-crate-types-1.rs | 14 + .../rustc-macro/two-crate-types-2.rs | 12 + src/test/compile-fail/issue-32655.rs | 7 +- .../run-pass-fulldeps/rustc-macro/add-impl.rs | 25 ++ .../rustc-macro/auxiliary/add-impl.rs | 33 ++ .../rustc-macro/auxiliary/derive-a.rs | 27 ++ .../rustc-macro/auxiliary/derive-atob.rs | 26 ++ .../rustc-macro/auxiliary/derive-ctod.rs | 26 ++ .../auxiliary/derive-same-struct.rs | 32 ++ .../auxiliary/expand-with-a-macro.rs | 36 +++ .../rustc-macro/derive-same-struct.rs | 23 ++ .../rustc-macro/expand-with-a-macro.rs | 30 ++ .../run-pass-fulldeps/rustc-macro/load-two.rs | 30 ++ .../run-pass-fulldeps/rustc-macro/smoke.rs | 29 ++ ...ociated-types-normalize-unifield-struct.rs | 3 - .../builtin-superkinds-in-metadata.rs | 2 - src/test/run-pass/coherence-impl-in-fn.rs | 2 - src/test/run-pass/deriving-bounds.rs | 2 - src/test/run-pass/issue-20797.rs | 2 - src/test/run-pass/issue-2288.rs | 2 - .../sync-send-iterators-in-libcollections.rs | 2 - 84 files changed, 2213 insertions(+), 279 deletions(-) create mode 100644 src/librustc_driver/derive_registrar.rs create mode 100644 src/librustc_macro/Cargo.toml create mode 100644 src/librustc_macro/lib.rs create mode 100644 src/libsyntax_ext/deriving/custom.rs create mode 100644 src/libsyntax_ext/rustc_macro_registrar.rs create mode 100644 src/test/compile-fail-fulldeps/rustc-macro/append-impl.rs create mode 100644 src/test/compile-fail-fulldeps/rustc-macro/at-the-root.rs create mode 100644 src/test/compile-fail-fulldeps/rustc-macro/attribute.rs create mode 100644 src/test/compile-fail-fulldeps/rustc-macro/auxiliary/append-impl.rs create mode 100644 src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-a-2.rs create mode 100644 src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-a.rs create mode 100644 src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-bad.rs create mode 100644 src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-panic.rs create mode 100644 src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-unstable-2.rs create mode 100644 src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-unstable.rs create mode 100644 src/test/compile-fail-fulldeps/rustc-macro/cannot-link.rs create mode 100644 src/test/compile-fail-fulldeps/rustc-macro/define-two.rs create mode 100644 src/test/compile-fail-fulldeps/rustc-macro/derive-bad.rs create mode 100644 src/test/compile-fail-fulldeps/rustc-macro/derive-still-gated.rs create mode 100644 src/test/compile-fail-fulldeps/rustc-macro/expand-to-unstable-2.rs create mode 100644 src/test/compile-fail-fulldeps/rustc-macro/expand-to-unstable.rs create mode 100644 src/test/compile-fail-fulldeps/rustc-macro/export-macro.rs create mode 100644 src/test/compile-fail-fulldeps/rustc-macro/exports.rs create mode 100644 src/test/compile-fail-fulldeps/rustc-macro/feature-gate-1.rs create mode 100644 src/test/compile-fail-fulldeps/rustc-macro/feature-gate-2.rs rename src/test/{run-pass/single-derive-attr-with-gate.rs => compile-fail-fulldeps/rustc-macro/feature-gate-3.rs} (68%) create mode 100644 src/test/compile-fail-fulldeps/rustc-macro/feature-gate-4.rs create mode 100644 src/test/compile-fail-fulldeps/rustc-macro/feature-gate-5.rs create mode 100644 src/test/compile-fail-fulldeps/rustc-macro/import.rs create mode 100644 src/test/compile-fail-fulldeps/rustc-macro/load-panic.rs create mode 100644 src/test/compile-fail-fulldeps/rustc-macro/require-rustc-macro-crate-type.rs create mode 100644 src/test/compile-fail-fulldeps/rustc-macro/shadow-builtin.rs create mode 100644 src/test/compile-fail-fulldeps/rustc-macro/shadow.rs create mode 100644 src/test/compile-fail-fulldeps/rustc-macro/signature.rs create mode 100644 src/test/compile-fail-fulldeps/rustc-macro/two-crate-types-1.rs create mode 100644 src/test/compile-fail-fulldeps/rustc-macro/two-crate-types-2.rs create mode 100644 src/test/run-pass-fulldeps/rustc-macro/add-impl.rs create mode 100644 src/test/run-pass-fulldeps/rustc-macro/auxiliary/add-impl.rs create mode 100644 src/test/run-pass-fulldeps/rustc-macro/auxiliary/derive-a.rs create mode 100644 src/test/run-pass-fulldeps/rustc-macro/auxiliary/derive-atob.rs create mode 100644 src/test/run-pass-fulldeps/rustc-macro/auxiliary/derive-ctod.rs create mode 100644 src/test/run-pass-fulldeps/rustc-macro/auxiliary/derive-same-struct.rs create mode 100644 src/test/run-pass-fulldeps/rustc-macro/auxiliary/expand-with-a-macro.rs create mode 100644 src/test/run-pass-fulldeps/rustc-macro/derive-same-struct.rs create mode 100644 src/test/run-pass-fulldeps/rustc-macro/expand-with-a-macro.rs create mode 100644 src/test/run-pass-fulldeps/rustc-macro/load-two.rs create mode 100644 src/test/run-pass-fulldeps/rustc-macro/smoke.rs diff --git a/mk/crates.mk b/mk/crates.mk index a915d07384f3..06ad07de136b 100644 --- a/mk/crates.mk +++ b/mk/crates.mk @@ -59,7 +59,7 @@ RUSTC_CRATES := rustc rustc_typeck rustc_mir rustc_borrowck rustc_resolve rustc_ rustc_trans rustc_back rustc_llvm rustc_privacy rustc_lint \ rustc_data_structures rustc_platform_intrinsics rustc_errors \ rustc_plugin rustc_metadata rustc_passes rustc_save_analysis \ - rustc_const_eval rustc_const_math rustc_incremental + rustc_const_eval rustc_const_math rustc_incremental rustc_macro HOST_CRATES := syntax syntax_ext proc_macro syntax_pos $(RUSTC_CRATES) rustdoc fmt_macros \ flate arena graphviz rbml log serialize TOOLS := compiletest rustdoc rustc rustbook error_index_generator @@ -99,7 +99,7 @@ DEPS_term := std DEPS_test := std getopts term native:rust_test_helpers DEPS_syntax := std term serialize log arena libc rustc_bitflags rustc_unicode rustc_errors syntax_pos -DEPS_syntax_ext := syntax syntax_pos rustc_errors fmt_macros +DEPS_syntax_ext := syntax syntax_pos rustc_errors fmt_macros rustc_macro DEPS_proc_macro := syntax syntax_pos rustc_plugin log DEPS_syntax_pos := serialize @@ -118,11 +118,13 @@ DEPS_rustc_driver := arena flate getopts graphviz libc rustc rustc_back rustc_bo rustc_trans rustc_privacy rustc_lint rustc_plugin \ rustc_metadata syntax_ext proc_macro \ rustc_passes rustc_save_analysis rustc_const_eval \ - rustc_incremental syntax_pos rustc_errors + rustc_incremental syntax_pos rustc_errors rustc_macro DEPS_rustc_errors := log libc serialize syntax_pos DEPS_rustc_lint := rustc log syntax syntax_pos rustc_const_eval DEPS_rustc_llvm := native:rustllvm libc std rustc_bitflags -DEPS_rustc_metadata := rustc syntax syntax_pos rustc_errors rbml rustc_const_math +DEPS_rustc_macro := std syntax +DEPS_rustc_metadata := rustc syntax syntax_pos rustc_errors rbml rustc_const_math \ + rustc_macro syntax_ext DEPS_rustc_passes := syntax syntax_pos rustc core rustc_const_eval rustc_errors DEPS_rustc_mir := rustc syntax syntax_pos rustc_const_math rustc_const_eval rustc_bitflags DEPS_rustc_resolve := arena rustc log syntax syntax_pos rustc_errors diff --git a/src/librustc/middle/dependency_format.rs b/src/librustc/middle/dependency_format.rs index cf6905ecf439..7822fe2536f1 100644 --- a/src/librustc/middle/dependency_format.rs +++ b/src/librustc/middle/dependency_format.rs @@ -139,8 +139,13 @@ fn calculate_type(sess: &session::Session, } } - // Everything else falls through below - config::CrateTypeExecutable | config::CrateTypeDylib => {}, + // Everything else falls through below. This will happen either with the + // `-C prefer-dynamic` or because we're a rustc-macro crate. Note that + // rustc-macro crates are required to be dylibs, and they're currently + // required to link to libsyntax as well. + config::CrateTypeExecutable | + config::CrateTypeDylib | + config::CrateTypeRustcMacro => {}, } let mut formats = FnvHashMap(); diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index e29a7cf9d684..1f9738556d92 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -138,7 +138,8 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { // Creates a new reachability computation context. fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> ReachableContext<'a, 'tcx> { let any_library = tcx.sess.crate_types.borrow().iter().any(|ty| { - *ty == config::CrateTypeRlib || *ty == config::CrateTypeDylib + *ty == config::CrateTypeRlib || *ty == config::CrateTypeDylib || + *ty == config::CrateTypeRustcMacro }); ReachableContext { tcx: tcx, diff --git a/src/librustc/middle/weak_lang_items.rs b/src/librustc/middle/weak_lang_items.rs index 6fb1b16705fe..c2f275e6deaf 100644 --- a/src/librustc/middle/weak_lang_items.rs +++ b/src/librustc/middle/weak_lang_items.rs @@ -70,6 +70,7 @@ fn verify(sess: &Session, items: &lang_items::LanguageItems) { let needs_check = sess.crate_types.borrow().iter().any(|kind| { match *kind { config::CrateTypeDylib | + config::CrateTypeRustcMacro | config::CrateTypeCdylib | config::CrateTypeExecutable | config::CrateTypeStaticlib => true, diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 562dce6a1b12..a2f926aa92c5 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -475,6 +475,7 @@ pub enum CrateType { CrateTypeRlib, CrateTypeStaticlib, CrateTypeCdylib, + CrateTypeRustcMacro, } #[derive(Clone, Hash)] @@ -962,6 +963,9 @@ pub fn default_configuration(sess: &Session) -> ast::CrateConfig { if sess.opts.debug_assertions { ret.push(attr::mk_word_item(InternedString::new("debug_assertions"))); } + if sess.opts.crate_types.contains(&CrateTypeRustcMacro) { + ret.push(attr::mk_word_item(InternedString::new("rustc_macro"))); + } return ret; } @@ -1547,6 +1551,7 @@ pub fn parse_crate_types_from_list(list_list: Vec) -> Result CrateTypeDylib, "cdylib" => CrateTypeCdylib, "bin" => CrateTypeExecutable, + "rustc-macro" => CrateTypeRustcMacro, _ => { return Err(format!("unknown crate type: `{}`", part)); @@ -1635,6 +1640,7 @@ impl fmt::Display for CrateType { CrateTypeRlib => "rlib".fmt(f), CrateTypeStaticlib => "staticlib".fmt(f), CrateTypeCdylib => "cdylib".fmt(f), + CrateTypeRustcMacro => "rustc-macro".fmt(f), } } } diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 338c65637995..ee2837e7bf1a 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -62,6 +62,7 @@ pub struct Session { pub entry_fn: RefCell>, pub entry_type: Cell>, pub plugin_registrar_fn: Cell>, + pub derive_registrar_fn: Cell>, pub default_sysroot: Option, // The name of the root source file of the crate, in the local file system. // The path is always expected to be absolute. `None` means that there is no @@ -314,6 +315,12 @@ impl Session { format!("__rustc_plugin_registrar__{}_{}", svh, index.as_usize()) } + pub fn generate_derive_registrar_symbol(&self, + svh: &Svh, + index: DefIndex) -> String { + format!("__rustc_derive_registrar__{}_{}", svh, index.as_usize()) + } + pub fn sysroot<'a>(&'a self) -> &'a Path { match self.opts.maybe_sysroot { Some (ref sysroot) => sysroot, @@ -501,6 +508,7 @@ pub fn build_session_(sopts: config::Options, entry_fn: RefCell::new(None), entry_type: Cell::new(None), plugin_registrar_fn: Cell::new(None), + derive_registrar_fn: Cell::new(None), default_sysroot: default_sysroot, local_crate_source_file: local_crate_source_file, working_dir: env::current_dir().unwrap(), diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index e048e618e84d..725bbf6adfd4 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -495,6 +495,10 @@ pub struct GlobalCtxt<'tcx> { /// Cache for layouts computed from types. pub layout_cache: RefCell, &'tcx Layout>>, + + /// Map from function to the `#[derive]` mode that it's defining. Only used + /// by `rustc-macro` crates. + pub derive_macros: RefCell>, } impl<'tcx> GlobalCtxt<'tcx> { @@ -756,6 +760,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { crate_name: token::intern_and_get_ident(crate_name), data_layout: data_layout, layout_cache: RefCell::new(FnvHashMap()), + derive_macros: RefCell::new(NodeMap()), }, f) } } diff --git a/src/librustc_driver/derive_registrar.rs b/src/librustc_driver/derive_registrar.rs new file mode 100644 index 000000000000..ea7621e16e7b --- /dev/null +++ b/src/librustc_driver/derive_registrar.rs @@ -0,0 +1,37 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use rustc::dep_graph::DepNode; +use rustc::hir::intravisit::Visitor; +use rustc::hir::map::Map; +use rustc::hir; +use syntax::ast; +use syntax::attr; + +pub fn find(hir_map: &Map) -> Option { + let _task = hir_map.dep_graph.in_task(DepNode::PluginRegistrar); + let krate = hir_map.krate(); + + let mut finder = Finder { registrar: None }; + krate.visit_all_items(&mut finder); + finder.registrar +} + +struct Finder { + registrar: Option, +} + +impl<'v> Visitor<'v> for Finder { + fn visit_item(&mut self, item: &hir::Item) { + if attr::contains_name(&item.attrs, "rustc_derive_registrar") { + self.registrar = Some(item.id); + } + } +} diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 94092be4922b..47a0399b6328 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -55,6 +55,8 @@ use syntax::util::node_count::NodeCounter; use syntax; use syntax_ext; +use derive_registrar; + #[derive(Clone)] pub struct Resolutions { pub def_map: DefMap, @@ -696,6 +698,18 @@ pub fn phase_2_configure_and_expand<'a, F>(sess: &Session, sess.diagnostic()) }); + krate = time(time_passes, "maybe creating a macro crate", || { + let crate_types = sess.crate_types.borrow(); + let is_rustc_macro_crate = crate_types.contains(&config::CrateTypeRustcMacro); + let num_crate_types = crate_types.len(); + syntax_ext::rustc_macro_registrar::modify(&sess.parse_sess, + krate, + is_rustc_macro_crate, + num_crate_types, + sess.diagnostic(), + &sess.features.borrow()) + }); + let resolver_arenas = Resolver::arenas(); let mut resolver = Resolver::new(sess, make_glob_map, &resolver_arenas); @@ -838,6 +852,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, sess.plugin_registrar_fn.set(time(time_passes, "looking for plugin registrar", || { plugin::build::find_plugin_registrar(sess.diagnostic(), &hir_map) })); + sess.derive_registrar_fn.set(derive_registrar::find(&hir_map)); let region_map = time(time_passes, "region resolution", @@ -1171,6 +1186,9 @@ pub fn collect_crate_types(session: &Session, attrs: &[ast::Attribute]) -> Vec { Some(config::CrateTypeStaticlib) } + Some(ref n) if *n == "rustc-macro" => { + Some(config::CrateTypeRustcMacro) + } Some(ref n) if *n == "bin" => Some(config::CrateTypeExecutable), Some(_) => { session.add_lint(lint::builtin::UNKNOWN_CRATE_TYPES, diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index efadf1ff488d..6616e9579e81 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -107,7 +107,7 @@ pub mod test; pub mod driver; pub mod pretty; pub mod target_features; - +mod derive_registrar; const BUG_REPORT_URL: &'static str = "https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.\ md#bug-reports"; diff --git a/src/librustc_macro/Cargo.toml b/src/librustc_macro/Cargo.toml new file mode 100644 index 000000000000..6b3ee21d9ace --- /dev/null +++ b/src/librustc_macro/Cargo.toml @@ -0,0 +1,12 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_macro" +version = "0.0.0" + +[lib] +name = "rustc_macro" +path = "lib.rs" +crate-type = ["dylib"] + +[dependencies] +syntax = { path = "../libsyntax" } diff --git a/src/librustc_macro/lib.rs b/src/librustc_macro/lib.rs new file mode 100644 index 000000000000..c2a2cc2ecd64 --- /dev/null +++ b/src/librustc_macro/lib.rs @@ -0,0 +1,169 @@ +// 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. + +//! A support library for macro authors when defining new macros. +//! +//! This library, provided by the standard distribution, provides the types +//! consumed in the interfaces of procedurally defined macro definitions. +//! Currently the primary use of this crate is to provide the ability to define +//! new custom derive modes through `#[rustc_macro_derive]`. +//! +//! Added recently as part of [RFC 1681] this crate is currently *unstable* and +//! requires the `#![feature(rustc_macro_lib)]` directive to use. Eventually, +//! though, it is intended for this crate to become stable to use (perhaps under +//! a different name). +//! +//! [RFC 1681]: https://github.com/rust-lang/rfcs/blob/master/text/1681-macros-1.1.md +//! +//! Note that this crate is intentionally very bare-bones currently. The main +//! type, `TokenStream`, only supports `fmt::Display` and `FromStr` +//! implementations, indicating that it can only go to and come from a string. +//! This functionality is intended to be expanded over time as more surface +//! area for macro authors is stabilized. + +#![crate_name = "rustc_macro"] +#![unstable(feature = "rustc_macro_lib", issue = "27812")] +#![crate_type = "rlib"] +#![crate_type = "dylib"] +#![cfg_attr(not(stage0), deny(warnings))] +#![deny(missing_docs)] + +#![feature(rustc_private)] +#![feature(staged_api)] +#![feature(lang_items)] + +extern crate syntax; + +use std::fmt; +use std::str::FromStr; + +use syntax::ast; +use syntax::parse; +use syntax::ptr::P; + +/// The main type provided by this crate, representing an abstract stream of +/// tokens. +/// +/// This is both the input and output of `#[rustc_macro_derive]` definitions. +/// Currently it's required to be a list of valid Rust items, but this +/// restriction may be lifted in the future. +/// +/// The API of this type is intentionally bare-bones, but it'll be expanded over +/// time! +pub struct TokenStream { + inner: Vec>, +} + +/// Error returned from `TokenStream::from_str`. +#[derive(Debug)] +pub struct LexError { + _inner: (), +} + +/// Permanently unstable internal implementation details of this crate. This +/// should not be used. +/// +/// These methods are used by the rest of the compiler to generate instances of +/// `TokenStream` to hand to macro definitions, as well as consume the output. +/// +/// Note that this module is also intentionally separate from the rest of the +/// crate. This allows the `#[unstable]` directive below to naturally apply to +/// all of the contents. +#[unstable(feature = "rustc_macro_internals", issue = "27812")] +#[doc(hidden)] +pub mod __internal { + use std::cell::Cell; + + use syntax::ast; + use syntax::ptr::P; + use syntax::parse::ParseSess; + use super::TokenStream; + + pub fn new_token_stream(item: P) -> TokenStream { + TokenStream { inner: vec![item] } + } + + pub fn token_stream_items(stream: TokenStream) -> Vec> { + stream.inner + } + + pub trait Registry { + fn register_custom_derive(&mut self, + trait_name: &str, + expand: fn(TokenStream) -> TokenStream); + } + + // Emulate scoped_thread_local!() here essentially + thread_local! { + static CURRENT_SESS: Cell<*const ParseSess> = Cell::new(0 as *const _); + } + + pub fn set_parse_sess(sess: &ParseSess, f: F) -> R + where F: FnOnce() -> R + { + struct Reset { prev: *const ParseSess } + + impl Drop for Reset { + fn drop(&mut self) { + CURRENT_SESS.with(|p| p.set(self.prev)); + } + } + + CURRENT_SESS.with(|p| { + let _reset = Reset { prev: p.get() }; + p.set(sess); + f() + }) + } + + pub fn with_parse_sess(f: F) -> R + where F: FnOnce(&ParseSess) -> R + { + let p = CURRENT_SESS.with(|p| p.get()); + assert!(!p.is_null()); + f(unsafe { &*p }) + } +} + +impl FromStr for TokenStream { + type Err = LexError; + + fn from_str(src: &str) -> Result { + __internal::with_parse_sess(|sess| { + let src = src.to_string(); + let cfg = Vec::new(); + let name = "rustc-macro source code".to_string(); + let mut parser = parse::new_parser_from_source_str(sess, cfg, name, + src); + let mut ret = TokenStream { inner: Vec::new() }; + loop { + match parser.parse_item() { + Ok(Some(item)) => ret.inner.push(item), + Ok(None) => return Ok(ret), + Err(mut err) => { + err.cancel(); + return Err(LexError { _inner: () }) + } + } + } + }) + } +} + +impl fmt::Display for TokenStream { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + for item in self.inner.iter() { + let item = syntax::print::pprust::item_to_string(item); + try!(f.write_str(&item)); + try!(f.write_str("\n")); + } + Ok(()) + } +} diff --git a/src/librustc_metadata/Cargo.toml b/src/librustc_metadata/Cargo.toml index 2d3302c2eef3..d70510896b96 100644 --- a/src/librustc_metadata/Cargo.toml +++ b/src/librustc_metadata/Cargo.toml @@ -19,6 +19,8 @@ rustc_const_math = { path = "../librustc_const_math" } rustc_data_structures = { path = "../librustc_data_structures" } rustc_errors = { path = "../librustc_errors" } rustc_llvm = { path = "../librustc_llvm" } +rustc_macro = { path = "../librustc_macro" } serialize = { path = "../libserialize" } syntax = { path = "../libsyntax" } -syntax_pos = { path = "../libsyntax_pos" } \ No newline at end of file +syntax_ext = { path = "../libsyntax_ext" } +syntax_pos = { path = "../libsyntax_pos" } diff --git a/src/librustc_metadata/common.rs b/src/librustc_metadata/common.rs index 85cf41e42a27..1e6c74bef8da 100644 --- a/src/librustc_metadata/common.rs +++ b/src/librustc_metadata/common.rs @@ -234,6 +234,8 @@ pub fn rustc_version() -> String { pub const tag_panic_strategy: usize = 0x114; +pub const tag_macro_derive_registrar: usize = 0x115; + // NB: increment this if you change the format of metadata such that // rustc_version can't be found. pub const metadata_encoding_version : &'static [u8] = &[b'r', b'u', b's', b't', 0, 0, 0, 2]; diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 7e1f3ea618c9..2524348dc1a9 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -130,18 +130,23 @@ struct ExtensionCrate { metadata: PMDSource, dylib: Option, target_only: bool, + + ident: String, + name: String, + span: Span, + should_link: bool, } enum PMDSource { Registered(Rc), - Owned(MetadataBlob), + Owned(loader::Library), } impl PMDSource { pub fn as_slice<'a>(&'a self) -> &'a [u8] { match *self { PMDSource::Registered(ref cmd) => cmd.data(), - PMDSource::Owned(ref mdb) => mdb.as_slice(), + PMDSource::Owned(ref lib) => lib.metadata.as_slice(), } } } @@ -151,6 +156,17 @@ enum LoadResult { Loaded(loader::Library), } +pub struct Macros { + pub macro_rules: Vec, + + /// An array of pairs where the first element is the name of the custom + /// derive (e.g. the trait being derived) and the second element is the + /// index of the definition. + pub custom_derive_registrar: Option, + pub svh: Svh, + pub dylib: Option, +} + impl<'a> CrateReader<'a> { pub fn new(sess: &'a Session, cstore: &'a CStore, @@ -281,6 +297,7 @@ impl<'a> CrateReader<'a> { explicitly_linked: bool) -> (ast::CrateNum, Rc, cstore::CrateSource) { + info!("register crate `extern crate {} as {}`", name, ident); self.verify_no_symbol_conflicts(span, &lib.metadata); // Claim this crate number and cache it @@ -319,6 +336,11 @@ impl<'a> CrateReader<'a> { explicitly_linked: Cell::new(explicitly_linked), }); + if decoder::get_derive_registrar_fn(cmeta.data.as_slice()).is_some() { + self.sess.span_err(span, "crates of the `rustc-macro` crate type \ + cannot be linked at runtime"); + } + let source = cstore::CrateSource { dylib: dylib, rlib: rlib, @@ -349,9 +371,11 @@ impl<'a> CrateReader<'a> { kind: PathKind, explicitly_linked: bool) -> (ast::CrateNum, Rc, cstore::CrateSource) { + info!("resolving crate `extern crate {} as {}`", name, ident); let result = match self.existing_match(name, hash, kind) { Some(cnum) => LoadResult::Previous(cnum), None => { + info!("falling back to a load"); let mut load_ctxt = loader::Context { sess: self.sess, span: span, @@ -412,6 +436,7 @@ impl<'a> CrateReader<'a> { self.cstore.iter_crate_data(|cnum, data| { if data.name() == meta_name && meta_hash == data.hash() { assert!(loader.hash.is_none()); + info!("load success, going to previous cnum: {}", cnum); result = LoadResult::Previous(cnum); } }); @@ -483,6 +508,8 @@ impl<'a> CrateReader<'a> { } fn read_extension_crate(&mut self, span: Span, info: &CrateInfo) -> ExtensionCrate { + info!("read extension crate {} `extern crate {} as {}` linked={}", + info.id, info.name, info.ident, info.should_link); let target_triple = &self.sess.opts.target_triple[..]; let is_cross = target_triple != config::host_triple(); let mut should_link = info.should_link && !is_cross; @@ -533,16 +560,7 @@ impl<'a> CrateReader<'a> { } LoadResult::Loaded(library) => { let dylib = library.dylib.clone(); - let metadata = if should_link { - // Register crate now to avoid double-reading metadata - let (_, cmd, _) = self.register_crate(&None, &info.ident, - &info.name, span, - library, true); - PMDSource::Registered(cmd) - } else { - // Not registering the crate; just hold on to the metadata - PMDSource::Owned(library.metadata) - }; + let metadata = PMDSource::Owned(library); (dylib, metadata) } }; @@ -551,59 +569,97 @@ impl<'a> CrateReader<'a> { metadata: metadata, dylib: dylib.map(|p| p.0), target_only: target_only, + name: info.name.to_string(), + ident: info.ident.to_string(), + span: span, + should_link: should_link, } } - /// Read exported macros. - pub fn read_exported_macros(&mut self, item: &ast::Item) -> Vec { + pub fn read_macros(&mut self, item: &ast::Item) -> Macros { let ci = self.extract_crate_info(item).unwrap(); let ekrate = self.read_extension_crate(item.span, &ci); let source_name = format!("<{} macros>", item.ident); - let mut macros = vec![]; + let mut ret = Macros { + macro_rules: Vec::new(), + custom_derive_registrar: None, + svh: decoder::get_crate_hash(ekrate.metadata.as_slice()), + dylib: None, + }; decoder::each_exported_macro(ekrate.metadata.as_slice(), - |name, attrs, span, body| { - // NB: Don't use parse::parse_tts_from_source_str because it parses with - // quote_depth > 0. - let mut p = parse::new_parser_from_source_str(&self.sess.parse_sess, - self.local_crate_config.clone(), - source_name.clone(), - body); - let lo = p.span.lo; - let body = match p.parse_all_token_trees() { - Ok(body) => body, - Err(mut err) => { - err.emit(); - self.sess.abort_if_errors(); - unreachable!(); - } - }; - let local_span = mk_sp(lo, p.last_span.hi); - - // Mark the attrs as used - for attr in &attrs { - attr::mark_used(attr); + |name, attrs, span, body| { + // NB: Don't use parse::parse_tts_from_source_str because it parses with + // quote_depth > 0. + let mut p = parse::new_parser_from_source_str(&self.sess.parse_sess, + self.local_crate_config.clone(), + source_name.clone(), + body); + let lo = p.span.lo; + let body = match p.parse_all_token_trees() { + Ok(body) => body, + Err(mut err) => { + err.emit(); + self.sess.abort_if_errors(); + unreachable!(); } + }; + let local_span = mk_sp(lo, p.last_span.hi); - macros.push(ast::MacroDef { - ident: ast::Ident::with_empty_ctxt(name), - attrs: attrs, - id: ast::DUMMY_NODE_ID, - span: local_span, - imported_from: Some(item.ident), - // overridden in plugin/load.rs - export: false, - use_locally: false, - allow_internal_unstable: false, - - body: body, - }); - self.sess.imported_macro_spans.borrow_mut() - .insert(local_span, (name.as_str().to_string(), span)); - true + // Mark the attrs as used + for attr in &attrs { + attr::mark_used(attr); } - ); - macros + + ret.macro_rules.push(ast::MacroDef { + ident: ast::Ident::with_empty_ctxt(name), + attrs: attrs, + id: ast::DUMMY_NODE_ID, + span: local_span, + imported_from: Some(item.ident), + // overridden in plugin/load.rs + export: false, + use_locally: false, + allow_internal_unstable: false, + + body: body, + }); + self.sess.imported_macro_spans.borrow_mut() + .insert(local_span, (name.as_str().to_string(), span)); + true + }); + + match decoder::get_derive_registrar_fn(ekrate.metadata.as_slice()) { + Some(id) => ret.custom_derive_registrar = Some(id), + + // If this crate is not a rustc-macro crate then we might be able to + // register it with the local crate store to prevent loading the + // metadata twice. + // + // If it's a rustc-macro crate, though, then we definitely don't + // want to register it with the local crate store as we're just + // going to use it as we would a plugin. + None => { + ekrate.register(self); + return ret + } + } + + self.cstore.add_used_for_derive_macros(item); + ret.dylib = ekrate.dylib.clone(); + if ret.dylib.is_none() { + span_bug!(item.span, "rustc-macro crate not dylib"); + } + + if ekrate.target_only { + let message = format!("rustc-macro crate is not available for \ + triple `{}` (only found {})", + config::host_triple(), + self.sess.opts.target_triple); + self.sess.span_fatal(item.span, &message); + } + + return ret } /// Look for a plugin registrar. Returns library path, crate @@ -774,6 +830,7 @@ impl<'a> CrateReader<'a> { match *ct { config::CrateTypeExecutable => need_exe_alloc = true, config::CrateTypeDylib | + config::CrateTypeRustcMacro | config::CrateTypeCdylib | config::CrateTypeStaticlib => need_lib_alloc = true, config::CrateTypeRlib => {} @@ -858,6 +915,27 @@ impl<'a> CrateReader<'a> { } } +impl ExtensionCrate { + fn register(self, creader: &mut CrateReader) { + if !self.should_link { + return + } + + let library = match self.metadata { + PMDSource::Owned(lib) => lib, + PMDSource::Registered(_) => return, + }; + + // Register crate now to avoid double-reading metadata + creader.register_crate(&None, + &self.ident, + &self.name, + self.span, + library, + true); + } +} + impl<'a> LocalCrateReader<'a> { fn new(sess: &'a Session, cstore: &'a CStore, @@ -906,11 +984,25 @@ impl<'a> LocalCrateReader<'a> { fn process_item(&mut self, i: &ast::Item) { match i.node { ast::ItemKind::ExternCrate(_) => { - if !should_link(i) { - return; + // If this `extern crate` item has `#[macro_use]` then we can + // safely skip it. These annotations were processed during macro + // expansion and are already loaded (if necessary) into our + // crate store. + // + // Note that it's important we *don't* fall through below as + // some `#[macro_use]` crate are explicitly not linked (e.g. + // macro crates) so we want to ensure we avoid `resolve_crate` + // with those. + if attr::contains_name(&i.attrs, "macro_use") { + if self.cstore.was_used_for_derive_macros(i) { + return + } } if let Some(info) = self.creader.extract_crate_info(i) { + if !info.should_link { + return; + } let (cnum, _, _) = self.creader.resolve_crate(&None, &info.ident, &info.name, diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs index d786cc5ba0eb..952d7008d0f2 100644 --- a/src/librustc_metadata/cstore.rs +++ b/src/librustc_metadata/cstore.rs @@ -28,13 +28,13 @@ use rustc::hir::svh::Svh; use rustc::middle::cstore::ExternCrate; use rustc::session::config::PanicStrategy; use rustc_data_structures::indexed_vec::IndexVec; -use rustc::util::nodemap::{FnvHashMap, NodeMap, NodeSet, DefIdMap}; +use rustc::util::nodemap::{FnvHashMap, NodeMap, NodeSet, DefIdMap, FnvHashSet}; use std::cell::{RefCell, Ref, Cell}; use std::rc::Rc; use std::path::PathBuf; use flate::Bytes; -use syntax::ast; +use syntax::ast::{self, Ident}; use syntax::attr; use syntax::codemap; use syntax_pos; @@ -115,6 +115,7 @@ pub struct CStore { pub inlined_item_cache: RefCell>>, pub defid_for_inlined_node: RefCell>, pub visible_parent_map: RefCell>, + pub used_for_derive_macro: RefCell>, } impl CStore { @@ -130,6 +131,7 @@ impl CStore { visible_parent_map: RefCell::new(FnvHashMap()), inlined_item_cache: RefCell::new(FnvHashMap()), defid_for_inlined_node: RefCell::new(FnvHashMap()), + used_for_derive_macro: RefCell::new(FnvHashSet()), } } @@ -286,6 +288,14 @@ impl CStore { { self.extern_mod_crate_map.borrow().get(&emod_id).cloned() } + + pub fn was_used_for_derive_macros(&self, i: &ast::Item) -> bool { + self.used_for_derive_macro.borrow().contains(&i.ident) + } + + pub fn add_used_for_derive_macros(&self, i: &ast::Item) { + self.used_for_derive_macro.borrow_mut().insert(i.ident); + } } impl CrateMetadata { diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 7117cdb731cf..9a13be8ade52 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -1398,6 +1398,11 @@ pub fn each_exported_macro(data: &[u8], mut f: F) where } } +pub fn get_derive_registrar_fn(data: &[u8]) -> Option { + reader::maybe_get_doc(rbml::Doc::new(data), tag_macro_derive_registrar) + .map(|doc| DefIndex::from_u32(reader::doc_as_u32(doc))) +} + pub fn get_macro_span(doc: rbml::Doc) -> Span { let lo_doc = reader::get_doc(doc, tag_macro_def_span_lo); let lo = BytePos(reader::doc_as_u32(lo_doc)); diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index b3ac678d7120..bb4cf70bd3b3 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -31,7 +31,7 @@ use rustc::ty::{self, Ty, TyCtxt}; use rustc::hir::svh::Svh; use rustc::mir::mir_map::MirMap; -use rustc::session::config::{self, PanicStrategy}; +use rustc::session::config::{self, PanicStrategy, CrateTypeRustcMacro}; use rustc::util::nodemap::{FnvHashMap, NodeSet}; use rustc_serialize::Encodable; @@ -1567,7 +1567,8 @@ fn encode_codemap(ecx: &EncodeContext, rbml_w: &mut Encoder) { /// Serialize the text of the exported macros fn encode_macro_defs(rbml_w: &mut Encoder, - krate: &hir::Crate) { + krate: &hir::Crate, + tcx: TyCtxt) { rbml_w.start_tag(tag_macro_defs); for def in &krate.exported_macros { rbml_w.start_tag(tag_macro_def); @@ -1585,6 +1586,12 @@ fn encode_macro_defs(rbml_w: &mut Encoder, rbml_w.end_tag(); } rbml_w.end_tag(); + + if tcx.sess.crate_types.borrow().contains(&CrateTypeRustcMacro) { + let id = tcx.sess.derive_registrar_fn.get().unwrap(); + let did = tcx.map.local_def_id(id); + rbml_w.wr_tagged_u32(tag_macro_derive_registrar, did.index.as_u32()); + } } fn encode_struct_field_attrs(ecx: &EncodeContext, @@ -1882,7 +1889,7 @@ fn encode_metadata_inner(rbml_w: &mut Encoder, // Encode macro definitions i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap(); - encode_macro_defs(rbml_w, krate); + encode_macro_defs(rbml_w, krate, ecx.tcx); stats.macro_defs_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i; // Encode the def IDs of impls, for coherence checking. diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs index a96fa8a006d8..a3afb9d84bd3 100644 --- a/src/librustc_metadata/lib.rs +++ b/src/librustc_metadata/lib.rs @@ -19,11 +19,13 @@ #![feature(box_patterns)] #![feature(enumset)] +#![feature(question_mark)] #![feature(quote)] #![feature(rustc_diagnostic_macros)] +#![feature(rustc_macro_lib)] +#![feature(rustc_macro_internals)] #![feature(rustc_private)] #![feature(staged_api)] -#![feature(question_mark)] #[macro_use] extern crate log; #[macro_use] extern crate syntax; @@ -33,12 +35,14 @@ extern crate flate; extern crate rbml; extern crate serialize as rustc_serialize; // used by deriving extern crate rustc_errors as errors; +extern crate syntax_ext; #[macro_use] extern crate rustc; extern crate rustc_data_structures; extern crate rustc_back; extern crate rustc_llvm; +extern crate rustc_macro; extern crate rustc_const_math; pub use rustc::middle; diff --git a/src/librustc_metadata/macro_import.rs b/src/librustc_metadata/macro_import.rs index fa31b6f4c722..22691975050e 100644 --- a/src/librustc_metadata/macro_import.rs +++ b/src/librustc_metadata/macro_import.rs @@ -10,16 +10,25 @@ //! Used by `rustc` when loading a crate with exported macros. -use creader::CrateReader; +use std::collections::HashSet; +use std::env; +use std::mem; + +use creader::{CrateReader, Macros}; use cstore::CStore; +use rustc::hir::def_id::DefIndex; use rustc::session::Session; -use rustc::util::nodemap::{FnvHashSet, FnvHashMap}; - -use syntax::parse::token; +use rustc::util::nodemap::FnvHashMap; +use rustc_back::dynamic_lib::DynamicLibrary; +use rustc_macro::TokenStream; +use rustc_macro::__internal::Registry; use syntax::ast; use syntax::attr; +use syntax::ext::base::LoadedMacro; use syntax::ext; +use syntax::parse::token; +use syntax_ext::deriving::custom::CustomDerive; use syntax_pos::Span; pub struct MacroLoader<'a> { @@ -47,7 +56,9 @@ pub fn call_bad_macro_reexport(a: &Session, b: Span) { pub type MacroSelection = FnvHashMap; impl<'a> ext::base::MacroLoader for MacroLoader<'a> { - fn load_crate(&mut self, extern_crate: &ast::Item, allows_macros: bool) -> Vec { + fn load_crate(&mut self, + extern_crate: &ast::Item, + allows_macros: bool) -> Vec { // Parse the attributes relating to macros. let mut import = Some(FnvHashMap()); // None => load all let mut reexport = FnvHashMap(); @@ -105,7 +116,7 @@ impl<'a> MacroLoader<'a> { allows_macros: bool, import: Option, reexport: MacroSelection) - -> Vec { + -> Vec { if let Some(sel) = import.as_ref() { if sel.is_empty() && reexport.is_empty() { return Vec::new(); @@ -118,10 +129,11 @@ impl<'a> MacroLoader<'a> { return Vec::new(); } - let mut macros = Vec::new(); - let mut seen = FnvHashSet(); + let mut macros = self.reader.read_macros(vi); + let mut ret = Vec::new(); + let mut seen = HashSet::new(); - for mut def in self.reader.read_exported_macros(vi) { + for mut def in macros.macro_rules.drain(..) { let name = def.ident.name.as_str(); def.use_locally = match import.as_ref() { @@ -132,10 +144,29 @@ impl<'a> MacroLoader<'a> { def.allow_internal_unstable = attr::contains_name(&def.attrs, "allow_internal_unstable"); debug!("load_macros: loaded: {:?}", def); - macros.push(def); + ret.push(LoadedMacro::Def(def)); seen.insert(name); } + if let Some(index) = macros.custom_derive_registrar { + // custom derive crates currently should not have any macro_rules! + // exported macros, enforced elsewhere + assert_eq!(ret.len(), 0); + + if import.is_some() { + self.sess.span_err(vi.span, "`rustc-macro` crates cannot be \ + selectively imported from, must \ + use `#[macro_use]`"); + } + + if reexport.len() > 0 { + self.sess.span_err(vi.span, "`rustc-macro` crates cannot be \ + reexported from"); + } + + self.load_derive_macros(vi.span, ¯os, index, &mut ret); + } + if let Some(sel) = import.as_ref() { for (name, span) in sel { if !seen.contains(&name) { @@ -152,6 +183,54 @@ impl<'a> MacroLoader<'a> { } } - macros + return ret + } + + /// Load the custom derive macros into the list of macros we're loading. + /// + /// Note that this is intentionally similar to how we load plugins today, + /// but also intentionally separate. Plugins are likely always going to be + /// implemented as dynamic libraries, but we have a possible future where + /// custom derive (and other macro-1.1 style features) are implemented via + /// executables and custom IPC. + fn load_derive_macros(&mut self, + span: Span, + macros: &Macros, + index: DefIndex, + ret: &mut Vec) { + // Make sure the path contains a / or the linker will search for it. + let path = macros.dylib.as_ref().unwrap(); + let path = env::current_dir().unwrap().join(path); + let lib = match DynamicLibrary::open(Some(&path)) { + Ok(lib) => lib, + Err(err) => self.sess.span_fatal(span, &err), + }; + + let sym = self.sess.generate_derive_registrar_symbol(¯os.svh, index); + let registrar = unsafe { + let sym = match lib.symbol(&sym) { + Ok(f) => f, + Err(err) => self.sess.span_fatal(span, &err), + }; + mem::transmute::<*mut u8, fn(&mut Registry)>(sym) + }; + + struct MyRegistrar<'a>(&'a mut Vec); + + impl<'a> Registry for MyRegistrar<'a> { + fn register_custom_derive(&mut self, + trait_name: &str, + expand: fn(TokenStream) -> TokenStream) { + let derive = Box::new(CustomDerive::new(expand)); + self.0.push(LoadedMacro::CustomDerive(trait_name.to_string(), + derive)); + } + } + + registrar(&mut MyRegistrar(ret)); + + // Intentionally leak the dynamic library. We can't ever unload it + // since the library can make things that will live arbitrarily long. + mem::forget(lib); } } diff --git a/src/librustc_plugin/registry.rs b/src/librustc_plugin/registry.rs index 5ae6584aed42..6db821b2cd8d 100644 --- a/src/librustc_plugin/registry.rs +++ b/src/librustc_plugin/registry.rs @@ -156,7 +156,6 @@ impl<'a> Registry<'a> { self.llvm_passes.push(name.to_owned()); } - /// Register an attribute with an attribute type. /// /// Registered attributes will bypass the `custom_attribute` feature gate. diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index b21785c27dae..b970c63a2243 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -238,6 +238,7 @@ pub fn invalid_output_for_target(sess: &Session, match (sess.target.target.options.dynamic_linking, sess.target.target.options.executables, crate_type) { (false, _, config::CrateTypeCdylib) | + (false, _, config::CrateTypeRustcMacro) | (false, _, config::CrateTypeDylib) => true, (_, false, config::CrateTypeExecutable) => true, _ => false @@ -261,6 +262,7 @@ pub fn filename_for_input(sess: &Session, outputs.out_directory.join(&format!("lib{}.rlib", libname)) } config::CrateTypeCdylib | + config::CrateTypeRustcMacro | config::CrateTypeDylib => { let (prefix, suffix) = (&sess.target.target.options.dll_prefix, &sess.target.target.options.dll_suffix); @@ -291,7 +293,8 @@ pub fn each_linked_rlib(sess: &Session, let fmts = sess.dependency_formats.borrow(); let fmts = fmts.get(&config::CrateTypeExecutable) .or_else(|| fmts.get(&config::CrateTypeStaticlib)) - .or_else(|| fmts.get(&config::CrateTypeCdylib)); + .or_else(|| fmts.get(&config::CrateTypeCdylib)) + .or_else(|| fmts.get(&config::CrateTypeRustcMacro)); let fmts = fmts.unwrap_or_else(|| { bug!("could not find formats for rlibs") }); @@ -738,7 +741,8 @@ fn link_args(cmd: &mut Linker, // When linking a dynamic library, we put the metadata into a section of the // executable. This metadata is in a separate object file from the main // object file, so we link that in here. - if crate_type == config::CrateTypeDylib { + if crate_type == config::CrateTypeDylib || + crate_type == config::CrateTypeRustcMacro { cmd.add_object(&outputs.with_extension("metadata.o")); } diff --git a/src/librustc_trans/back/linker.rs b/src/librustc_trans/back/linker.rs index f2d5b128d270..58cad5c117f9 100644 --- a/src/librustc_trans/back/linker.rs +++ b/src/librustc_trans/back/linker.rs @@ -8,10 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use std::collections::HashMap; use std::ffi::OsString; use std::fs::{self, File}; -use std::io::{self, BufWriter}; use std::io::prelude::*; +use std::io::{self, BufWriter}; use std::path::{Path, PathBuf}; use std::process::Command; @@ -28,16 +29,16 @@ use syntax::ast; /// For all the linkers we support, and information they might /// need out of the shared crate context before we get rid of it. pub struct LinkerInfo { - dylib_exports: Vec, - cdylib_exports: Vec + exports: HashMap>, } impl<'a, 'tcx> LinkerInfo { pub fn new(scx: &SharedCrateContext<'a, 'tcx>, reachable: &[String]) -> LinkerInfo { LinkerInfo { - dylib_exports: exported_symbols(scx, reachable, CrateType::CrateTypeDylib), - cdylib_exports: exported_symbols(scx, reachable, CrateType::CrateTypeCdylib) + exports: scx.sess().crate_types.borrow().iter().map(|&c| { + (c, exported_symbols(scx, reachable, c)) + }).collect(), } } @@ -243,7 +244,8 @@ impl<'a> Linker for GnuLinker<'a> { // exported symbols to ensure we don't expose any more. The object files // have far more public symbols than we actually want to export, so we // hide them all here. - if crate_type == CrateType::CrateTypeDylib { + if crate_type == CrateType::CrateTypeDylib || + crate_type == CrateType::CrateTypeRustcMacro { return } @@ -254,7 +256,7 @@ impl<'a> Linker for GnuLinker<'a> { let res = (|| -> io::Result<()> { let mut f = BufWriter::new(File::create(&path)?); writeln!(f, "{{\n global:")?; - for sym in &self.info.cdylib_exports { + for sym in self.info.exports[&crate_type].iter() { writeln!(f, " {};", sym)?; } writeln!(f, "\n local:\n *;\n}};")?; @@ -274,7 +276,7 @@ impl<'a> Linker for GnuLinker<'a> { }; let res = (|| -> io::Result<()> { let mut f = BufWriter::new(File::create(&path)?); - for sym in &self.info.cdylib_exports { + for sym in self.info.exports[&crate_type].iter() { writeln!(f, "{}{}", prefix, sym)?; } Ok(()) @@ -427,12 +429,7 @@ impl<'a> Linker for MsvcLinker<'a> { // straight to exports. writeln!(f, "LIBRARY")?; writeln!(f, "EXPORTS")?; - let symbols = if crate_type == CrateType::CrateTypeCdylib { - &self.info.cdylib_exports - } else { - &self.info.dylib_exports - }; - for symbol in symbols { + for symbol in self.info.exports[&crate_type].iter() { writeln!(f, " {}", symbol)?; } Ok(()) @@ -450,13 +447,10 @@ fn exported_symbols(scx: &SharedCrateContext, reachable: &[String], crate_type: CrateType) -> Vec { - if !scx.sess().crate_types.borrow().contains(&crate_type) { - return vec![]; - } - // See explanation in GnuLinker::export_symbols, for // why we don't ever need dylib symbols on non-MSVC. - if crate_type == CrateType::CrateTypeDylib { + if crate_type == CrateType::CrateTypeDylib || + crate_type == CrateType::CrateTypeRustcMacro { if !scx.sess().target.target.options.is_like_msvc { return vec![]; } diff --git a/src/librustc_trans/back/symbol_names.rs b/src/librustc_trans/back/symbol_names.rs index 9b02cbe6721f..143275fa7117 100644 --- a/src/librustc_trans/back/symbol_names.rs +++ b/src/librustc_trans/back/symbol_names.rs @@ -188,6 +188,11 @@ impl<'a, 'tcx> Instance<'tcx> { let idx = def_id.index; return scx.sess().generate_plugin_registrar_symbol(svh, idx); } + if scx.sess().derive_registrar_fn.get() == Some(id) { + let svh = &scx.link_meta().crate_hash; + let idx = def_id.index; + return scx.sess().generate_derive_registrar_symbol(svh, idx); + } } // FIXME(eddyb) Precompute a custom symbol name based on attributes. diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 43e190f5deb8..3b1c01319c49 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -27,10 +27,10 @@ use ptr::P; use util::small_vector::SmallVector; use util::lev_distance::find_best_match_for_name; use fold::Folder; +use feature_gate; use std::collections::{HashMap, HashSet}; use std::rc::Rc; -use std::default::Default; use tokenstream; @@ -568,12 +568,18 @@ fn initial_syntax_expander_table<'feat>(ecfg: &expand::ExpansionConfig<'feat>) } pub trait MacroLoader { - fn load_crate(&mut self, extern_crate: &ast::Item, allows_macros: bool) -> Vec; + fn load_crate(&mut self, extern_crate: &ast::Item, allows_macros: bool) + -> Vec; +} + +pub enum LoadedMacro { + Def(ast::MacroDef), + CustomDerive(String, Box), } pub struct DummyMacroLoader; impl MacroLoader for DummyMacroLoader { - fn load_crate(&mut self, _: &ast::Item, _: bool) -> Vec { + fn load_crate(&mut self, _: &ast::Item, _: bool) -> Vec { Vec::new() } } @@ -593,6 +599,7 @@ pub struct ExtCtxt<'a> { pub exported_macros: Vec, pub syntax_env: SyntaxEnv, + pub derive_modes: HashMap>, pub recursion_count: usize, pub filename: Option, @@ -616,6 +623,7 @@ impl<'a> ExtCtxt<'a> { exported_macros: Vec::new(), loader: loader, syntax_env: env, + derive_modes: HashMap::new(), recursion_count: 0, filename: None, @@ -714,6 +722,25 @@ impl<'a> ExtCtxt<'a> { } } + pub fn insert_custom_derive(&mut self, + name: &str, + ext: Box, + sp: Span) { + if !self.ecfg.enable_rustc_macro() { + feature_gate::emit_feature_err(&self.parse_sess.span_diagnostic, + "rustc_macro", + sp, + feature_gate::GateIssue::Language, + "loading custom derive macro crates \ + is experimentally supported"); + } + let name = token::intern_and_get_ident(name); + if self.derive_modes.insert(name.clone(), ext).is_some() { + self.span_err(sp, &format!("cannot shadow existing derive mode `{}`", + name)); + } + } + pub fn struct_span_warn(&self, sp: Span, msg: &str) diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 15ebf95d6239..d06b77a5b054 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -440,8 +440,7 @@ fn expand_annotatable(mut item: Annotatable, fld: &mut MacroExpander) -> SmallVe callee: NameAndSpan { format: MacroAttribute(intern(&attr.name())), span: Some(attr.span), - // attributes can do whatever they like, for now - allow_internal_unstable: true, + allow_internal_unstable: false, } }); @@ -538,7 +537,12 @@ impl<'a, 'b> MacroExpander<'a, 'b> { // We need to error on `#[macro_use] extern crate` when it isn't at the // crate root, because `$crate` won't work properly. for def in self.cx.loader.load_crate(item, self.at_crate_root) { - self.cx.insert_macro(def); + match def { + LoadedMacro::Def(def) => self.cx.insert_macro(def), + LoadedMacro::CustomDerive(name, ext) => { + self.cx.insert_custom_derive(&name, ext, item.span); + } + } } } else { let at_crate_root = ::std::mem::replace(&mut self.at_crate_root, false); @@ -688,6 +692,7 @@ impl<'feat> ExpansionConfig<'feat> { fn enable_allow_internal_unstable = allow_internal_unstable, fn enable_custom_derive = custom_derive, fn enable_pushpop_unsafe = pushpop_unsafe, + fn enable_rustc_macro = rustc_macro, } } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 02c44c3a56d7..683d5277359e 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -47,7 +47,7 @@ macro_rules! setter { } macro_rules! declare_features { - ($((active, $feature: ident, $ver: expr, $issue: expr)),+) => { + ($((active, $feature: ident, $ver: expr, $issue: expr),)+) => { /// Represents active features that are currently being implemented or /// currently being considered for addition/removal. const ACTIVE_FEATURES: &'static [(&'static str, &'static str, @@ -75,14 +75,14 @@ macro_rules! declare_features { } }; - ($((removed, $feature: ident, $ver: expr, $issue: expr)),+) => { + ($((removed, $feature: ident, $ver: expr, $issue: expr),)+) => { /// Represents features which has since been removed (it was once Active) const REMOVED_FEATURES: &'static [(&'static str, &'static str, Option)] = &[ $((stringify!($feature), $ver, $issue)),+ ]; }; - ($((accepted, $feature: ident, $ver: expr, $issue: expr)),+) => { + ($((accepted, $feature: ident, $ver: expr, $issue: expr),)+) => { /// Those language feature has since been Accepted (it was once Active) const ACCEPTED_FEATURES: &'static [(&'static str, &'static str, Option)] = &[ $((stringify!($feature), $ver, $issue)),+ @@ -288,7 +288,10 @@ declare_features! ( (active, abi_sysv64, "1.13.0", Some(36167)), // Use the import semantics from RFC 1560. - (active, item_like_imports, "1.13.0", Some(35120)) + (active, item_like_imports, "1.13.0", Some(35120)), + + // Macros 1.1 + (active, rustc_macro, "1.13.0", Some(35900)), ); declare_features! ( @@ -302,7 +305,6 @@ declare_features! ( (removed, struct_inherit, "1.0.0", None), (removed, test_removed_feature, "1.0.0", None), (removed, visible_private_types, "1.0.0", None), - (removed, unsafe_no_drop_flag, "1.0.0", None) ); declare_features! ( @@ -330,7 +332,7 @@ declare_features! ( (accepted, type_macros, "1.13.0", Some(27245)), (accepted, while_let, "1.0.0", None), // Allows `#[deprecated]` attribute - (accepted, deprecated, "1.9.0", Some(29935)) + (accepted, deprecated, "1.9.0", Some(29935)), ); // (changing above list without updating src/doc/reference.md makes @cmr sad) @@ -543,6 +545,15 @@ pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeGat is an experimental feature", cfg_fn!(linked_from))), + ("rustc_macro_derive", Normal, Gated("rustc_macro", + "the `#[rustc_macro_derive]` attribute \ + is an experimental feature", + cfg_fn!(rustc_macro))), + + ("rustc_copy_clone_marker", Whitelisted, Gated("rustc_attrs", + "internal implementation detail", + cfg_fn!(rustc_attrs))), + // FIXME: #14408 whitelist docs since rustdoc looks at them ("doc", Whitelisted, Ungated), @@ -616,6 +627,7 @@ const GATED_CFGS: &'static [(&'static str, &'static str, fn(&Features) -> bool)] ("target_vendor", "cfg_target_vendor", cfg_fn!(cfg_target_vendor)), ("target_thread_local", "cfg_target_thread_local", cfg_fn!(cfg_target_thread_local)), ("target_has_atomic", "cfg_target_has_atomic", cfg_fn!(cfg_target_has_atomic)), + ("rustc_macro", "rustc_macro", cfg_fn!(rustc_macro)), ]; #[derive(Debug, Eq, PartialEq)] diff --git a/src/libsyntax_ext/Cargo.toml b/src/libsyntax_ext/Cargo.toml index 040c6c8ebff2..6910e6400d4f 100644 --- a/src/libsyntax_ext/Cargo.toml +++ b/src/libsyntax_ext/Cargo.toml @@ -11,6 +11,7 @@ crate-type = ["dylib"] [dependencies] fmt_macros = { path = "../libfmt_macros" } log = { path = "../liblog" } +rustc_errors = { path = "../librustc_errors" } +rustc_macro = { path = "../librustc_macro" } syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } -rustc_errors = { path = "../librustc_errors" } \ No newline at end of file diff --git a/src/libsyntax_ext/deriving/clone.rs b/src/libsyntax_ext/deriving/clone.rs index f1a3a1f41b14..c7afaaf4796a 100644 --- a/src/libsyntax_ext/deriving/clone.rs +++ b/src/libsyntax_ext/deriving/clone.rs @@ -49,7 +49,7 @@ pub fn expand_deriving_clone(cx: &mut ExtCtxt, ItemKind::Struct(_, Generics { ref ty_params, .. }) | ItemKind::Enum(_, Generics { ref ty_params, .. }) if ty_params.is_empty() && - attr::contains_name(&annitem.attrs, "derive_Copy") => { + attr::contains_name(&annitem.attrs, "rustc_copy_clone_marker") => { bounds = vec![Literal(path_std!(cx, core::marker::Copy))]; unify_fieldless_variants = true; @@ -110,12 +110,12 @@ fn cs_clone(name: &str, Mode::Shallow => cx.std_path(&["clone", "assert_receiver_is_clone"]), Mode::Deep => cx.std_path(&["clone", "Clone", "clone"]), }; - let subcall = |field: &FieldInfo| { + let subcall = |cx: &mut ExtCtxt, field: &FieldInfo| { let args = vec![cx.expr_addr_of(field.span, field.self_.clone())]; let span = if mode == Mode::Shallow { // set the expn ID so we can call the unstable method - Span { expn_id: cx.backtrace(), ..trait_span } + super::allow_unstable(cx, field.span, "derive(Clone)") } else { field.span }; @@ -147,8 +147,10 @@ fn cs_clone(name: &str, match mode { Mode::Shallow => { - let mut stmts: Vec<_> = - all_fields.iter().map(subcall).map(|e| cx.stmt_expr(e)).collect(); + let mut stmts = all_fields.iter().map(|f| { + let call = subcall(cx, f); + cx.stmt_expr(call) + }).collect::>(); stmts.push(cx.stmt_expr(cx.expr_deref(trait_span, cx.expr_self(trait_span)))); cx.expr_block(cx.block(trait_span, stmts)) } @@ -166,14 +168,15 @@ fn cs_clone(name: &str, name)) } }; - cx.field_imm(field.span, ident, subcall(field)) + let call = subcall(cx, field); + cx.field_imm(field.span, ident, call) }) .collect::>(); cx.expr_struct(trait_span, ctor_path, fields) } VariantData::Tuple(..) => { - let subcalls = all_fields.iter().map(subcall).collect(); + let subcalls = all_fields.iter().map(|f| subcall(cx, f)).collect(); let path = cx.expr_path(ctor_path); cx.expr_call(trait_span, path, subcalls) } diff --git a/src/libsyntax_ext/deriving/custom.rs b/src/libsyntax_ext/deriving/custom.rs new file mode 100644 index 000000000000..1f9c24a0dcd6 --- /dev/null +++ b/src/libsyntax_ext/deriving/custom.rs @@ -0,0 +1,97 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::panic; + +use rustc_macro::{TokenStream, __internal}; +use syntax::ast::{self, ItemKind}; +use syntax::codemap::Span; +use syntax::ext::base::*; +use syntax::fold::{self, Folder}; +use errors::FatalError; + +pub struct CustomDerive { + inner: fn(TokenStream) -> TokenStream, +} + +impl CustomDerive { + pub fn new(inner: fn(TokenStream) -> TokenStream) -> CustomDerive { + CustomDerive { inner: inner } + } +} + +impl MultiItemModifier for CustomDerive { + fn expand(&self, + ecx: &mut ExtCtxt, + span: Span, + _meta_item: &ast::MetaItem, + item: Annotatable) + -> Vec { + let item = match item { + Annotatable::Item(item) => item, + Annotatable::ImplItem(_) | + Annotatable::TraitItem(_) => { + ecx.span_err(span, "custom derive attributes may only be \ + applied to struct/enum items"); + return Vec::new() + } + }; + match item.node { + ItemKind::Struct(..) | + ItemKind::Enum(..) => {} + _ => { + ecx.span_err(span, "custom derive attributes may only be \ + applied to struct/enum items"); + return Vec::new() + } + } + + let input = __internal::new_token_stream(item); + let res = __internal::set_parse_sess(&ecx.parse_sess, || { + let inner = self.inner; + panic::catch_unwind(panic::AssertUnwindSafe(|| inner(input))) + }); + let item = match res { + Ok(stream) => __internal::token_stream_items(stream), + Err(e) => { + let msg = "custom derive attribute panicked"; + let mut err = ecx.struct_span_fatal(span, msg); + if let Some(s) = e.downcast_ref::() { + err.help(&format!("message: {}", s)); + } + if let Some(s) = e.downcast_ref::<&'static str>() { + err.help(&format!("message: {}", s)); + } + + err.emit(); + panic!(FatalError); + } + }; + + // Right now we have no knowledge of spans at all in custom derive + // macros, everything is just parsed as a string. Reassign all spans to + // the #[derive] attribute for better errors here. + item.into_iter().flat_map(|item| { + ChangeSpan { span: span }.fold_item(item) + }).map(Annotatable::Item).collect() + } +} + +struct ChangeSpan { span: Span } + +impl Folder for ChangeSpan { + fn new_span(&mut self, _sp: Span) -> Span { + self.span + } + + fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac { + fold::noop_fold_mac(mac, self) + } +} diff --git a/src/libsyntax_ext/deriving/mod.rs b/src/libsyntax_ext/deriving/mod.rs index 81085122e875..5582166c12e9 100644 --- a/src/libsyntax_ext/deriving/mod.rs +++ b/src/libsyntax_ext/deriving/mod.rs @@ -12,7 +12,7 @@ use syntax::ast::{self, MetaItem}; use syntax::ext::base::{Annotatable, ExtCtxt, SyntaxEnv}; -use syntax::ext::base::{MultiDecorator, MultiItemDecorator, MultiModifier}; +use syntax::ext::base::MultiModifier; use syntax::ext::build::AstBuilder; use syntax::feature_gate; use syntax::codemap; @@ -61,6 +61,7 @@ pub mod decodable; pub mod hash; pub mod debug; pub mod default; +pub mod custom; #[path="cmp/partial_eq.rs"] pub mod partial_eq; @@ -74,156 +75,201 @@ pub mod ord; pub mod generic; +fn allow_unstable(cx: &mut ExtCtxt, span: Span, attr_name: &str) -> Span { + Span { + expn_id: cx.codemap().record_expansion(codemap::ExpnInfo { + call_site: span, + callee: codemap::NameAndSpan { + format: codemap::MacroAttribute(intern(attr_name)), + span: Some(span), + allow_internal_unstable: true, + }, + }), + ..span + } +} + fn expand_derive(cx: &mut ExtCtxt, span: Span, mitem: &MetaItem, annotatable: Annotatable) - -> Annotatable { + -> Vec { debug!("expand_derive: span = {:?}", span); debug!("expand_derive: mitem = {:?}", mitem); debug!("expand_derive: annotatable input = {:?}", annotatable); - let annot = annotatable.map_item_or(|item| { - item.map(|mut item| { - if mitem.value_str().is_some() { - cx.span_err(mitem.span, "unexpected value in `derive`"); + let mut item = match annotatable { + Annotatable::Item(item) => item, + other => { + cx.span_err(span, "`derive` can only be applied to items"); + return vec![other] + } + }; + + if mitem.value_str().is_some() { + cx.span_err(mitem.span, "unexpected value in `derive`"); + } + + let traits = mitem.meta_item_list().unwrap_or(&[]); + if traits.is_empty() { + cx.span_warn(mitem.span, "empty trait list in `derive`"); + } + + // RFC #1445. `#[derive(PartialEq, Eq)]` adds a (trusted) + // `#[structural_match]` attribute. + if traits.iter().filter_map(|t| t.name()).any(|t| t == "PartialEq") && + traits.iter().filter_map(|t| t.name()).any(|t| t == "Eq") { + let structural_match = intern_and_get_ident("structural_match"); + let span = allow_unstable(cx, span, "derive(PartialEq, Eq)"); + let meta = cx.meta_word(span, structural_match); + item = item.map(|mut i| { + i.attrs.push(cx.attribute(span, meta)); + i + }); + } + + // RFC #1521. `Clone` can assume that `Copy` types' clone implementation is + // the same as the copy implementation. + // + // Add a marker attribute here picked up during #[derive(Clone)] + if traits.iter().filter_map(|t| t.name()).any(|t| t == "Clone") && + traits.iter().filter_map(|t| t.name()).any(|t| t == "Copy") { + let marker = intern_and_get_ident("rustc_copy_clone_marker"); + let span = allow_unstable(cx, span, "derive(Copy, Clone)"); + let meta = cx.meta_word(span, marker); + item = item.map(|mut i| { + i.attrs.push(cx.attribute(span, meta)); + i + }); + } + + let mut other_items = Vec::new(); + + let mut iter = traits.iter(); + while let Some(titem) = iter.next() { + + let tword = match titem.word() { + Some(name) => name, + None => { + cx.span_err(titem.span, "malformed `derive` entry"); + continue } + }; + let tname = tword.name(); - let traits = mitem.meta_item_list().unwrap_or(&[]); - if traits.is_empty() { - cx.span_warn(mitem.span, "empty trait list in `derive`"); + // If this is a built-in derive mode, then we expand it immediately + // here. + if is_builtin_trait(&tname) { + let name = intern_and_get_ident(&format!("derive({})", tname)); + let mitem = cx.meta_word(titem.span, name); + + let span = Span { + expn_id: cx.codemap().record_expansion(codemap::ExpnInfo { + call_site: titem.span, + callee: codemap::NameAndSpan { + format: codemap::MacroAttribute(intern(&format!("derive({})", tname))), + span: Some(titem.span), + allow_internal_unstable: true, + }, + }), + ..titem.span + }; + + let my_item = Annotatable::Item(item); + expand_builtin(&tname, cx, span, &mitem, &my_item, &mut |a| { + other_items.push(a); + }); + item = my_item.expect_item(); + + // Otherwise if this is a `rustc_macro`-style derive mode, we process it + // here. The logic here is to: + // + // 1. Collect the remaining `#[derive]` annotations into a list. If + // there are any left, attach a `#[derive]` attribute to the item + // that we're currently expanding with the remaining derive modes. + // 2. Manufacture a `#[derive(Foo)]` attribute to pass to the expander. + // 3. Expand the current item we're expanding, getting back a list of + // items that replace it. + // 4. Extend the returned list with the current list of items we've + // collected so far. + // 5. Return everything! + // + // If custom derive extensions end up threading through the `#[derive]` + // attribute, we'll get called again later on to continue expanding + // those modes. + } else if let Some(ext) = cx.derive_modes.remove(&tname) { + let remaining_derives = iter.cloned().collect::>(); + if remaining_derives.len() > 0 { + let list = cx.meta_list(titem.span, + intern_and_get_ident("derive"), + remaining_derives); + let attr = cx.attribute(titem.span, list); + item = item.map(|mut i| { + i.attrs.push(attr); + i + }); } + let titem = cx.meta_list_item_word(titem.span, tname.clone()); + let mitem = cx.meta_list(titem.span, + intern_and_get_ident("derive"), + vec![titem]); + let item = Annotatable::Item(item); + let mut items = ext.expand(cx, mitem.span, &mitem, item); + items.extend(other_items); + cx.derive_modes.insert(tname.clone(), ext); + return items - let mut found_partial_eq = false; - let mut eq_span = None; + // If we've gotten this far then it means that we're in the territory of + // the old custom derive mechanism. If the feature isn't enabled, we + // issue an error, otherwise manufacture the `derive_Foo` attribute. + } else if !cx.ecfg.enable_custom_derive() { + feature_gate::emit_feature_err(&cx.parse_sess.span_diagnostic, + "custom_derive", + titem.span, + feature_gate::GateIssue::Language, + feature_gate::EXPLAIN_CUSTOM_DERIVE); + } else { + let name = intern_and_get_ident(&format!("derive_{}", tname)); + let mitem = cx.meta_word(titem.span, name); + item = item.map(|mut i| { + i.attrs.push(cx.attribute(mitem.span, mitem)); + i + }); + } + } - for titem in traits.iter().rev() { - let tname = if let Some(word) = titem.word() { - word.name() - } else { - cx.span_err(titem.span, "malformed `derive` entry"); - continue; - }; - - if !(is_builtin_trait(&tname) || cx.ecfg.enable_custom_derive()) { - feature_gate::emit_feature_err(&cx.parse_sess.span_diagnostic, - "custom_derive", - titem.span, - feature_gate::GateIssue::Language, - feature_gate::EXPLAIN_CUSTOM_DERIVE); - continue; - } - - let span = Span { - expn_id: cx.codemap().record_expansion(codemap::ExpnInfo { - call_site: titem.span, - callee: codemap::NameAndSpan { - format: codemap::MacroAttribute(intern(&format!("derive({})", tname))), - span: Some(titem.span), - allow_internal_unstable: true, - }, - }), - ..titem.span - }; - - if &tname[..] == "Eq" { - eq_span = Some(span); - } else if &tname[..] == "PartialEq" { - found_partial_eq = true; - } - - // #[derive(Foo, Bar)] expands to #[derive_Foo] #[derive_Bar] - item.attrs.push(cx.attribute(span, - cx.meta_word(titem.span, - intern_and_get_ident(&format!("derive_{}", tname))))); - } - - // RFC #1445. `#[derive(PartialEq, Eq)]` adds a (trusted) - // `#[structural_match]` attribute. - if let Some(eq_span) = eq_span { - if found_partial_eq { - let structural_match = intern_and_get_ident("structural_match"); - item.attrs.push(cx.attribute(eq_span, cx.meta_word(eq_span, structural_match))); - } - } - - item - }) - }, - |a| { - cx.span_err(span, - "`derive` can only be applied to items"); - a - }); - debug!("expand_derive: annotatable output = {:?}", annot); - annot + other_items.insert(0, Annotatable::Item(item)); + return other_items } macro_rules! derive_traits { ($( $name:expr => $func:path, )+) => { pub fn register_all(env: &mut SyntaxEnv) { - // Define the #[derive_*] extensions. - $({ - struct DeriveExtension; - - impl MultiItemDecorator for DeriveExtension { - fn expand(&self, - ecx: &mut ExtCtxt, - sp: Span, - mitem: &MetaItem, - annotatable: &Annotatable, - push: &mut FnMut(Annotatable)) { - if !ecx.parse_sess.codemap().span_allows_unstable(sp) - && !ecx.ecfg.features.unwrap().custom_derive { - // FIXME: - // https://github.com/rust-lang/rust/pull/32671#issuecomment-206245303 - // This is just to avoid breakage with syntex. - // Remove that to spawn an error instead. - let cm = ecx.parse_sess.codemap(); - let parent = cm.with_expn_info(ecx.backtrace(), - |info| info.unwrap().call_site.expn_id); - cm.with_expn_info(parent, |info| { - if info.is_some() { - let mut w = ecx.parse_sess.span_diagnostic.struct_span_warn( - sp, feature_gate::EXPLAIN_DERIVE_UNDERSCORE, - ); - if option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_none() { - w.help( - &format!("add #![feature(custom_derive)] to \ - the crate attributes to enable") - ); - } - w.emit(); - } else { - feature_gate::emit_feature_err( - &ecx.parse_sess.span_diagnostic, - "custom_derive", sp, feature_gate::GateIssue::Language, - feature_gate::EXPLAIN_DERIVE_UNDERSCORE - ); - - return; - } - }) - } - - warn_if_deprecated(ecx, sp, $name); - $func(ecx, sp, mitem, annotatable, push); - } - } - - env.insert(intern(concat!("derive_", $name)), - MultiDecorator(Box::new(DeriveExtension))); - })+ - - env.insert(intern("derive"), - MultiModifier(Box::new(expand_derive))); + env.insert(intern("derive"), MultiModifier(Box::new(expand_derive))); } - fn is_builtin_trait(name: &str) -> bool { + pub fn is_builtin_trait(name: &str) -> bool { match name { $( $name )|+ => true, _ => false, } } + + fn expand_builtin(name: &str, + ecx: &mut ExtCtxt, + span: Span, + mitem: &MetaItem, + item: &Annotatable, + push: &mut FnMut(Annotatable)) { + match name { + $( + $name => { + warn_if_deprecated(ecx, span, $name); + $func(ecx, span, mitem, item, push); + } + )* + _ => panic!("not a builtin derive mode: {}", name), + } + } } } diff --git a/src/libsyntax_ext/lib.rs b/src/libsyntax_ext/lib.rs index 3aa62339b477..4bae9ec5a1a1 100644 --- a/src/libsyntax_ext/lib.rs +++ b/src/libsyntax_ext/lib.rs @@ -19,6 +19,8 @@ html_root_url = "https://doc.rust-lang.org/nightly/")] #![cfg_attr(not(stage0), deny(warnings))] +#![feature(rustc_macro_lib)] +#![feature(rustc_macro_internals)] #![feature(rustc_private)] #![feature(staged_api)] @@ -28,6 +30,7 @@ extern crate log; #[macro_use] extern crate syntax; extern crate syntax_pos; +extern crate rustc_macro; extern crate rustc_errors as errors; use syntax::ext::base::{MacroExpanderFn, NormalTT}; @@ -44,6 +47,8 @@ mod format; mod log_syntax; mod trace_macros; +pub mod rustc_macro_registrar; + // for custom_derive pub mod deriving; diff --git a/src/libsyntax_ext/rustc_macro_registrar.rs b/src/libsyntax_ext/rustc_macro_registrar.rs new file mode 100644 index 000000000000..7693e2416f4b --- /dev/null +++ b/src/libsyntax_ext/rustc_macro_registrar.rs @@ -0,0 +1,280 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::mem; + +use errors; +use syntax::ast::{self, Ident, NodeId}; +use syntax::codemap::{ExpnInfo, NameAndSpan, MacroAttribute}; +use syntax::ext::base::{ExtCtxt, DummyMacroLoader}; +use syntax::ext::build::AstBuilder; +use syntax::ext::expand::ExpansionConfig; +use syntax::parse::ParseSess; +use syntax::parse::token::{self, InternedString}; +use syntax::feature_gate::Features; +use syntax::ptr::P; +use syntax_pos::{Span, DUMMY_SP}; +use syntax::visit::{self, Visitor}; + +use deriving; + +struct CustomDerive { + trait_name: InternedString, + function_name: Ident, + span: Span, +} + +struct CollectCustomDerives<'a> { + derives: Vec, + in_root: bool, + handler: &'a errors::Handler, + is_rustc_macro_crate: bool, +} + +pub fn modify(sess: &ParseSess, + mut krate: ast::Crate, + is_rustc_macro_crate: bool, + num_crate_types: usize, + handler: &errors::Handler, + features: &Features) -> ast::Crate { + let mut loader = DummyMacroLoader; + let mut cx = ExtCtxt::new(sess, + Vec::new(), + ExpansionConfig::default("rustc_macro".to_string()), + &mut loader); + + let mut collect = CollectCustomDerives { + derives: Vec::new(), + in_root: true, + handler: handler, + is_rustc_macro_crate: is_rustc_macro_crate, + }; + visit::walk_crate(&mut collect, &krate); + + if !is_rustc_macro_crate { + return krate + } else if !features.rustc_macro { + let mut err = handler.struct_err("the `rustc-macro` crate type is \ + experimental"); + err.help("add #![feature(rustc_macro)] to the crate attributes to \ + enable"); + err.emit(); + } + + if num_crate_types > 1 { + handler.err("cannot mix `rustc-macro` crate type with others"); + } + + krate.module.items.push(mk_registrar(&mut cx, &collect.derives)); + + if krate.exported_macros.len() > 0 { + handler.err("cannot export macro_rules! macros from a `rustc-macro` \ + crate type currently"); + } + + return krate +} + +impl<'a> CollectCustomDerives<'a> { + fn check_not_pub_in_root(&self, vis: &ast::Visibility, sp: Span) { + if self.is_rustc_macro_crate && + self.in_root && + *vis == ast::Visibility::Public { + self.handler.span_err(sp, + "`rustc-macro` crate types cannot \ + export any items other than functions \ + tagged with `#[rustc_macro_derive]` \ + currently"); + } + } +} + +impl<'a> Visitor for CollectCustomDerives<'a> { + fn visit_item(&mut self, item: &ast::Item) { + // First up, make sure we're checking a bare function. If we're not then + // we're just not interested in this item. + // + // If we find one, try to locate a `#[rustc_macro_derive]` attribute on + // it. + match item.node { + ast::ItemKind::Fn(..) => {} + _ => { + self.check_not_pub_in_root(&item.vis, item.span); + return visit::walk_item(self, item) + } + } + + let mut attrs = item.attrs.iter() + .filter(|a| a.check_name("rustc_macro_derive")); + let attr = match attrs.next() { + Some(attr) => attr, + None => { + self.check_not_pub_in_root(&item.vis, item.span); + return visit::walk_item(self, item) + } + }; + + if let Some(a) = attrs.next() { + self.handler.span_err(a.span(), "multiple `#[rustc_macro_derive]` \ + attributes found"); + } + + if !self.is_rustc_macro_crate { + self.handler.span_err(attr.span(), + "the `#[rustc_macro_derive]` attribute is \ + only usable with crates of the `rustc-macro` \ + crate type"); + } + + // Once we've located the `#[rustc_macro_derive]` attribute, verify + // that it's of the form `#[rustc_macro_derive(Foo)]` + let list = match attr.meta_item_list() { + Some(list) => list, + None => { + self.handler.span_err(attr.span(), + "attribute must be of form: \ + #[rustc_macro_derive(TraitName)]"); + return + } + }; + if list.len() != 1 { + self.handler.span_err(attr.span(), + "attribute must only have one argument"); + return + } + let attr = &list[0]; + let trait_name = match attr.name() { + Some(name) => name, + _ => { + self.handler.span_err(attr.span(), "not a meta item"); + return + } + }; + if !attr.is_word() { + self.handler.span_err(attr.span(), "must only be one word"); + } + + if deriving::is_builtin_trait(&trait_name) { + self.handler.span_err(attr.span(), + "cannot override a built-in #[derive] mode"); + } + + if self.derives.iter().any(|d| d.trait_name == trait_name) { + self.handler.span_err(attr.span(), + "derive mode defined twice in this crate"); + } + + if self.in_root { + self.derives.push(CustomDerive { + span: item.span, + trait_name: trait_name, + function_name: item.ident, + }); + } else { + let msg = "functions tagged with `#[rustc_macro_derive]` must \ + currently reside in the root of the crate"; + self.handler.span_err(item.span, msg); + } + + visit::walk_item(self, item); + } + + fn visit_mod(&mut self, m: &ast::Mod, _s: Span, id: NodeId) { + let mut prev_in_root = self.in_root; + if id != ast::CRATE_NODE_ID { + prev_in_root = mem::replace(&mut self.in_root, false); + } + visit::walk_mod(self, m); + self.in_root = prev_in_root; + } + + fn visit_mac(&mut self, mac: &ast::Mac) { + visit::walk_mac(self, mac) + } +} + +// Creates a new module which looks like: +// +// mod $gensym { +// extern crate rustc_macro; +// +// use rustc_macro::__internal::Registry; +// +// #[plugin_registrar] +// fn registrar(registrar: &mut Registry) { +// registrar.register_custom_derive($name_trait1, ::$name1); +// registrar.register_custom_derive($name_trait2, ::$name2); +// // ... +// } +// } +fn mk_registrar(cx: &mut ExtCtxt, + custom_derives: &[CustomDerive]) -> P { + let eid = cx.codemap().record_expansion(ExpnInfo { + call_site: DUMMY_SP, + callee: NameAndSpan { + format: MacroAttribute(token::intern("rustc_macro")), + span: None, + allow_internal_unstable: true, + } + }); + let span = Span { expn_id: eid, ..DUMMY_SP }; + + let rustc_macro = token::str_to_ident("rustc_macro"); + let krate = cx.item(span, + rustc_macro, + Vec::new(), + ast::ItemKind::ExternCrate(None)); + + let __internal = token::str_to_ident("__internal"); + let registry = token::str_to_ident("Registry"); + let registrar = token::str_to_ident("registrar"); + let register_custom_derive = token::str_to_ident("register_custom_derive"); + let stmts = custom_derives.iter().map(|cd| { + let path = cx.path_global(cd.span, vec![cd.function_name]); + let trait_name = cx.expr_str(cd.span, cd.trait_name.clone()); + (path, trait_name) + }).map(|(path, trait_name)| { + let registrar = cx.expr_ident(span, registrar); + let ufcs_path = cx.path(span, vec![rustc_macro, __internal, registry, + register_custom_derive]); + cx.expr_call(span, + cx.expr_path(ufcs_path), + vec![registrar, trait_name, cx.expr_path(path)]) + }).map(|expr| { + cx.stmt_expr(expr) + }).collect::>(); + + let path = cx.path(span, vec![rustc_macro, __internal, registry]); + let registrar_path = cx.ty_path(path); + let arg_ty = cx.ty_rptr(span, registrar_path, None, ast::Mutability::Mutable); + let func = cx.item_fn(span, + registrar, + vec![cx.arg(span, registrar, arg_ty)], + cx.ty(span, ast::TyKind::Tup(Vec::new())), + cx.block(span, stmts)); + + let derive_registrar = token::intern_and_get_ident("rustc_derive_registrar"); + let derive_registrar = cx.meta_word(span, derive_registrar); + let derive_registrar = cx.attribute(span, derive_registrar); + let func = func.map(|mut i| { + i.attrs.push(derive_registrar); + i.vis = ast::Visibility::Public; + i + }); + let module = cx.item_mod(span, + span, + ast::Ident::with_empty_ctxt(token::gensym("registrar")), + Vec::new(), + vec![krate, func]); + module.map(|mut i| { + i.vis = ast::Visibility::Public; + i + }) +} diff --git a/src/rustc/Cargo.lock b/src/rustc/Cargo.lock index fde2f83e220f..3377fc43d8a6 100644 --- a/src/rustc/Cargo.lock +++ b/src/rustc/Cargo.lock @@ -214,6 +214,13 @@ dependencies = [ "rustc_bitflags 0.0.0", ] +[[package]] +name = "rustc_macro" +version = "0.0.0" +dependencies = [ + "syntax 0.0.0", +] + [[package]] name = "rustc_metadata" version = "0.0.0" @@ -228,8 +235,10 @@ dependencies = [ "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", "rustc_llvm 0.0.0", + "rustc_macro 0.0.0", "serialize 0.0.0", "syntax 0.0.0", + "syntax_ext 0.0.0", "syntax_pos 0.0.0", ] @@ -400,6 +409,7 @@ dependencies = [ "fmt_macros 0.0.0", "log 0.0.0", "rustc_errors 0.0.0", + "rustc_macro 0.0.0", "syntax 0.0.0", "syntax_pos 0.0.0", ] diff --git a/src/test/compile-fail-fulldeps/rustc-macro/append-impl.rs b/src/test/compile-fail-fulldeps/rustc-macro/append-impl.rs new file mode 100644 index 000000000000..fa0b5763803f --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/append-impl.rs @@ -0,0 +1,33 @@ +// 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. + +// aux-build:append-impl.rs + +#![feature(rustc_macro)] +#![allow(warnings)] + +#[macro_use] +extern crate append_impl; + +trait Append { + fn foo(&self); +} + +#[derive(PartialEq, + Append, + Eq)] +//~^^ ERROR: the semantics of constant patterns is not yet settled +struct A { + inner: u32, +} + +fn main() { + A { inner: 3 }.foo(); +} diff --git a/src/test/compile-fail-fulldeps/rustc-macro/at-the-root.rs b/src/test/compile-fail-fulldeps/rustc-macro/at-the-root.rs new file mode 100644 index 000000000000..46724523d1c7 --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/at-the-root.rs @@ -0,0 +1,25 @@ +// 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. + +#![crate_type = "rustc-macro"] +#![feature(rustc_macro)] + +extern crate rustc_macro; + +pub mod a { //~ `rustc-macro` crate types cannot export any items + use rustc_macro::TokenStream; + + #[rustc_macro_derive(B)] + pub fn bar(a: TokenStream) -> TokenStream { + //~^ ERROR: must currently reside in the root of the crate + a + } +} + diff --git a/src/test/compile-fail-fulldeps/rustc-macro/attribute.rs b/src/test/compile-fail-fulldeps/rustc-macro/attribute.rs new file mode 100644 index 000000000000..7740238aeacc --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/attribute.rs @@ -0,0 +1,46 @@ +// 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. + +#![crate_type = "rustc-macro"] +#![feature(rustc_macro)] + +extern crate rustc_macro; + +#[rustc_macro_derive] +//~^ ERROR: attribute must be of form: #[rustc_macro_derive(TraitName)] +pub fn foo1(input: rustc_macro::TokenStream) -> rustc_macro::TokenStream { + input +} + +#[rustc_macro_derive = "foo"] +//~^ ERROR: attribute must be of form: #[rustc_macro_derive(TraitName)] +pub fn foo2(input: rustc_macro::TokenStream) -> rustc_macro::TokenStream { + input +} + +#[rustc_macro_derive( + a = "b" +)] +//~^^ ERROR: must only be one word +pub fn foo3(input: rustc_macro::TokenStream) -> rustc_macro::TokenStream { + input +} + +#[rustc_macro_derive(b, c)] +//~^ ERROR: attribute must only have one argument +pub fn foo4(input: rustc_macro::TokenStream) -> rustc_macro::TokenStream { + input +} + +#[rustc_macro_derive(d(e))] +//~^ ERROR: must only be one word +pub fn foo5(input: rustc_macro::TokenStream) -> rustc_macro::TokenStream { + input +} diff --git a/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/append-impl.rs b/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/append-impl.rs new file mode 100644 index 000000000000..c3d295e02c16 --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/append-impl.rs @@ -0,0 +1,31 @@ +// 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. + +// force-host +// no-prefer-dynamic + +#![feature(rustc_macro)] +#![feature(rustc_macro_lib)] +#![crate_type = "rustc-macro"] + +extern crate rustc_macro; + +use rustc_macro::TokenStream; + +#[rustc_macro_derive(Append)] +pub fn derive_a(input: TokenStream) -> TokenStream { + let mut input = input.to_string(); + input.push_str(" + impl Append for A { + fn foo(&self) {} + } + "); + input.parse().unwrap() +} diff --git a/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-a-2.rs b/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-a-2.rs new file mode 100644 index 000000000000..ff00a9d96a30 --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-a-2.rs @@ -0,0 +1,25 @@ +// 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. + +// force-host +// no-prefer-dynamic + +#![feature(rustc_macro)] +#![feature(rustc_macro_lib)] +#![crate_type = "rustc-macro"] + +extern crate rustc_macro; + +use rustc_macro::TokenStream; + +#[rustc_macro_derive(A)] +pub fn derive_a(input: TokenStream) -> TokenStream { + input +} diff --git a/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-a.rs b/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-a.rs new file mode 100644 index 000000000000..ff00a9d96a30 --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-a.rs @@ -0,0 +1,25 @@ +// 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. + +// force-host +// no-prefer-dynamic + +#![feature(rustc_macro)] +#![feature(rustc_macro_lib)] +#![crate_type = "rustc-macro"] + +extern crate rustc_macro; + +use rustc_macro::TokenStream; + +#[rustc_macro_derive(A)] +pub fn derive_a(input: TokenStream) -> TokenStream { + input +} diff --git a/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-bad.rs b/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-bad.rs new file mode 100644 index 000000000000..5dd42d28b7be --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-bad.rs @@ -0,0 +1,26 @@ +// 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. + +// no-prefer-dynamic +// force-host + +#![feature(rustc_macro)] +#![feature(rustc_macro_lib)] +#![crate_type = "rustc-macro"] + +extern crate rustc_macro; + +use rustc_macro::TokenStream; + +#[rustc_macro_derive(A)] +pub fn derive_a(_input: TokenStream) -> TokenStream { + "struct A { inner }".parse().unwrap() +} + diff --git a/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-panic.rs b/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-panic.rs new file mode 100644 index 000000000000..d867082ed5e5 --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-panic.rs @@ -0,0 +1,25 @@ +// 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. + +// no-prefer-dynamic +// force-host + +#![feature(rustc_macro)] +#![feature(rustc_macro_lib)] +#![crate_type = "rustc-macro"] + +extern crate rustc_macro; + +use rustc_macro::TokenStream; + +#[rustc_macro_derive(A)] +pub fn derive_a(_input: TokenStream) -> TokenStream { + panic!("nope!"); +} diff --git a/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-unstable-2.rs b/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-unstable-2.rs new file mode 100644 index 000000000000..9eebad897564 --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-unstable-2.rs @@ -0,0 +1,29 @@ +// 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. + +// force-host +// no-prefer-dynamic + +#![feature(rustc_macro)] +#![feature(rustc_macro_lib)] +#![crate_type = "rustc-macro"] + +extern crate rustc_macro; + +use rustc_macro::TokenStream; + +#[rustc_macro_derive(Unstable)] +pub fn derive(_input: TokenStream) -> TokenStream { + + " + #[rustc_foo] + fn foo() {} + ".parse().unwrap() +} diff --git a/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-unstable.rs b/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-unstable.rs new file mode 100644 index 000000000000..f4a1ec997006 --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/auxiliary/derive-unstable.rs @@ -0,0 +1,26 @@ +// 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. + +// force-host +// no-prefer-dynamic + +#![feature(rustc_macro)] +#![feature(rustc_macro_lib)] +#![crate_type = "rustc-macro"] + +extern crate rustc_macro; + +use rustc_macro::TokenStream; + +#[rustc_macro_derive(Unstable)] +pub fn derive(_input: TokenStream) -> TokenStream { + + "unsafe fn foo() -> u32 { ::std::intrinsics::init() }".parse().unwrap() +} diff --git a/src/test/compile-fail-fulldeps/rustc-macro/cannot-link.rs b/src/test/compile-fail-fulldeps/rustc-macro/cannot-link.rs new file mode 100644 index 000000000000..1f135330a999 --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/cannot-link.rs @@ -0,0 +1,16 @@ +// 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. + +// aux-build:derive-a.rs + +extern crate derive_a; +//~^ ERROR: crates of the `rustc-macro` crate type cannot be linked at runtime + +fn main() {} diff --git a/src/test/compile-fail-fulldeps/rustc-macro/define-two.rs b/src/test/compile-fail-fulldeps/rustc-macro/define-two.rs new file mode 100644 index 000000000000..e4f21dc23840 --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/define-two.rs @@ -0,0 +1,28 @@ +// 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. + +// no-prefer-dynamic + +#![crate_type = "rustc-macro"] +#![feature(rustc_macro)] + +extern crate rustc_macro; + +use rustc_macro::TokenStream; + +#[rustc_macro_derive(A)] +pub fn foo(input: TokenStream) -> TokenStream { + input +} + +#[rustc_macro_derive(A)] //~ ERROR: derive mode defined twice in this crate +pub fn bar(input: TokenStream) -> TokenStream { + input +} diff --git a/src/test/compile-fail-fulldeps/rustc-macro/derive-bad.rs b/src/test/compile-fail-fulldeps/rustc-macro/derive-bad.rs new file mode 100644 index 000000000000..f3a73af29935 --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/derive-bad.rs @@ -0,0 +1,25 @@ +// 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. + +// aux-build:derive-bad.rs + +#![feature(rustc_macro)] + +#[macro_use] +extern crate derive_bad; + +#[derive( + A +)] +//~^^ ERROR: custom derive attribute panicked +//~| HELP: called `Result::unwrap()` on an `Err` value: LexError +struct A; + +fn main() {} diff --git a/src/test/compile-fail-fulldeps/rustc-macro/derive-still-gated.rs b/src/test/compile-fail-fulldeps/rustc-macro/derive-still-gated.rs new file mode 100644 index 000000000000..a46d79f517f7 --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/derive-still-gated.rs @@ -0,0 +1,22 @@ +// 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. + +// aux-build:derive-a.rs + +#![feature(rustc_macro)] +#![allow(warnings)] + +#[macro_use] +extern crate derive_a; + +#[derive_A] //~ ERROR: attributes of the form `#[derive_*]` are reserved for the compiler +struct A; + +fn main() {} diff --git a/src/test/compile-fail-fulldeps/rustc-macro/expand-to-unstable-2.rs b/src/test/compile-fail-fulldeps/rustc-macro/expand-to-unstable-2.rs new file mode 100644 index 000000000000..29b9fd228094 --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/expand-to-unstable-2.rs @@ -0,0 +1,25 @@ +// 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. + +// aux-build:derive-unstable-2.rs + +#![feature(rustc_macro)] +#![allow(warnings)] + +#[macro_use] +extern crate derive_unstable_2; + +#[derive(Unstable)] +//~^ ERROR: reserved for internal compiler +struct A; + +fn main() { + foo(); +} diff --git a/src/test/compile-fail-fulldeps/rustc-macro/expand-to-unstable.rs b/src/test/compile-fail-fulldeps/rustc-macro/expand-to-unstable.rs new file mode 100644 index 000000000000..874081760f66 --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/expand-to-unstable.rs @@ -0,0 +1,25 @@ +// 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. + +// aux-build:derive-unstable.rs + +#![feature(rustc_macro)] +#![allow(warnings)] + +#[macro_use] +extern crate derive_unstable; + +#[derive(Unstable)] +//~^ ERROR: use of unstable library feature +struct A; + +fn main() { + unsafe { foo(); } +} diff --git a/src/test/compile-fail-fulldeps/rustc-macro/export-macro.rs b/src/test/compile-fail-fulldeps/rustc-macro/export-macro.rs new file mode 100644 index 000000000000..759f3d32e16e --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/export-macro.rs @@ -0,0 +1,19 @@ +// 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. + +// error-pattern: cannot export macro_rules! macros from a `rustc-macro` crate + +#![crate_type = "rustc-macro"] +#![feature(rustc_macro)] + +#[macro_export] +macro_rules! foo { + ($e:expr) => ($e) +} diff --git a/src/test/compile-fail-fulldeps/rustc-macro/exports.rs b/src/test/compile-fail-fulldeps/rustc-macro/exports.rs new file mode 100644 index 000000000000..e985356dc584 --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/exports.rs @@ -0,0 +1,22 @@ +// 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. + +#![crate_type = "rustc-macro"] +#![allow(warnings)] + +pub fn a() {} //~ ERROR: cannot export any items +pub struct B; //~ ERROR: cannot export any items +pub enum C {} //~ ERROR: cannot export any items +pub mod d {} //~ ERROR: cannot export any items + +mod e {} +struct F; +enum G {} +fn h() {} diff --git a/src/test/compile-fail-fulldeps/rustc-macro/feature-gate-1.rs b/src/test/compile-fail-fulldeps/rustc-macro/feature-gate-1.rs new file mode 100644 index 000000000000..86afc08cae86 --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/feature-gate-1.rs @@ -0,0 +1,13 @@ +// 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. + +// error-pattern: the `rustc-macro` crate type is experimental + +#![crate_type = "rustc-macro"] diff --git a/src/test/compile-fail-fulldeps/rustc-macro/feature-gate-2.rs b/src/test/compile-fail-fulldeps/rustc-macro/feature-gate-2.rs new file mode 100644 index 000000000000..1a19f6046d9e --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/feature-gate-2.rs @@ -0,0 +1,13 @@ +// 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. + +extern crate rustc_macro; //~ ERROR: use of unstable library feature + +fn main() {} diff --git a/src/test/run-pass/single-derive-attr-with-gate.rs b/src/test/compile-fail-fulldeps/rustc-macro/feature-gate-3.rs similarity index 68% rename from src/test/run-pass/single-derive-attr-with-gate.rs rename to src/test/compile-fail-fulldeps/rustc-macro/feature-gate-3.rs index addc56e9c421..9f47f07bd023 100644 --- a/src/test/run-pass/single-derive-attr-with-gate.rs +++ b/src/test/compile-fail-fulldeps/rustc-macro/feature-gate-3.rs @@ -1,4 +1,4 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// 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. // @@ -8,13 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 +#![crate_type = "rustc-macro"] -#![feature(custom_derive)] - -#[derive_Clone] -struct Test; - -pub fn main() { - Test.clone(); +#[rustc_macro_derive(Foo)] //~ ERROR: is an experimental feature +pub fn foo() { } diff --git a/src/test/compile-fail-fulldeps/rustc-macro/feature-gate-4.rs b/src/test/compile-fail-fulldeps/rustc-macro/feature-gate-4.rs new file mode 100644 index 000000000000..0fdd13bc30cc --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/feature-gate-4.rs @@ -0,0 +1,15 @@ +// 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. + +// aux-build:derive-a.rs + +#[macro_use] +extern crate derive_a; +//~^ ERROR: loading custom derive macro crates is experimentally supported diff --git a/src/test/compile-fail-fulldeps/rustc-macro/feature-gate-5.rs b/src/test/compile-fail-fulldeps/rustc-macro/feature-gate-5.rs new file mode 100644 index 000000000000..e44b29a17051 --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/feature-gate-5.rs @@ -0,0 +1,12 @@ +// 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. + +#[cfg(rustc_macro)] //~ ERROR: experimental and subject to change +fn foo() {} diff --git a/src/test/compile-fail-fulldeps/rustc-macro/import.rs b/src/test/compile-fail-fulldeps/rustc-macro/import.rs new file mode 100644 index 000000000000..c1d0823cb6b8 --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/import.rs @@ -0,0 +1,22 @@ +// 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. + +// aux-build:derive-a.rs + +#![feature(rustc_macro)] +#![allow(warnings)] + +#[macro_use] +extern crate derive_a; + +use derive_a::derive_a; +//~^ ERROR: unresolved import `derive_a::derive_a` + +fn main() {} diff --git a/src/test/compile-fail-fulldeps/rustc-macro/load-panic.rs b/src/test/compile-fail-fulldeps/rustc-macro/load-panic.rs new file mode 100644 index 000000000000..0d08d27c38e4 --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/load-panic.rs @@ -0,0 +1,23 @@ +// 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. + +// aux-build:derive-panic.rs + +#![feature(rustc_macro)] + +#[macro_use] +extern crate derive_panic; + +#[derive(A)] +//~^ ERROR: custom derive attribute panicked +//~| HELP: message: nope! +struct Foo; + +fn main() {} diff --git a/src/test/compile-fail-fulldeps/rustc-macro/require-rustc-macro-crate-type.rs b/src/test/compile-fail-fulldeps/rustc-macro/require-rustc-macro-crate-type.rs new file mode 100644 index 000000000000..cdc50acea926 --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/require-rustc-macro-crate-type.rs @@ -0,0 +1,21 @@ +// 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. + +#![feature(rustc_macro)] + +extern crate rustc_macro; + +#[rustc_macro_derive(Foo)] +//~^ ERROR: only usable with crates of the `rustc-macro` crate type +pub fn foo(a: rustc_macro::TokenStream) -> rustc_macro::TokenStream { + a +} + +fn main() {} diff --git a/src/test/compile-fail-fulldeps/rustc-macro/shadow-builtin.rs b/src/test/compile-fail-fulldeps/rustc-macro/shadow-builtin.rs new file mode 100644 index 000000000000..1353a234b483 --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/shadow-builtin.rs @@ -0,0 +1,22 @@ +// 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. + +#![crate_type = "rustc-macro"] +#![feature(rustc_macro)] + +extern crate rustc_macro; + +use rustc_macro::TokenStream; + +#[rustc_macro_derive(PartialEq)] +//~^ ERROR: cannot override a built-in #[derive] mode +pub fn foo(input: TokenStream) -> TokenStream { + input +} diff --git a/src/test/compile-fail-fulldeps/rustc-macro/shadow.rs b/src/test/compile-fail-fulldeps/rustc-macro/shadow.rs new file mode 100644 index 000000000000..33330ed8f6a0 --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/shadow.rs @@ -0,0 +1,21 @@ +// 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. + +// aux-build:derive-a.rs +// aux-build:derive-a-2.rs + +#![feature(rustc_macro)] + +#[macro_use] +extern crate derive_a; +#[macro_use] +extern crate derive_a_2; //~ ERROR: cannot shadow existing derive mode `A` + +fn main() {} diff --git a/src/test/compile-fail-fulldeps/rustc-macro/signature.rs b/src/test/compile-fail-fulldeps/rustc-macro/signature.rs new file mode 100644 index 000000000000..9662cc69e1e1 --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/signature.rs @@ -0,0 +1,24 @@ +// 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. + +#![crate_type = "rustc-macro"] +#![feature(rustc_macro)] +#![allow(warnings)] + +extern crate rustc_macro; + +#[rustc_macro_derive(A)] +unsafe extern fn foo(a: i32, b: u32) -> u32 { + //~^ ERROR: mismatched types + //~| NOTE: expected normal fn, found unsafe fn + //~| NOTE: expected type `fn(rustc_macro::TokenStream) -> rustc_macro::TokenStream` + //~| NOTE: found type `unsafe extern "C" fn(i32, u32) -> u32 {foo}` + loop {} +} diff --git a/src/test/compile-fail-fulldeps/rustc-macro/two-crate-types-1.rs b/src/test/compile-fail-fulldeps/rustc-macro/two-crate-types-1.rs new file mode 100644 index 000000000000..35f6149ad494 --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/two-crate-types-1.rs @@ -0,0 +1,14 @@ +// 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. + +// error-pattern: cannot mix `rustc-macro` crate type with others + +#![crate_type = "rustc-macro"] +#![crate_type = "rlib"] diff --git a/src/test/compile-fail-fulldeps/rustc-macro/two-crate-types-2.rs b/src/test/compile-fail-fulldeps/rustc-macro/two-crate-types-2.rs new file mode 100644 index 000000000000..ec95e3e4685b --- /dev/null +++ b/src/test/compile-fail-fulldeps/rustc-macro/two-crate-types-2.rs @@ -0,0 +1,12 @@ +// 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. + +// error-pattern: cannot mix `rustc-macro` crate type with others +// compile-flags: --crate-type rlib --crate-type rustc-macro diff --git a/src/test/compile-fail/issue-32655.rs b/src/test/compile-fail/issue-32655.rs index edd7fe4a1e58..25ecd5d08626 100644 --- a/src/test/compile-fail/issue-32655.rs +++ b/src/test/compile-fail/issue-32655.rs @@ -13,7 +13,7 @@ macro_rules! foo ( () => ( - #[derive_Clone] //~ WARN attributes of the form + #[derive_Clone] //~ ERROR attributes of the form struct T; ); ); @@ -25,9 +25,8 @@ macro_rules! bar ( foo!(); bar!( - #[derive_Clone] //~ WARN attributes of the form + #[derive_Clone] //~ ERROR attributes of the form struct S; ); -#[rustc_error] -fn main() {} //~ ERROR compilation successful +fn main() {} diff --git a/src/test/run-pass-fulldeps/rustc-macro/add-impl.rs b/src/test/run-pass-fulldeps/rustc-macro/add-impl.rs new file mode 100644 index 000000000000..226c082564ae --- /dev/null +++ b/src/test/run-pass-fulldeps/rustc-macro/add-impl.rs @@ -0,0 +1,25 @@ +// 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. + +// aux-build:add-impl.rs + +#![feature(rustc_macro)] + +#[macro_use] +extern crate add_impl; + +#[derive(AddImpl)] +struct B; + +fn main() { + B.foo(); + foo(); + bar::foo(); +} diff --git a/src/test/run-pass-fulldeps/rustc-macro/auxiliary/add-impl.rs b/src/test/run-pass-fulldeps/rustc-macro/auxiliary/add-impl.rs new file mode 100644 index 000000000000..8aab423af0a3 --- /dev/null +++ b/src/test/run-pass-fulldeps/rustc-macro/auxiliary/add-impl.rs @@ -0,0 +1,33 @@ +// 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. + +// no-prefer-dynamic + +#![crate_type = "rustc-macro"] +#![feature(rustc_macro)] +#![feature(rustc_macro_lib)] + +extern crate rustc_macro; + +use rustc_macro::TokenStream; + +#[rustc_macro_derive(AddImpl)] +// #[cfg(rustc_macro)] +pub fn derive(input: TokenStream) -> TokenStream { + (input.to_string() + " + impl B { + fn foo(&self) {} + } + + fn foo() {} + + mod bar { pub fn foo() {} } + ").parse().unwrap() +} diff --git a/src/test/run-pass-fulldeps/rustc-macro/auxiliary/derive-a.rs b/src/test/run-pass-fulldeps/rustc-macro/auxiliary/derive-a.rs new file mode 100644 index 000000000000..4dd6ad88b757 --- /dev/null +++ b/src/test/run-pass-fulldeps/rustc-macro/auxiliary/derive-a.rs @@ -0,0 +1,27 @@ +// 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. + +// no-prefer-dynamic + +#![crate_type = "rustc-macro"] +#![feature(rustc_macro)] +#![feature(rustc_macro_lib)] + +extern crate rustc_macro; + +use rustc_macro::TokenStream; + +#[rustc_macro_derive(A)] +pub fn derive(input: TokenStream) -> TokenStream { + let input = input.to_string(); + assert!(input.contains("struct A;")); + assert!(input.contains("#[derive(Eq, Copy, Clone)]")); + "#[derive(Eq, Copy, Clone)] struct A;".parse().unwrap() +} diff --git a/src/test/run-pass-fulldeps/rustc-macro/auxiliary/derive-atob.rs b/src/test/run-pass-fulldeps/rustc-macro/auxiliary/derive-atob.rs new file mode 100644 index 000000000000..5b85e2b2a7c4 --- /dev/null +++ b/src/test/run-pass-fulldeps/rustc-macro/auxiliary/derive-atob.rs @@ -0,0 +1,26 @@ +// 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. + +// no-prefer-dynamic + +#![crate_type = "rustc-macro"] +#![feature(rustc_macro)] +#![feature(rustc_macro_lib)] + +extern crate rustc_macro; + +use rustc_macro::TokenStream; + +#[rustc_macro_derive(AToB)] +pub fn derive(input: TokenStream) -> TokenStream { + let input = input.to_string(); + assert_eq!(input, "struct A;\n"); + "struct B;".parse().unwrap() +} diff --git a/src/test/run-pass-fulldeps/rustc-macro/auxiliary/derive-ctod.rs b/src/test/run-pass-fulldeps/rustc-macro/auxiliary/derive-ctod.rs new file mode 100644 index 000000000000..54f8dff509ab --- /dev/null +++ b/src/test/run-pass-fulldeps/rustc-macro/auxiliary/derive-ctod.rs @@ -0,0 +1,26 @@ +// 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. + +// no-prefer-dynamic + +#![crate_type = "rustc-macro"] +#![feature(rustc_macro)] +#![feature(rustc_macro_lib)] + +extern crate rustc_macro; + +use rustc_macro::TokenStream; + +#[rustc_macro_derive(CToD)] +pub fn derive(input: TokenStream) -> TokenStream { + let input = input.to_string(); + assert_eq!(input, "struct C;\n"); + "struct D;".parse().unwrap() +} diff --git a/src/test/run-pass-fulldeps/rustc-macro/auxiliary/derive-same-struct.rs b/src/test/run-pass-fulldeps/rustc-macro/auxiliary/derive-same-struct.rs new file mode 100644 index 000000000000..d83e352e3b17 --- /dev/null +++ b/src/test/run-pass-fulldeps/rustc-macro/auxiliary/derive-same-struct.rs @@ -0,0 +1,32 @@ +// 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. + +// no-prefer-dynamic +// compile-flags:--crate-type rustc-macro + +#![feature(rustc_macro)] +#![feature(rustc_macro_lib)] + +extern crate rustc_macro; + +use rustc_macro::TokenStream; + +#[rustc_macro_derive(AToB)] +pub fn derive1(input: TokenStream) -> TokenStream { + println!("input1: {:?}", input.to_string()); + assert_eq!(input.to_string(), "#[derive(BToC)]\nstruct A;\n"); + "#[derive(BToC)] struct B;".parse().unwrap() +} + +#[rustc_macro_derive(BToC)] +pub fn derive2(input: TokenStream) -> TokenStream { + assert_eq!(input.to_string(), "struct B;\n"); + "struct C;".parse().unwrap() +} diff --git a/src/test/run-pass-fulldeps/rustc-macro/auxiliary/expand-with-a-macro.rs b/src/test/run-pass-fulldeps/rustc-macro/auxiliary/expand-with-a-macro.rs new file mode 100644 index 000000000000..96aea407e6e7 --- /dev/null +++ b/src/test/run-pass-fulldeps/rustc-macro/auxiliary/expand-with-a-macro.rs @@ -0,0 +1,36 @@ +// 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. + +// no-prefer-dynamic + +#![crate_type = "rustc-macro"] +#![feature(rustc_macro)] +#![feature(rustc_macro_lib)] +#![deny(warnings)] + +extern crate rustc_macro; + +use rustc_macro::TokenStream; + +#[rustc_macro_derive(A)] +pub fn derive(input: TokenStream) -> TokenStream { + let input = input.to_string(); + assert!(input.contains("struct A;")); + r#" + struct A; + + impl A { + fn a(&self) { + panic!("hello"); + } + } + "#.parse().unwrap() +} + diff --git a/src/test/run-pass-fulldeps/rustc-macro/derive-same-struct.rs b/src/test/run-pass-fulldeps/rustc-macro/derive-same-struct.rs new file mode 100644 index 000000000000..ee0d59456488 --- /dev/null +++ b/src/test/run-pass-fulldeps/rustc-macro/derive-same-struct.rs @@ -0,0 +1,23 @@ +// 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. + +// aux-build:derive-same-struct.rs + +#![feature(rustc_macro)] + +#[macro_use] +extern crate derive_same_struct; + +#[derive(AToB, BToC)] +struct A; + +fn main() { + C; +} diff --git a/src/test/run-pass-fulldeps/rustc-macro/expand-with-a-macro.rs b/src/test/run-pass-fulldeps/rustc-macro/expand-with-a-macro.rs new file mode 100644 index 000000000000..cc59be2d75df --- /dev/null +++ b/src/test/run-pass-fulldeps/rustc-macro/expand-with-a-macro.rs @@ -0,0 +1,30 @@ +// 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. + +// aux-build:expand-with-a-macro.rs +// ignore-stage1 + +#![feature(rustc_macro)] +#![deny(warnings)] + +#[macro_use] +extern crate expand_with_a_macro; + +use std::panic; + +#[derive(A)] +struct A; + +fn main() { + assert!(panic::catch_unwind(|| { + A.a(); + }).is_err()); +} + diff --git a/src/test/run-pass-fulldeps/rustc-macro/load-two.rs b/src/test/run-pass-fulldeps/rustc-macro/load-two.rs new file mode 100644 index 000000000000..1500970f02da --- /dev/null +++ b/src/test/run-pass-fulldeps/rustc-macro/load-two.rs @@ -0,0 +1,30 @@ +// 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. + +// aux-build:derive-atob.rs +// aux-build:derive-ctod.rs + +#![feature(rustc_macro)] + +#[macro_use] +extern crate derive_atob; +#[macro_use] +extern crate derive_ctod; + +#[derive(AToB)] +struct A; + +#[derive(CToD)] +struct C; + +fn main() { + B; + D; +} diff --git a/src/test/run-pass-fulldeps/rustc-macro/smoke.rs b/src/test/run-pass-fulldeps/rustc-macro/smoke.rs new file mode 100644 index 000000000000..588380f1140c --- /dev/null +++ b/src/test/run-pass-fulldeps/rustc-macro/smoke.rs @@ -0,0 +1,29 @@ +// 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. + +// aux-build:derive-a.rs +// ignore-stage1 + +#![feature(rustc_macro)] + +#[macro_use] +extern crate derive_a; + +#[derive(Debug, PartialEq, A, Eq, Copy, Clone)] +struct A; + +fn main() { + A; + assert_eq!(A, A); + A.clone(); + let a = A; + let _c = a; + let _d = a; +} diff --git a/src/test/run-pass/associated-types-normalize-unifield-struct.rs b/src/test/run-pass/associated-types-normalize-unifield-struct.rs index 3dffae99292c..517033d58702 100644 --- a/src/test/run-pass/associated-types-normalize-unifield-struct.rs +++ b/src/test/run-pass/associated-types-normalize-unifield-struct.rs @@ -11,9 +11,6 @@ // Regression test for issue #21010: Normalize associated types in // various special paths in the `type_is_immediate` function. - -// pretty-expanded FIXME #23616 - pub trait OffsetState: Sized {} pub trait Offset { type State: OffsetState; diff --git a/src/test/run-pass/builtin-superkinds-in-metadata.rs b/src/test/run-pass/builtin-superkinds-in-metadata.rs index c026ffc6d318..3259b1cc0679 100644 --- a/src/test/run-pass/builtin-superkinds-in-metadata.rs +++ b/src/test/run-pass/builtin-superkinds-in-metadata.rs @@ -13,8 +13,6 @@ // Tests (correct) usage of trait super-builtin-kinds cross-crate. -// pretty-expanded FIXME #23616 - extern crate trait_superkinds_in_metadata; use trait_superkinds_in_metadata::{RequiresRequiresShareAndSend, RequiresShare}; use trait_superkinds_in_metadata::RequiresCopy; diff --git a/src/test/run-pass/coherence-impl-in-fn.rs b/src/test/run-pass/coherence-impl-in-fn.rs index b0630b516407..d7c21340afc3 100644 --- a/src/test/run-pass/coherence-impl-in-fn.rs +++ b/src/test/run-pass/coherence-impl-in-fn.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 - pub fn main() { #[derive(Copy, Clone)] enum x { foo } diff --git a/src/test/run-pass/deriving-bounds.rs b/src/test/run-pass/deriving-bounds.rs index 4204d9b5c3ea..6d0a43997bc4 100644 --- a/src/test/run-pass/deriving-bounds.rs +++ b/src/test/run-pass/deriving-bounds.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 - #[derive(Copy, Clone)] struct Test; diff --git a/src/test/run-pass/issue-20797.rs b/src/test/run-pass/issue-20797.rs index 321ed1a3bb28..de9524366508 100644 --- a/src/test/run-pass/issue-20797.rs +++ b/src/test/run-pass/issue-20797.rs @@ -10,8 +10,6 @@ // Regression test for #20797. -// pretty-expanded FIXME #23616 - #![feature(question_mark)] use std::default::Default; diff --git a/src/test/run-pass/issue-2288.rs b/src/test/run-pass/issue-2288.rs index d16655a68554..379715f53903 100644 --- a/src/test/run-pass/issue-2288.rs +++ b/src/test/run-pass/issue-2288.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 - #![allow(unknown_features)] #![feature(box_syntax)] diff --git a/src/test/run-pass/sync-send-iterators-in-libcollections.rs b/src/test/run-pass/sync-send-iterators-in-libcollections.rs index 7fa592105c09..45ac334dc1d7 100644 --- a/src/test/run-pass/sync-send-iterators-in-libcollections.rs +++ b/src/test/run-pass/sync-send-iterators-in-libcollections.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 - #![allow(warnings)] #![feature(collections)] #![feature(drain, enumset, collections_bound, btree_range, vecmap)] From 63671c495bf16dc0f9e1c97fa11af8a895b5ed24 Mon Sep 17 00:00:00 2001 From: Andrea Corradi Date: Sun, 28 Aug 2016 12:57:38 +0200 Subject: [PATCH 119/443] Update E0496 to new format --- src/librustc/middle/resolve_lifetime.rs | 6 ++-- src/test/compile-fail/E0496.rs | 2 ++ .../loops-reject-duplicate-labels-2.rs | 33 ++++++++--------- .../loops-reject-duplicate-labels.rs | 32 +++++++++-------- ...loops-reject-labels-shadowing-lifetimes.rs | 36 ++++++++++++------- .../loops-reject-lifetime-shadowing-label.rs | 3 +- src/test/compile-fail/shadowed-lifetime.rs | 6 ++-- 7 files changed, 69 insertions(+), 49 deletions(-) diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index ebe405002215..747f6982ad79 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -395,9 +395,9 @@ fn signal_shadowing_problem(sess: &Session, name: ast::Name, orig: Original, sha {} name that is already in scope", shadower.kind.desc(), name, orig.kind.desc())) }; - err.span_note(orig.span, - &format!("shadowed {} `{}` declared here", - orig.kind.desc(), name)); + err.span_label(orig.span, &"first declared here"); + err.span_label(shadower.span, + &format!("lifetime {} already in scope", name)); err.emit(); } diff --git a/src/test/compile-fail/E0496.rs b/src/test/compile-fail/E0496.rs index 4ca3cd9c13da..8aeeeebcb567 100644 --- a/src/test/compile-fail/E0496.rs +++ b/src/test/compile-fail/E0496.rs @@ -13,7 +13,9 @@ struct Foo<'a> { } impl<'a> Foo<'a> { + //~^ NOTE first declared here fn f<'a>(x: &'a i32) { //~ ERROR E0496 + //~^ NOTE lifetime 'a already in scope } } diff --git a/src/test/compile-fail/loops-reject-duplicate-labels-2.rs b/src/test/compile-fail/loops-reject-duplicate-labels-2.rs index 4a3338c4bf6c..ca18ca3796a1 100644 --- a/src/test/compile-fail/loops-reject-duplicate-labels-2.rs +++ b/src/test/compile-fail/loops-reject-duplicate-labels-2.rs @@ -19,30 +19,31 @@ // https://internals.rust-lang.org/t/psa-rejecting-duplicate-loop-labels/1833 pub fn foo() { - { 'fl: for _ in 0..10 { break; } } //~ NOTE shadowed label `'fl` declared here + { 'fl: for _ in 0..10 { break; } } //~ NOTE first declared here { 'fl: loop { break; } } //~ WARN label name `'fl` shadows a label name that is already in scope - - { 'lf: loop { break; } } //~ NOTE shadowed label `'lf` declared here + //~^ NOTE lifetime 'fl already in scope + { 'lf: loop { break; } } //~ NOTE first declared here { 'lf: for _ in 0..10 { break; } } //~ WARN label name `'lf` shadows a label name that is already in scope - - { 'wl: while 2 > 1 { break; } } //~ NOTE shadowed label `'wl` declared here + //~^ NOTE lifetime 'lf already in scope + { 'wl: while 2 > 1 { break; } } //~ NOTE first declared here { 'wl: loop { break; } } //~ WARN label name `'wl` shadows a label name that is already in scope - - { 'lw: loop { break; } } //~ NOTE shadowed label `'lw` declared here + //~^ NOTE lifetime 'wl already in scope + { 'lw: loop { break; } } //~ NOTE first declared here { 'lw: while 2 > 1 { break; } } //~ WARN label name `'lw` shadows a label name that is already in scope - - { 'fw: for _ in 0..10 { break; } } //~ NOTE shadowed label `'fw` declared here + //~^ NOTE lifetime 'lw already in scope + { 'fw: for _ in 0..10 { break; } } //~ NOTE first declared here { 'fw: while 2 > 1 { break; } } //~ WARN label name `'fw` shadows a label name that is already in scope - - { 'wf: while 2 > 1 { break; } } //~ NOTE shadowed label `'wf` declared here + //~^ NOTE lifetime 'fw already in scope + { 'wf: while 2 > 1 { break; } } //~ NOTE first declared here { 'wf: for _ in 0..10 { break; } } //~ WARN label name `'wf` shadows a label name that is already in scope - - { 'tl: while let Some(_) = None:: { break; } } //~ NOTE shadowed label `'tl` declared here + //~^ NOTE lifetime 'wf already in scope + { 'tl: while let Some(_) = None:: { break; } } //~ NOTE first declared here { 'tl: loop { break; } } //~ WARN label name `'tl` shadows a label name that is already in scope - - { 'lt: loop { break; } } //~ NOTE shadowed label `'lt` declared here + //~^ NOTE lifetime 'tl already in scope + { 'lt: loop { break; } } //~ NOTE first declared here { 'lt: while let Some(_) = None:: { break; } } - //~^ WARN label name `'lt` shadows a label name that is already in scope + //~^ WARN label name `'lt` shadows a label name that is already in scope + //~| NOTE lifetime 'lt already in scope } #[rustc_error] diff --git a/src/test/compile-fail/loops-reject-duplicate-labels.rs b/src/test/compile-fail/loops-reject-duplicate-labels.rs index 15446bf642d4..31f89493896d 100644 --- a/src/test/compile-fail/loops-reject-duplicate-labels.rs +++ b/src/test/compile-fail/loops-reject-duplicate-labels.rs @@ -16,30 +16,32 @@ // This is testing the exact cases that are in the issue description. fn foo() { - 'fl: for _ in 0..10 { break; } //~ NOTE shadowed label `'fl` declared here + 'fl: for _ in 0..10 { break; } //~ NOTE first declared here 'fl: loop { break; } //~ WARN label name `'fl` shadows a label name that is already in scope + //~^ NOTE lifetime 'fl already in scope - 'lf: loop { break; } //~ NOTE shadowed label `'lf` declared here + 'lf: loop { break; } //~ NOTE first declared here 'lf: for _ in 0..10 { break; } //~ WARN label name `'lf` shadows a label name that is already in scope - - 'wl: while 2 > 1 { break; } //~ NOTE shadowed label `'wl` declared here + //~^ NOTE lifetime 'lf already in scope + 'wl: while 2 > 1 { break; } //~ NOTE first declared here 'wl: loop { break; } //~ WARN label name `'wl` shadows a label name that is already in scope - - 'lw: loop { break; } //~ NOTE shadowed label `'lw` declared here + //~^ NOTE lifetime 'wl already in scope + 'lw: loop { break; } //~ NOTE first declared here 'lw: while 2 > 1 { break; } //~ WARN label name `'lw` shadows a label name that is already in scope - - 'fw: for _ in 0..10 { break; } //~ NOTE shadowed label `'fw` declared here + //~^ NOTE lifetime 'lw already in scope + 'fw: for _ in 0..10 { break; } //~ NOTE first declared here 'fw: while 2 > 1 { break; } //~ WARN label name `'fw` shadows a label name that is already in scope - - 'wf: while 2 > 1 { break; } //~ NOTE shadowed label `'wf` declared here + //~^ NOTE lifetime 'fw already in scope + 'wf: while 2 > 1 { break; } //~ NOTE first declared here 'wf: for _ in 0..10 { break; } //~ WARN label name `'wf` shadows a label name that is already in scope - - 'tl: while let Some(_) = None:: { break; } //~ NOTE shadowed label `'tl` declared here + //~^ NOTE lifetime 'wf already in scope + 'tl: while let Some(_) = None:: { break; } //~ NOTE first declared here 'tl: loop { break; } //~ WARN label name `'tl` shadows a label name that is already in scope - - 'lt: loop { break; } //~ NOTE shadowed label `'lt` declared here + //~^ NOTE lifetime 'tl already in scope + 'lt: loop { break; } //~ NOTE first declared here 'lt: while let Some(_) = None:: { break; } - //~^ WARN label name `'lt` shadows a label name that is already in scope + //~^ WARN label name `'lt` shadows a label name that is already in scope + //~| NOTE lifetime 'lt already in scope } // Note however that it is okay for the same label to be reused in diff --git a/src/test/compile-fail/loops-reject-labels-shadowing-lifetimes.rs b/src/test/compile-fail/loops-reject-labels-shadowing-lifetimes.rs index bbdd0774ed93..9a735f9c97c9 100644 --- a/src/test/compile-fail/loops-reject-labels-shadowing-lifetimes.rs +++ b/src/test/compile-fail/loops-reject-labels-shadowing-lifetimes.rs @@ -16,9 +16,10 @@ #![allow(dead_code, unused_variables)] fn foo() { - fn foo<'a>() { //~ NOTE shadowed lifetime `'a` declared here + fn foo<'a>() { //~ NOTE first declared here 'a: loop { break 'a; } //~^ WARN label name `'a` shadows a lifetime name that is already in scope + //~| NOTE lifetime 'a already in scope } struct Struct<'b, 'c> { _f: &'b i8, _g: &'c i8 } @@ -40,76 +41,87 @@ fn foo() { } } - impl<'bad, 'c> Struct<'bad, 'c> { //~ NOTE shadowed lifetime `'bad` declared here + impl<'bad, 'c> Struct<'bad, 'c> { //~ NOTE first declared here fn meth_bad(&self) { 'bad: loop { break 'bad; } //~^ WARN label name `'bad` shadows a lifetime name that is already in scope + //~| NOTE lifetime 'bad already in scope } } - impl<'b, 'bad> Struct<'b, 'bad> { //~ NOTE shadowed lifetime `'bad` declared here + impl<'b, 'bad> Struct<'b, 'bad> { //~ NOTE first declared here fn meth_bad2(&self) { 'bad: loop { break 'bad; } //~^ WARN label name `'bad` shadows a lifetime name that is already in scope + //~| NOTE lifetime 'bad already in scope } } impl<'b, 'c> Struct<'b, 'c> { - fn meth_bad3<'bad>(x: &'bad i8) { //~ NOTE shadowed lifetime `'bad` declared here + fn meth_bad3<'bad>(x: &'bad i8) { //~ NOTE first declared here 'bad: loop { break 'bad; } //~^ WARN label name `'bad` shadows a lifetime name that is already in scope + //~| NOTE lifetime 'bad already in scope } fn meth_bad4<'a,'bad>(x: &'a i8, y: &'bad i8) { - //~^ NOTE shadowed lifetime `'bad` declared here + //~^ NOTE first declared here 'bad: loop { break 'bad; } //~^ WARN label name `'bad` shadows a lifetime name that is already in scope + //~| NOTE lifetime 'bad already in scope } } - impl <'bad, 'e> Enum<'bad, 'e> { //~ NOTE shadowed lifetime `'bad` declared here + impl <'bad, 'e> Enum<'bad, 'e> { //~ NOTE first declared here fn meth_bad(&self) { 'bad: loop { break 'bad; } //~^ WARN label name `'bad` shadows a lifetime name that is already in scope + //~| NOTE lifetime 'bad already in scope } } - impl <'d, 'bad> Enum<'d, 'bad> { //~ NOTE shadowed lifetime `'bad` declared here + impl <'d, 'bad> Enum<'d, 'bad> { //~ NOTE first declared here fn meth_bad2(&self) { 'bad: loop { break 'bad; } //~^ WARN label name `'bad` shadows a lifetime name that is already in scope + //~| NOTE lifetime 'bad already in scope } } impl <'d, 'e> Enum<'d, 'e> { - fn meth_bad3<'bad>(x: &'bad i8) { //~ NOTE shadowed lifetime `'bad` declared here + fn meth_bad3<'bad>(x: &'bad i8) { //~ NOTE first declared here 'bad: loop { break 'bad; } //~^ WARN label name `'bad` shadows a lifetime name that is already in scope + //~| NOTE lifetime 'bad already in scope } - fn meth_bad4<'a,'bad>(x: &'bad i8) { //~ NOTE shadowed lifetime `'bad` declared here + fn meth_bad4<'a,'bad>(x: &'bad i8) { //~ NOTE first declared here 'bad: loop { break 'bad; } //~^ WARN label name `'bad` shadows a lifetime name that is already in scope + //~| NOTE lifetime 'bad already in scope } } - trait HasDefaultMethod1<'bad> { //~ NOTE shadowed lifetime `'bad` declared here + trait HasDefaultMethod1<'bad> { //~ NOTE first declared here fn meth_okay() { 'c: loop { break 'c; } } fn meth_bad(&self) { 'bad: loop { break 'bad; } //~^ WARN label name `'bad` shadows a lifetime name that is already in scope + //~| NOTE lifetime 'bad already in scope } } - trait HasDefaultMethod2<'a,'bad> { //~ NOTE shadowed lifetime `'bad` declared here + trait HasDefaultMethod2<'a,'bad> { //~ NOTE first declared here fn meth_bad(&self) { 'bad: loop { break 'bad; } //~^ WARN label name `'bad` shadows a lifetime name that is already in scope + //~| NOTE lifetime 'bad already in scope } } trait HasDefaultMethod3<'a,'b> { - fn meth_bad<'bad>(&self) { //~ NOTE shadowed lifetime `'bad` declared here + fn meth_bad<'bad>(&self) { //~ NOTE first declared here 'bad: loop { break 'bad; } //~^ WARN label name `'bad` shadows a lifetime name that is already in scope + //~| NOTE lifetime 'bad already in scope } } } diff --git a/src/test/compile-fail/loops-reject-lifetime-shadowing-label.rs b/src/test/compile-fail/loops-reject-lifetime-shadowing-label.rs index 2344d251c9a6..0a90917d975e 100644 --- a/src/test/compile-fail/loops-reject-lifetime-shadowing-label.rs +++ b/src/test/compile-fail/loops-reject-lifetime-shadowing-label.rs @@ -27,9 +27,10 @@ fn foo() { let z = 3_i8; - 'a: loop { //~ NOTE shadowed label `'a` declared here + 'a: loop { //~ NOTE first declared here let b = Box::new(|x: &i8| *x) as Box Fn(&'a i8) -> i8>; //~^ WARN lifetime name `'a` shadows a label name that is already in scope + //~| NOTE lifetime 'a already in scope assert_eq!((*b)(&z), z); break 'a; } diff --git a/src/test/compile-fail/shadowed-lifetime.rs b/src/test/compile-fail/shadowed-lifetime.rs index 8cbab5f83080..31283623a3ce 100644 --- a/src/test/compile-fail/shadowed-lifetime.rs +++ b/src/test/compile-fail/shadowed-lifetime.rs @@ -13,16 +13,18 @@ struct Foo<'a>(&'a isize); impl<'a> Foo<'a> { - //~^ NOTE shadowed lifetime `'a` declared here + //~^ NOTE first declared here fn shadow_in_method<'a>(&'a self) -> &'a isize { //~^ ERROR lifetime name `'a` shadows a lifetime name that is already in scope + //~| NOTE lifetime 'a already in scope self.0 } fn shadow_in_type<'b>(&'b self) -> &'b isize { - //~^ NOTE shadowed lifetime `'b` declared here + //~^ NOTE first declared here let x: for<'b> fn(&'b isize) = panic!(); //~^ ERROR lifetime name `'b` shadows a lifetime name that is already in scope + //~| NOTE lifetime 'b already in scope self.0 } From 18434f94572ee047aff8898a0d25ee8939585827 Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Fri, 2 Sep 2016 02:21:53 +0530 Subject: [PATCH 120/443] Update compiler error E0558 to use new error format Fixes #36196 part of #35233 --- src/libsyntax/attr.rs | 5 +++-- src/test/compile-fail/E0558.rs | 5 ++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index 703f3f7adf91..81ee96459fd6 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -438,8 +438,9 @@ pub fn find_export_name_attr(diag: &Handler, attrs: &[Attribute]) -> Option Date: Fri, 2 Sep 2016 19:54:02 -0400 Subject: [PATCH 121/443] indicate where to copy config.toml.example --- src/bootstrap/config.toml.example | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/bootstrap/config.toml.example b/src/bootstrap/config.toml.example index 2894adafef62..9e8910669a06 100644 --- a/src/bootstrap/config.toml.example +++ b/src/bootstrap/config.toml.example @@ -1,5 +1,7 @@ # Sample TOML configuration file for building Rust. # +# To configure rustbuild, copy this file to ../config.toml. +# # All options are commented out by default in this file, and they're commented # out with their default values. The build system by default looks for # `config.toml` in the current directory of a build for build configuration, but From a34485ff1925e81702bbb46bf2a5634fa008672b Mon Sep 17 00:00:00 2001 From: Alex Burka Date: Sat, 3 Sep 2016 02:02:03 -0400 Subject: [PATCH 122/443] change wording --- src/bootstrap/config.toml.example | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/config.toml.example b/src/bootstrap/config.toml.example index 9e8910669a06..20c91960e9ea 100644 --- a/src/bootstrap/config.toml.example +++ b/src/bootstrap/config.toml.example @@ -1,6 +1,7 @@ # Sample TOML configuration file for building Rust. # -# To configure rustbuild, copy this file to ../config.toml. +# To configure rustbuild, copy this file to the directory from which you will be +# running the build, and name it config.toml. # # All options are commented out by default in this file, and they're commented # out with their default values. The build system by default looks for From 0efc4bf387f962f7ba56a9bc0179fcc72701f53c Mon Sep 17 00:00:00 2001 From: Alex Burka Date: Sat, 3 Sep 2016 01:29:12 +0000 Subject: [PATCH 123/443] rustbuild: add config.toml option to disable codegen tests --- src/bootstrap/config.rs | 2 ++ src/bootstrap/config.toml.example | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 682a6f74126a..c1af7bd794cb 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -144,6 +144,7 @@ struct Rust { rpath: Option, optimize_tests: Option, debuginfo_tests: Option, + codegen_tests: Option, } /// TOML representation of how each build target is configured. @@ -232,6 +233,7 @@ impl Config { set(&mut config.rust_optimize, rust.optimize); set(&mut config.rust_optimize_tests, rust.optimize_tests); set(&mut config.rust_debuginfo_tests, rust.debuginfo_tests); + set(&mut config.codegen_tests, rust.codegen_tests); set(&mut config.rust_rpath, rust.rpath); set(&mut config.debug_jemalloc, rust.debug_jemalloc); set(&mut config.use_jemalloc, rust.use_jemalloc); diff --git a/src/bootstrap/config.toml.example b/src/bootstrap/config.toml.example index 2894adafef62..ef24a948664f 100644 --- a/src/bootstrap/config.toml.example +++ b/src/bootstrap/config.toml.example @@ -130,6 +130,10 @@ #optimize-tests = true #debuginfo-tests = true +# Flag indicating whether codegen tests will be run or not. If you get an error +# saying that the FileCheck executable is missing, you may want to disable this. +#codegen-tests = true + # ============================================================================= # Options for specific targets # From 1db878fd38eb00daf794d87ab04cb50c7fa6e4fc Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 17 Jul 2016 00:15:15 +0300 Subject: [PATCH 124/443] Add unions to AST --- src/librustc_passes/ast_validation.rs | 10 ++++++++++ src/libsyntax/ast.rs | 2 +- src/libsyntax/diagnostics/macros.rs | 7 +++++++ 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index dde1a4a75956..b8284f5dcf10 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -196,6 +196,16 @@ impl<'a> Visitor for AstValidator<'a> { // Ensure that `path` attributes on modules are recorded as used (c.f. #35584). attr::first_attr_value_str_by_name(&item.attrs, "path"); } + ItemKind::Union(ref vdata, _) => { + if !vdata.is_struct() { + self.err_handler().span_err(item.span, + "tuple and unit unions are not permitted"); + } + if vdata.fields().len() == 0 { + self.err_handler().span_err(item.span, + "unions cannot have zero fields"); + } + } _ => {} } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index fcb99444957c..4394fb0e1431 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1886,7 +1886,7 @@ pub enum ItemKind { /// A union definition (`union` or `pub union`). /// /// E.g. `union Foo { x: A, y: B }` - Union(VariantData, Generics), // FIXME: not yet implemented + Union(VariantData, Generics), /// A Trait declaration (`trait` or `pub trait`). /// /// E.g. `trait Foo { .. }` or `trait Foo { .. }` diff --git a/src/libsyntax/diagnostics/macros.rs b/src/libsyntax/diagnostics/macros.rs index 25e0428248df..e2a7ec0a33de 100644 --- a/src/libsyntax/diagnostics/macros.rs +++ b/src/libsyntax/diagnostics/macros.rs @@ -107,6 +107,13 @@ macro_rules! help { }) } +#[macro_export] +macro_rules! unimplemented_unions { + () => ({ + panic!("unions are not fully implemented"); + }) +} + #[macro_export] macro_rules! register_diagnostics { ($($code:tt),*) => ( From 4001c039de931f4e5ad5318b12e333ef30c52d1b Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 6 Aug 2016 21:36:28 +0300 Subject: [PATCH 125/443] Add unions to HIR --- src/librustc/hir/fold.rs | 4 ++++ src/librustc/hir/intravisit.rs | 3 ++- src/librustc/hir/map/def_collector.rs | 6 +++--- src/librustc/hir/map/mod.rs | 1 + src/librustc/hir/mod.rs | 3 +++ src/librustc/hir/print.rs | 5 ++++- src/librustc/middle/reachable.rs | 2 +- src/librustc/middle/resolve_lifetime.rs | 1 + src/librustc_metadata/encoder.rs | 3 +++ src/librustc_privacy/lib.rs | 8 +++++--- src/librustc_trans/collector.rs | 5 +++-- src/librustc_typeck/collect.rs | 3 ++- src/librustc_typeck/variance/constraints.rs | 2 +- src/librustc_typeck/variance/terms.rs | 3 ++- src/librustdoc/visit_ast.rs | 2 ++ 15 files changed, 37 insertions(+), 14 deletions(-) diff --git a/src/librustc/hir/fold.rs b/src/librustc/hir/fold.rs index 12bc49c10dab..57b5599bd1d7 100644 --- a/src/librustc/hir/fold.rs +++ b/src/librustc/hir/fold.rs @@ -761,6 +761,10 @@ pub fn noop_fold_item_underscore(i: Item_, folder: &mut T) -> Item_ { let struct_def = folder.fold_variant_data(struct_def); ItemStruct(struct_def, folder.fold_generics(generics)) } + ItemUnion(struct_def, generics) => { + let struct_def = folder.fold_variant_data(struct_def); + ItemUnion(struct_def, folder.fold_generics(generics)) + } ItemDefaultImpl(unsafety, ref trait_ref) => { ItemDefaultImpl(unsafety, folder.fold_trait_ref((*trait_ref).clone())) } diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index bc1dff7c6fc3..62157b1ca368 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -348,7 +348,8 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) { visitor.visit_ty(typ); walk_list!(visitor, visit_impl_item, impl_items); } - ItemStruct(ref struct_definition, ref generics) => { + ItemStruct(ref struct_definition, ref generics) | + ItemUnion(ref struct_definition, ref generics) => { visitor.visit_generics(generics); visitor.visit_id(item.id); visitor.visit_variant_data(struct_definition, item.name, generics, item.id, item.span); diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs index 77567fc7a460..389d0a1d50d5 100644 --- a/src/librustc/hir/map/def_collector.rs +++ b/src/librustc/hir/map/def_collector.rs @@ -302,9 +302,9 @@ impl<'ast> intravisit::Visitor<'ast> for DefCollector<'ast> { let def_data = match i.node { hir::ItemDefaultImpl(..) | hir::ItemImpl(..) => DefPathData::Impl, - hir::ItemEnum(..) | hir::ItemStruct(..) | hir::ItemTrait(..) | - hir::ItemExternCrate(..) | hir::ItemMod(..) | hir::ItemForeignMod(..) | - hir::ItemTy(..) => + hir::ItemEnum(..) | hir::ItemStruct(..) | hir::ItemUnion(..) | + hir::ItemTrait(..) | hir::ItemExternCrate(..) | hir::ItemMod(..) | + hir::ItemForeignMod(..) | hir::ItemTy(..) => DefPathData::TypeNs(i.name.as_str()), hir::ItemStatic(..) | hir::ItemConst(..) | hir::ItemFn(..) => DefPathData::ValueNs(i.name.as_str()), diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index 5e14bb51ce86..3ffc95e64f5a 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -1030,6 +1030,7 @@ fn node_id_to_string(map: &Map, id: NodeId, include_id: bool) -> String { ItemTy(..) => "ty", ItemEnum(..) => "enum", ItemStruct(..) => "struct", + ItemUnion(..) => "union", ItemTrait(..) => "trait", ItemImpl(..) => "impl", ItemDefaultImpl(..) => "default impl", diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 295a49d26d0f..e16005558f82 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -1483,6 +1483,8 @@ pub enum Item_ { ItemEnum(EnumDef, Generics), /// A struct definition, e.g. `struct Foo {x: A}` ItemStruct(VariantData, Generics), + /// A union definition, e.g. `union Foo {x: A, y: B}` + ItemUnion(VariantData, Generics), /// Represents a Trait Declaration ItemTrait(Unsafety, Generics, TyParamBounds, HirVec), @@ -1512,6 +1514,7 @@ impl Item_ { ItemTy(..) => "type alias", ItemEnum(..) => "enum", ItemStruct(..) => "struct", + ItemUnion(..) => "union", ItemTrait(..) => "trait", ItemImpl(..) | ItemDefaultImpl(..) => "item", diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index 893d6708ead4..f236bd4884d5 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -752,7 +752,10 @@ impl<'a> State<'a> { self.head(&visibility_qualified(&item.vis, "struct"))?; self.print_struct(struct_def, generics, item.name, item.span, true)?; } - + hir::ItemUnion(ref struct_def, ref generics) => { + self.head(&visibility_qualified(&item.vis, "union"))?; + self.print_struct(struct_def, generics, item.name, item.span, true)?; + } hir::ItemDefaultImpl(unsafety, ref trait_ref) => { self.head("")?; self.print_visibility(&item.vis)?; diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index 1f9738556d92..0625504af88e 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -269,7 +269,7 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { hir::ItemMod(..) | hir::ItemForeignMod(..) | hir::ItemImpl(..) | hir::ItemTrait(..) | hir::ItemStruct(..) | hir::ItemEnum(..) | - hir::ItemDefaultImpl(..) => {} + hir::ItemUnion(..) | hir::ItemDefaultImpl(..) => {} } } ast_map::NodeTraitItem(trait_method) => { diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index ebe405002215..4d1eed612cfd 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -156,6 +156,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for LifetimeContext<'a, 'tcx> { hir::ItemTy(_, ref generics) | hir::ItemEnum(_, ref generics) | hir::ItemStruct(_, ref generics) | + hir::ItemUnion(_, ref generics) | hir::ItemTrait(_, ref generics, _, _) | hir::ItemImpl(_, _, ref generics, _, _, _) => { // These kinds of items have only early bound lifetime parameters. diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index bb4cf70bd3b3..e82742004c39 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -1179,6 +1179,9 @@ impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> { hir::ItemStruct(ref struct_def, _) => { self.encode_addl_struct_info(def_id, struct_def.id(), item); } + hir::ItemUnion(..) => { + unimplemented_unions!(); + } hir::ItemImpl(_, _, _, _, _, ref ast_items) => { self.encode_addl_impl_info(def_id, item.id, ast_items); } diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 41b7c51e3009..4b13d13fb705 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -234,7 +234,8 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> { } } // Visit everything except for private fields - hir::ItemStruct(ref struct_def, ref generics) => { + hir::ItemStruct(ref struct_def, ref generics) | + hir::ItemUnion(ref struct_def, ref generics) => { if item_level.is_some() { self.reach().visit_generics(generics); for field in struct_def.fields() { @@ -1067,8 +1068,9 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivateItemsInPublicInterfacesVisitor<'a, 'tc check.visit_foreign_item(foreign_item); } } - // Subitems of structs have their own publicity - hir::ItemStruct(ref struct_def, ref generics) => { + // Subitems of structs and unions have their own publicity + hir::ItemStruct(ref struct_def, ref generics) | + hir::ItemUnion(ref struct_def, ref generics) => { check.required_visibility = item_visibility; check.visit_generics(generics); diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index c82bfa5c91ba..bea6f30faec3 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -1121,8 +1121,9 @@ impl<'b, 'a, 'v> hir_visit::Visitor<'v> for RootCollector<'b, 'a, 'v> { } } - hir::ItemEnum(_, ref generics) | - hir::ItemStruct(_, ref generics) => { + hir::ItemEnum(_, ref generics) | + hir::ItemStruct(_, ref generics) | + hir::ItemUnion(_, ref generics) => { if !generics.is_parameterized() { let ty = { let tables = self.scx.tcx().tables.borrow(); diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 2b62e513ab27..f2f3163dde7c 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1637,7 +1637,8 @@ fn predicates_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, hir::ItemFn(_, _, _, _, ref generics, _) | hir::ItemTy(_, ref generics) | hir::ItemEnum(_, ref generics) | - hir::ItemStruct(_, ref generics) => generics, + hir::ItemStruct(_, ref generics) | + hir::ItemUnion(_, ref generics) => generics, _ => &no_generics }; diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs index 2cf84b5745af..888709d25724 100644 --- a/src/librustc_typeck/variance/constraints.rs +++ b/src/librustc_typeck/variance/constraints.rs @@ -80,7 +80,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ConstraintContext<'a, 'tcx> { debug!("visit_item item={}", tcx.map.node_to_string(item.id)); match item.node { - hir::ItemEnum(..) | hir::ItemStruct(..) => { + hir::ItemEnum(..) | hir::ItemStruct(..) | hir::ItemUnion(..) => { let scheme = tcx.lookup_item_type(did); // Not entirely obvious: constraints on structs/enums do not diff --git a/src/librustc_typeck/variance/terms.rs b/src/librustc_typeck/variance/terms.rs index c0b53787177d..1238f7cbcb33 100644 --- a/src/librustc_typeck/variance/terms.rs +++ b/src/librustc_typeck/variance/terms.rs @@ -234,7 +234,8 @@ impl<'a, 'tcx, 'v> Visitor<'v> for TermsContext<'a, 'tcx> { match item.node { hir::ItemEnum(_, ref generics) | - hir::ItemStruct(_, ref generics) => { + hir::ItemStruct(_, ref generics) | + hir::ItemUnion(_, ref generics) => { self.add_inferreds_for_item(item.id, false, generics); } hir::ItemTrait(_, ref generics, _, _) => { diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 6af36e24d815..e70fbf4463a2 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -365,6 +365,8 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { om.enums.push(self.visit_enum_def(item, name, ed, gen)), hir::ItemStruct(ref sd, ref gen) => om.structs.push(self.visit_variant_data(item, name, sd, gen)), + hir::ItemUnion(..) => + unimplemented_unions!(), hir::ItemFn(ref fd, ref unsafety, constness, ref abi, ref gen, _) => om.fns.push(self.visit_fn(item, name, &**fd, unsafety, constness, abi, gen)), From 35d52a003bf0997d31378796bf59cc66c3ae7683 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 6 Aug 2016 21:56:02 +0300 Subject: [PATCH 126/443] Add unions to definition map --- src/librustc/hir/def.rs | 6 ++++-- src/librustc/middle/mem_categorization.rs | 2 +- src/librustc_metadata/astencode.rs | 1 + src/librustc_resolve/build_reduced_graph.rs | 21 ++++++++++++++++++++- src/librustc_save_analysis/dump_visitor.rs | 1 + src/librustc_typeck/check/mod.rs | 1 + 6 files changed, 28 insertions(+), 4 deletions(-) diff --git a/src/librustc/hir/def.rs b/src/librustc/hir/def.rs index d15d51aed09a..aa0eac37ecff 100644 --- a/src/librustc/hir/def.rs +++ b/src/librustc/hir/def.rs @@ -41,6 +41,7 @@ pub enum Def { // If Def::Struct lives in value namespace (e.g. tuple struct, unit struct expressions) // it denotes a constructor and its DefId refers to NodeId of the struct's constructor. Struct(DefId), + Union(DefId), Label(ast::NodeId), Method(DefId), Err, @@ -109,7 +110,7 @@ impl Def { Def::Fn(..) | Def::Mod(..) | Def::ForeignMod(..) | Def::Static(..) | Def::Variant(..) | Def::Enum(..) | Def::TyAlias(..) | Def::AssociatedTy(..) | - Def::TyParam(..) | Def::Struct(..) | Def::Trait(..) | + Def::TyParam(..) | Def::Struct(..) | Def::Union(..) | Def::Trait(..) | Def::Method(..) | Def::Const(..) | Def::AssociatedConst(..) | Def::PrimTy(..) | Def::Label(..) | Def::SelfTy(..) | Def::Err => { bug!("attempted .var_id() on invalid {:?}", self) @@ -121,7 +122,7 @@ impl Def { match *self { Def::Fn(id) | Def::Mod(id) | Def::ForeignMod(id) | Def::Static(id, _) | Def::Variant(_, id) | Def::Enum(id) | Def::TyAlias(id) | Def::AssociatedTy(_, id) | - Def::TyParam(id) | Def::Struct(id) | Def::Trait(id) | + Def::TyParam(id) | Def::Struct(id) | Def::Union(id) | Def::Trait(id) | Def::Method(id) | Def::Const(id) | Def::AssociatedConst(id) | Def::Local(id, _) | Def::Upvar(id, _, _, _) => { id @@ -147,6 +148,7 @@ impl Def { Def::TyAlias(..) => "type", Def::AssociatedTy(..) => "associated type", Def::Struct(..) => "struct", + Def::Union(..) => "union", Def::Trait(..) => "trait", Def::Method(..) => "method", Def::Const(..) => "constant", diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index a74bdb02044d..b17411ced57f 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -572,7 +572,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { id, expr_ty, def); match def { - Def::Struct(..) | Def::Variant(..) | Def::Const(..) | + Def::Struct(..) | Def::Union(..) | Def::Variant(..) | Def::Const(..) | Def::AssociatedConst(..) | Def::Fn(..) | Def::Method(..) => { Ok(self.cat_rvalue_node(id, span, expr_ty)) } diff --git a/src/librustc_metadata/astencode.rs b/src/librustc_metadata/astencode.rs index 0236f9c413dd..9d9c6f033a96 100644 --- a/src/librustc_metadata/astencode.rs +++ b/src/librustc_metadata/astencode.rs @@ -416,6 +416,7 @@ impl tr for Def { Def::Upvar(did1, nid1, index, nid2) } Def::Struct(did) => Def::Struct(did.tr(dcx)), + Def::Union(did) => Def::Union(did.tr(dcx)), Def::Label(nid) => Def::Label(dcx.tr_id(nid)), Def::Err => Def::Err, } diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 3e9b37f0a95a..8e97870c21a5 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -278,7 +278,19 @@ impl<'b> Resolver<'b> { self.structs.insert(item_def_id, field_names); } - ItemKind::Union(..) => panic!("`union` is not yet implemented"), + ItemKind::Union(ref vdata, _) => { + let def = Def::Union(self.definitions.local_def_id(item.id)); + self.define(parent, name, TypeNS, (def, sp, vis)); + + // Record the def ID and fields of this union. + let field_names = vdata.fields().iter().enumerate().map(|(index, field)| { + self.resolve_visibility(&field.vis); + field.ident.map(|ident| ident.name) + .unwrap_or_else(|| token::intern(&index.to_string())) + }).collect(); + let item_def_id = self.definitions.local_def_id(item.id); + self.structs.insert(item_def_id, field_names); + } ItemKind::DefaultImpl(_, _) | ItemKind::Impl(..) => {} @@ -461,6 +473,13 @@ impl<'b> Resolver<'b> { let fields = self.session.cstore.struct_field_names(def_id); self.structs.insert(def_id, fields); } + Def::Union(def_id) => { + let _ = self.try_define(parent, name, TypeNS, (def, DUMMY_SP, vis)); + + // Record the def ID and fields of this union. + let fields = self.session.cstore.struct_field_names(def_id); + self.structs.insert(def_id, fields); + } Def::Struct(..) => {} Def::Local(..) | Def::PrimTy(..) | diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index dbe956f021e4..f9a20cec42d1 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -300,6 +300,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { }.lower(self.tcx)); } Def::Struct(..) | + Def::Union(..) | Def::Enum(..) | Def::TyAlias(..) | Def::AssociatedTy(..) | diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 90a9d9bffe7d..be33f836cc6c 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -4118,6 +4118,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { match def { // Case 1 and 1b. Reference to a *type* or *enum variant*. Def::Struct(def_id) | + Def::Union(def_id) | Def::Variant(_, def_id) | Def::Enum(def_id) | Def::TyAlias(def_id) | From cbd912babab4b8cebe9e90a632117913ca192743 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 7 Aug 2016 01:09:00 +0300 Subject: [PATCH 127/443] Add union types --- src/librustc/infer/freshen.rs | 1 + src/librustc/traits/coherence.rs | 3 +- src/librustc/traits/error_reporting.rs | 1 + src/librustc/traits/select.rs | 7 +- src/librustc/ty/contents.rs | 3 +- src/librustc/ty/context.rs | 4 +- src/librustc/ty/error.rs | 3 + src/librustc/ty/fast_reject.rs | 3 + src/librustc/ty/flags.rs | 2 +- src/librustc/ty/item_path.rs | 1 + src/librustc/ty/layout.rs | 3 + src/librustc/ty/mod.rs | 3 +- src/librustc/ty/outlives.rs | 1 + src/librustc/ty/structural_impls.rs | 2 + src/librustc/ty/sty.rs | 6 ++ src/librustc/ty/util.rs | 5 +- src/librustc/ty/walk.rs | 1 + src/librustc/ty/wf.rs | 3 +- src/librustc/util/ppaux.rs | 5 +- src/librustc_lint/types.rs | 34 ++++++++- src/librustc_metadata/tyencode.rs | 5 ++ src/librustc_trans/collector.rs | 1 + src/librustc_trans/debuginfo/type_names.rs | 1 + src/librustc_trans/trans_item.rs | 1 + src/librustc_trans/type_of.rs | 83 +++++++++------------ src/librustc_typeck/check/dropck.rs | 2 +- src/librustc_typeck/coherence/mod.rs | 5 +- src/librustc_typeck/variance/constraints.rs | 3 +- src/librustdoc/clean/mod.rs | 1 + 29 files changed, 124 insertions(+), 69 deletions(-) diff --git a/src/librustc/infer/freshen.rs b/src/librustc/infer/freshen.rs index f793d489cab0..8aeb0757f5de 100644 --- a/src/librustc/infer/freshen.rs +++ b/src/librustc/infer/freshen.rs @@ -168,6 +168,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> { ty::TyFnPtr(_) | ty::TyTrait(..) | ty::TyStruct(..) | + ty::TyUnion(..) | ty::TyClosure(..) | ty::TyNever | ty::TyTuple(..) | diff --git a/src/librustc/traits/coherence.rs b/src/librustc/traits/coherence.rs index a5a415dd27c6..f856e110ea2a 100644 --- a/src/librustc/traits/coherence.rs +++ b/src/librustc/traits/coherence.rs @@ -261,7 +261,8 @@ fn ty_is_local_constructor(tcx: TyCtxt, ty: Ty, infer_is_local: InferIsLocal)-> } ty::TyEnum(def, _) | - ty::TyStruct(def, _) => { + ty::TyStruct(def, _) | + ty::TyUnion(def, _) => { def.did.is_local() } diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 6d6d7c2b3ba0..95e83d404a74 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -166,6 +166,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { ty::TyParam(..) => Some(14), ty::TyAnon(..) => Some(15), ty::TyNever => Some(16), + ty::TyUnion(..) => Some(17), ty::TyInfer(..) | ty::TyError => None } } diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 0573f0c5bbaa..f8f10d9c2654 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -1780,7 +1780,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { Where(ty::Binder(tys.last().into_iter().cloned().collect())) } - ty::TyStruct(def, substs) | ty::TyEnum(def, substs) => { + ty::TyStruct(def, substs) | ty::TyUnion(def, substs) | + ty::TyEnum(def, substs) => { let sized_crit = def.sized_constraint(self.tcx()); // (*) binder moved here Where(ty::Binder(match sized_crit.sty { @@ -1836,7 +1837,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { Where(ty::Binder(tys.to_vec())) } - ty::TyStruct(..) | ty::TyEnum(..) | + ty::TyStruct(..) | ty::TyUnion(..) | ty::TyEnum(..) | ty::TyProjection(..) | ty::TyParam(..) | ty::TyAnon(..) => { // Fallback to whatever user-defined impls exist in this case. None @@ -1933,7 +1934,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { substs.types().collect() } - ty::TyStruct(def, substs) | ty::TyEnum(def, substs) => { + ty::TyStruct(def, substs) | ty::TyUnion(def, substs) | ty::TyEnum(def, substs) => { def.all_fields() .map(|f| f.ty(self.tcx(), substs)) .collect() diff --git a/src/librustc/ty/contents.rs b/src/librustc/ty/contents.rs index 53bf046d6b59..d7d4693c1165 100644 --- a/src/librustc/ty/contents.rs +++ b/src/librustc/ty/contents.rs @@ -224,7 +224,8 @@ impl<'a, 'tcx> ty::TyS<'tcx> { |ty| tc_ty(tcx, *ty, cache)) } - ty::TyStruct(def, substs) | ty::TyEnum(def, substs) => { + ty::TyStruct(def, substs) | ty::TyUnion(def, substs) | + ty::TyEnum(def, substs) => { let mut res = TypeContents::union(&def.variants, |v| { TypeContents::union(&v.fields, |f| { diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 725bbf6adfd4..8dd7bc562d7c 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -1032,8 +1032,8 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { pub fn print_debug_stats(self) { sty_debug_print!( self, - TyEnum, TyBox, TyArray, TySlice, TyRawPtr, TyRef, TyFnDef, TyFnPtr, - TyTrait, TyStruct, TyClosure, TyTuple, TyParam, TyInfer, TyProjection, TyAnon); + TyEnum, TyBox, TyArray, TySlice, TyRawPtr, TyRef, TyFnDef, TyFnPtr, TyTrait, + TyStruct, TyUnion, TyClosure, TyTuple, TyParam, TyInfer, TyProjection, TyAnon); println!("Substs interner: #{}", self.interners.substs.borrow().len()); println!("BareFnTy interner: #{}", self.interners.bare_fn.borrow().len()); diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs index 3d60d326b2b0..0e33e396f7e1 100644 --- a/src/librustc/ty/error.rs +++ b/src/librustc/ty/error.rs @@ -247,6 +247,9 @@ impl<'a, 'gcx, 'lcx, 'tcx> ty::TyS<'tcx> { ty::TyStruct(def, _) => { format!("struct `{}`", tcx.item_path_str(def.did)) } + ty::TyUnion(def, _) => { + format!("union `{}`", tcx.item_path_str(def.did)) + } ty::TyClosure(..) => "closure".to_string(), ty::TyTuple(_) => "tuple".to_string(), ty::TyInfer(ty::TyVar(_)) => "inferred type".to_string(), diff --git a/src/librustc/ty/fast_reject.rs b/src/librustc/ty/fast_reject.rs index f7472d611bef..23678d1e3774 100644 --- a/src/librustc/ty/fast_reject.rs +++ b/src/librustc/ty/fast_reject.rs @@ -66,6 +66,9 @@ pub fn simplify_type<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, ty::TyStruct(def, _) => { Some(StructSimplifiedType(def.did)) } + ty::TyUnion(..) => { + unimplemented_unions!(); + } ty::TyRef(_, mt) => { // since we introduce auto-refs during method lookup, we // just treat &T and T as equivalent from the point of diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs index 1afd49ab47fb..ce6e4d6516ec 100644 --- a/src/librustc/ty/flags.rs +++ b/src/librustc/ty/flags.rs @@ -102,7 +102,7 @@ impl FlagComputation { } } - &ty::TyEnum(_, substs) | &ty::TyStruct(_, substs) => { + &ty::TyEnum(_, substs) | &ty::TyStruct(_, substs) | &ty::TyUnion(_, substs) => { self.add_substs(substs); } diff --git a/src/librustc/ty/item_path.rs b/src/librustc/ty/item_path.rs index 62bd30e25559..42ec2b18fb02 100644 --- a/src/librustc/ty/item_path.rs +++ b/src/librustc/ty/item_path.rs @@ -320,6 +320,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn characteristic_def_id_of_type(ty: Ty) -> Option { match ty.sty { ty::TyStruct(adt_def, _) | + ty::TyUnion(adt_def, _) | ty::TyEnum(adt_def, _) => Some(adt_def.did), ty::TyTrait(ref data) => Some(data.principal.def_id()), diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 1ede8545e08e..622966ca5aba 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -896,6 +896,9 @@ impl<'a, 'gcx, 'tcx> Layout { non_zero: Some(def.did) == tcx.lang_items.non_zero() } } + ty::TyUnion(..) => { + unimplemented_unions!(); + } ty::TyEnum(def, substs) => { let hint = *tcx.lookup_repr_hints(def.did).get(0) .unwrap_or(&attr::ReprAny); diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index e9c01f5bad66..ddf25538ee4d 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1421,6 +1421,7 @@ bitflags! { const IS_PHANTOM_DATA = 1 << 3, const IS_SIMD = 1 << 4, const IS_FUNDAMENTAL = 1 << 5, + const IS_UNION = 1 << 7, } } @@ -1818,7 +1819,7 @@ impl<'a, 'tcx> AdtDefData<'tcx, 'tcx> { } } - TyEnum(adt, substs) | TyStruct(adt, substs) => { + TyEnum(adt, substs) | TyStruct(adt, substs) | TyUnion(adt, substs) => { // recursive case let adt = tcx.lookup_adt_def_master(adt.did); adt.calculate_sized_constraint_inner(tcx, stack); diff --git a/src/librustc/ty/outlives.rs b/src/librustc/ty/outlives.rs index 4d5b38212f60..a7bb0374b75b 100644 --- a/src/librustc/ty/outlives.rs +++ b/src/librustc/ty/outlives.rs @@ -174,6 +174,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { ty::TyNever | // ... ty::TyEnum(..) | // OutlivesNominalType ty::TyStruct(..) | // OutlivesNominalType + ty::TyUnion(..) | // OutlivesNominalType ty::TyBox(..) | // OutlivesNominalType (ish) ty::TyAnon(..) | // OutlivesNominalType (ish) ty::TyStr | // OutlivesScalar (ish) diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index ad3769605abd..952641f6832f 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -495,6 +495,7 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { ty::TyRef(r.fold_with(folder), tm.fold_with(folder)) } ty::TyStruct(did, substs) => ty::TyStruct(did, substs.fold_with(folder)), + ty::TyUnion(did, substs) => ty::TyUnion(did, substs.fold_with(folder)), ty::TyClosure(did, substs) => ty::TyClosure(did, substs.fold_with(folder)), ty::TyProjection(ref data) => ty::TyProjection(data.fold_with(folder)), ty::TyAnon(did, substs) => ty::TyAnon(did, substs.fold_with(folder)), @@ -524,6 +525,7 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { ty::TyFnPtr(ref f) => f.visit_with(visitor), ty::TyRef(r, ref tm) => r.visit_with(visitor) || tm.visit_with(visitor), ty::TyStruct(_did, ref substs) => substs.visit_with(visitor), + ty::TyUnion(_did, ref substs) => substs.visit_with(visitor), ty::TyClosure(_did, ref substs) => substs.visit_with(visitor), ty::TyProjection(ref data) => data.visit_with(visitor), ty::TyAnon(_, ref substs) => substs.visit_with(visitor), diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 0e3f18c4474e..b023cdad9ee2 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -120,6 +120,11 @@ pub enum TypeVariants<'tcx> { /// See warning about substitutions for enumerated types. TyStruct(AdtDef<'tcx>, &'tcx Substs<'tcx>), + /// A union type, defined with `union`. + /// + /// See warning about substitutions for enumerated types. + TyUnion(AdtDef<'tcx>, &'tcx Substs<'tcx>), + /// `Box`; this is nominally a struct in the documentation, but is /// special-cased internally. For example, it is possible to implicitly /// move the contents of a box out of that box, and methods of any type @@ -1227,6 +1232,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { } TyEnum(_, substs) | TyStruct(_, substs) | + TyUnion(_, substs) | TyAnon(_, substs) => { substs.regions().collect() } diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 77d16287fedc..971fc2cee804 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -430,6 +430,7 @@ impl<'a, 'gcx, 'tcx> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tcx> { TyUint(u) => self.hash(u), TyFloat(f) => self.hash(f), TyStruct(d, _) | + TyUnion(d, _) | TyEnum(d, _) => self.def_id(d.did), TyArray(_, n) => self.hash(n), TyRawPtr(m) | @@ -558,7 +559,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> { }) => Some(true), TyArray(..) | TySlice(_) | TyTrait(..) | TyTuple(..) | - TyClosure(..) | TyEnum(..) | TyStruct(..) | TyAnon(..) | + TyClosure(..) | TyEnum(..) | TyStruct(..) | TyUnion(..) | TyAnon(..) | TyProjection(..) | TyParam(..) | TyInfer(..) | TyError => None }.unwrap_or_else(|| !self.impls_bound(tcx, param_env, ty::BoundCopy, span)); @@ -598,7 +599,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> { TyStr | TyTrait(..) | TySlice(_) => Some(false), - TyEnum(..) | TyStruct(..) | TyProjection(..) | TyParam(..) | + TyEnum(..) | TyStruct(..) | TyUnion(..) | TyProjection(..) | TyParam(..) | TyInfer(..) | TyAnon(..) | TyError => None }.unwrap_or_else(|| self.impls_bound(tcx, param_env, ty::BoundSized, span)); diff --git a/src/librustc/ty/walk.rs b/src/librustc/ty/walk.rs index 409f5a85997b..cea3bd6348db 100644 --- a/src/librustc/ty/walk.rs +++ b/src/librustc/ty/walk.rs @@ -95,6 +95,7 @@ fn push_subtypes<'tcx>(stack: &mut Vec>, parent_ty: Ty<'tcx>) { } ty::TyEnum(_, ref substs) | ty::TyStruct(_, ref substs) | + ty::TyUnion(_, ref substs) | ty::TyAnon(_, ref substs) => { stack.extend(substs.types().rev()); } diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs index aef646a7aaca..599e2be4db24 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/ty/wf.rs @@ -337,7 +337,8 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { } ty::TyEnum(def, substs) | - ty::TyStruct(def, substs) => { + ty::TyStruct(def, substs) | + ty::TyUnion(def, substs) => { // WfNominalType let obligations = self.nominal_obligations(def.did, substs); self.out.extend(obligations); diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 7e2cc2938ca9..d0e02f2e8acd 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -8,11 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. - use hir::def_id::DefId; use ty::subst::{self, Subst, Substs}; use ty::{BrAnon, BrEnv, BrFresh, BrNamed}; -use ty::{TyBool, TyChar, TyStruct, TyEnum}; +use ty::{TyBool, TyChar, TyStruct, TyUnion, TyEnum}; use ty::{TyError, TyStr, TyArray, TySlice, TyFloat, TyFnDef, TyFnPtr}; use ty::{TyParam, TyRawPtr, TyRef, TyNever, TyTuple}; use ty::TyClosure; @@ -869,7 +868,7 @@ impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> { TyInfer(infer_ty) => write!(f, "{}", infer_ty), TyError => write!(f, "[type error]"), TyParam(ref param_ty) => write!(f, "{}", param_ty), - TyEnum(def, substs) | TyStruct(def, substs) => { + TyEnum(def, substs) | TyStruct(def, substs) | TyUnion(def, substs) => { ty::tls::with(|tcx| { if def.did.is_local() && !tcx.tcache.borrow().contains_key(&def.did) { diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index 40e78c007ccf..54cec3fd7e13 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -377,7 +377,8 @@ enum FfiResult { FfiSafe, FfiUnsafe(&'static str), FfiBadStruct(DefId, &'static str), - FfiBadEnum(DefId, &'static str) + FfiBadUnion(DefId, &'static str), + FfiBadEnum(DefId, &'static str), } /// Check if this enum can be safely exported based on the @@ -452,12 +453,32 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { let r = self.check_type_for_ffi(cache, field_ty); match r { FfiSafe => {} - FfiBadStruct(..) | FfiBadEnum(..) => { return r; } + FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => { return r; } FfiUnsafe(s) => { return FfiBadStruct(def.did, s); } } } FfiSafe } + ty::TyUnion(def, substs) => { + if !cx.lookup_repr_hints(def.did).contains(&attr::ReprExtern) { + return FfiUnsafe( + "found union without foreign-function-safe \ + representation annotation in foreign module, \ + consider adding a #[repr(C)] attribute to \ + the type"); + } + + for field in &def.struct_variant().fields { + let field_ty = cx.normalize_associated_type(&field.ty(cx, substs)); + let r = self.check_type_for_ffi(cache, field_ty); + match r { + FfiSafe => {} + FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => { return r; } + FfiUnsafe(s) => { return FfiBadUnion(def.did, s); } + } + } + FfiSafe + } ty::TyEnum(def, substs) => { if def.variants.is_empty() { // Empty enums are okay... although sort of useless. @@ -507,7 +528,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { let r = self.check_type_for_ffi(cache, arg); match r { FfiSafe => {} - FfiBadStruct(..) | FfiBadEnum(..) => { return r; } + FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => { return r; } FfiUnsafe(s) => { return FfiBadEnum(def.did, s); } } } @@ -614,6 +635,13 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { &format!("found non-foreign-function-safe member in \ struct marked #[repr(C)]: {}", s)); } + FfiResult::FfiBadUnion(_, s) => { + // FIXME: This diagnostic is difficult to read, and doesn't + // point at the relevant field. + self.cx.span_lint(IMPROPER_CTYPES, sp, + &format!("found non-foreign-function-safe member in \ + union marked #[repr(C)]: {}", s)); + } FfiResult::FfiBadEnum(_, s) => { // FIXME: This diagnostic is difficult to read, and doesn't // point at the relevant variant. diff --git a/src/librustc_metadata/tyencode.rs b/src/librustc_metadata/tyencode.rs index 954ca878c01e..b334a21c07c7 100644 --- a/src/librustc_metadata/tyencode.rs +++ b/src/librustc_metadata/tyencode.rs @@ -170,6 +170,11 @@ pub fn enc_ty<'a, 'tcx>(w: &mut Cursor>, cx: &ctxt<'a, 'tcx>, t: Ty<'tcx enc_substs(w, cx, substs); write!(w, "]"); } + ty::TyUnion(def, substs) => { + write!(w, "u[{}|", (cx.ds)(cx.tcx, def.did)); + enc_substs(w, cx, substs); + write!(w, "]"); + } ty::TyClosure(def, substs) => { write!(w, "k[{}|", (cx.ds)(cx.tcx, def)); enc_substs(w, cx, substs.func_substs); diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index bea6f30faec3..47b3bb36cb93 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -798,6 +798,7 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, /* nothing to do */ } ty::TyStruct(ref adt_def, substs) | + ty::TyUnion(ref adt_def, substs) | ty::TyEnum(ref adt_def, substs) => { for field in adt_def.all_fields() { let field_type = monomorphize::apply_param_substs(scx, diff --git a/src/librustc_trans/debuginfo/type_names.rs b/src/librustc_trans/debuginfo/type_names.rs index f757578e6954..bd839243e201 100644 --- a/src/librustc_trans/debuginfo/type_names.rs +++ b/src/librustc_trans/debuginfo/type_names.rs @@ -45,6 +45,7 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, ty::TyUint(uint_ty) => output.push_str(uint_ty.ty_to_string()), ty::TyFloat(float_ty) => output.push_str(float_ty.ty_to_string()), ty::TyStruct(def, substs) | + ty::TyUnion(def, substs) | ty::TyEnum(def, substs) => { push_item_name(cx, def.did, qualified, output); push_type_params(cx, substs, output); diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs index 8a0f37230c8d..deef0b09a17b 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -397,6 +397,7 @@ pub fn push_unique_type_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty::TyFloat(ast::FloatTy::F32) => output.push_str("f32"), ty::TyFloat(ast::FloatTy::F64) => output.push_str("f64"), ty::TyStruct(adt_def, substs) | + ty::TyUnion(adt_def, substs) | ty::TyEnum(adt_def, substs) => { push_item_name(tcx, adt_def.did, output); push_type_params(tcx, substs, &[], output); diff --git a/src/librustc_trans/type_of.rs b/src/librustc_trans/type_of.rs index 6605d12e2e12..d5d8f049681d 100644 --- a/src/librustc_trans/type_of.rs +++ b/src/librustc_trans/type_of.rs @@ -89,27 +89,23 @@ pub fn sizing_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Typ Type::nil(cx) } - ty::TyTuple(..) | ty::TyEnum(..) | ty::TyClosure(..) => { - let repr = adt::represent_type(cx, t); - adt::sizing_type_of(cx, &repr, false) + ty::TyStruct(..) if t.is_simd() => { + let e = t.simd_type(cx.tcx()); + if !e.is_machine() { + cx.sess().fatal(&format!("monomorphising SIMD type `{}` with \ + a non-machine element type `{}`", + t, e)) + } + let llet = type_of(cx, e); + let n = t.simd_size(cx.tcx()) as u64; + ensure_array_fits_in_address_space(cx, llet, n, t); + Type::vector(&llet, n) } - ty::TyStruct(..) => { - if t.is_simd() { - let e = t.simd_type(cx.tcx()); - if !e.is_machine() { - cx.sess().fatal(&format!("monomorphising SIMD type `{}` with \ - a non-machine element type `{}`", - t, e)) - } - let llet = type_of(cx, e); - let n = t.simd_size(cx.tcx()) as u64; - ensure_array_fits_in_address_space(cx, llet, n, t); - Type::vector(&llet, n) - } else { - let repr = adt::represent_type(cx, t); - adt::sizing_type_of(cx, &repr, false) - } + ty::TyTuple(..) | ty::TyStruct(..) | ty::TyUnion(..) | + ty::TyEnum(..) | ty::TyClosure(..) => { + let repr = adt::represent_type(cx, t); + adt::sizing_type_of(cx, &repr, false) } ty::TyProjection(..) | ty::TyInfer(..) | ty::TyParam(..) | @@ -244,15 +240,6 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> ty::TyUint(t) => Type::uint_from_ty(cx, t), ty::TyFloat(t) => Type::float_from_ty(cx, t), ty::TyNever => Type::nil(cx), - ty::TyEnum(def, ref substs) => { - // Only create the named struct, but don't fill it in. We - // fill it in *after* placing it into the type cache. This - // avoids creating more than one copy of the enum when one - // of the enum's variants refers to the enum itself. - let repr = adt::represent_type(cx, t); - let name = llvm_type_name(cx, def.did, substs); - adt::incomplete_type_of(cx, &repr, &name[..]) - } ty::TyClosure(..) => { // Only create the named struct, but don't fill it in. We // fill it in *after* placing it into the type cache. @@ -307,26 +294,28 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> let repr = adt::represent_type(cx, t); adt::type_of(cx, &repr) } - ty::TyStruct(def, ref substs) => { - if t.is_simd() { - let e = t.simd_type(cx.tcx()); - if !e.is_machine() { - cx.sess().fatal(&format!("monomorphising SIMD type `{}` with \ - a non-machine element type `{}`", - t, e)) - } - let llet = in_memory_type_of(cx, e); - let n = t.simd_size(cx.tcx()) as u64; - ensure_array_fits_in_address_space(cx, llet, n, t); - Type::vector(&llet, n) - } else { - // Only create the named struct, but don't fill it in. We fill it - // in *after* placing it into the type cache. This prevents - // infinite recursion with recursive struct types. - let repr = adt::represent_type(cx, t); - let name = llvm_type_name(cx, def.did, substs); - adt::incomplete_type_of(cx, &repr, &name[..]) + ty::TyStruct(..) if t.is_simd() => { + let e = t.simd_type(cx.tcx()); + if !e.is_machine() { + cx.sess().fatal(&format!("monomorphising SIMD type `{}` with \ + a non-machine element type `{}`", + t, e)) } + let llet = in_memory_type_of(cx, e); + let n = t.simd_size(cx.tcx()) as u64; + ensure_array_fits_in_address_space(cx, llet, n, t); + Type::vector(&llet, n) + } + ty::TyStruct(def, ref substs) | + ty::TyUnion(def, ref substs) | + ty::TyEnum(def, ref substs) => { + // Only create the named struct, but don't fill it in. We + // fill it in *after* placing it into the type cache. This + // avoids creating more than one copy of the enum when one + // of the enum's variants refers to the enum itself. + let repr = adt::represent_type(cx, t); + let name = llvm_type_name(cx, def.did, substs); + adt::incomplete_type_of(cx, &repr, &name[..]) } ty::TyInfer(..) | diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index 3a6076774330..b73b8b998876 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -439,7 +439,7 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'b, 'gcx, 'tcx>( cx, context, ity, depth+1) } - ty::TyStruct(def, substs) | ty::TyEnum(def, substs) => { + ty::TyStruct(def, substs) | ty::TyUnion(def, substs) | ty::TyEnum(def, substs) => { let did = def.did; for variant in &def.variants { for field in variant.fields.iter() { diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index f743ef218756..a20195bd801d 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -24,7 +24,7 @@ use rustc::ty::{ImplOrTraitItemId, ConstTraitItemId}; use rustc::ty::{MethodTraitItemId, TypeTraitItemId, ParameterEnvironment}; use rustc::ty::{Ty, TyBool, TyChar, TyEnum, TyError}; use rustc::ty::{TyParam, TyRawPtr}; -use rustc::ty::{TyRef, TyStruct, TyTrait, TyNever, TyTuple}; +use rustc::ty::{TyRef, TyStruct, TyUnion, TyTrait, TyNever, TyTuple}; use rustc::ty::{TyStr, TyArray, TySlice, TyFloat, TyInfer, TyInt}; use rustc::ty::{TyUint, TyClosure, TyBox, TyFnDef, TyFnPtr}; use rustc::ty::{TyProjection, TyAnon}; @@ -70,7 +70,8 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { fn get_base_type_def_id(&self, span: Span, ty: Ty<'tcx>) -> Option { match ty.sty { TyEnum(def, _) | - TyStruct(def, _) => { + TyStruct(def, _) | + TyUnion(def, _) => { Some(def.did) } diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs index 888709d25724..e20e74be67cd 100644 --- a/src/librustc_typeck/variance/constraints.rs +++ b/src/librustc_typeck/variance/constraints.rs @@ -344,7 +344,8 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { } ty::TyEnum(def, substs) | - ty::TyStruct(def, substs) => { + ty::TyStruct(def, substs) | + ty::TyUnion(def, substs) => { let item_type = self.tcx().lookup_item_type(def.did); // This edge is actually implied by the call to diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index e4b6a30d5bcb..92bb265ca995 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1801,6 +1801,7 @@ impl<'tcx> Clean for ty::Ty<'tcx> { decl: (cx.map.local_def_id(0), &fty.sig).clean(cx), abi: fty.abi, }), + ty::TyUnion(..) => unimplemented_unions!(), ty::TyStruct(def, substs) | ty::TyEnum(def, substs) => { let did = def.did; From a014323e456c00f93134d03b4af95844b2ed4b95 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Tue, 9 Aug 2016 01:18:47 +0300 Subject: [PATCH 128/443] Lower unions from AST to HIR and from HIR to types Parse union items and add a feature for them --- src/librustc/hir/lowering.rs | 5 ++++- src/librustc/ty/context.rs | 5 +++++ src/librustc/ty/mod.rs | 10 +++++++--- src/librustc_privacy/lib.rs | 2 +- src/librustc_typeck/check/dropck.rs | 3 ++- src/librustc_typeck/collect.rs | 10 ++++++++++ src/libsyntax/feature_gate.rs | 9 +++++++++ src/libsyntax/parse/parser.rs | 31 +++++++++++++++++++++++++++++ 8 files changed, 69 insertions(+), 6 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 6739d3f662ac..80e034721d63 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -638,7 +638,10 @@ impl<'a> LoweringContext<'a> { let struct_def = self.lower_variant_data(struct_def); hir::ItemStruct(struct_def, self.lower_generics(generics)) } - ItemKind::Union(..) => panic!("`union` is not yet implemented"), + ItemKind::Union(ref vdata, ref generics) => { + let vdata = self.lower_variant_data(vdata); + hir::ItemUnion(vdata, self.lower_generics(generics)) + } ItemKind::DefaultImpl(unsafety, ref trait_ref) => { hir::ItemDefaultImpl(self.lower_unsafety(unsafety), self.lower_trait_ref(trait_ref)) diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 8dd7bc562d7c..0fc1641d31f7 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -1321,6 +1321,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.mk_ty(TyStruct(def, substs)) } + pub fn mk_union(self, def: AdtDef<'tcx>, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> { + // take a copy of substs so that we own the vectors inside + self.mk_ty(TyUnion(def, substs)) + } + pub fn mk_closure(self, closure_id: DefId, substs: &'tcx Substs<'tcx>, diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index ddf25538ee4d..4cda74911138 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1514,7 +1514,7 @@ impl<'tcx> Decodable for AdtDef<'tcx> { #[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub enum AdtKind { Struct, Enum } +pub enum AdtKind { Struct, Union, Enum } #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] pub enum VariantKind { Struct, Tuple, Unit } @@ -1545,8 +1545,10 @@ impl<'a, 'gcx, 'tcx, 'container> AdtDefData<'gcx, 'container> { if Some(did) == tcx.lang_items.phantom_data() { flags = flags | AdtFlags::IS_PHANTOM_DATA; } - if let AdtKind::Enum = kind { - flags = flags | AdtFlags::IS_ENUM; + match kind { + AdtKind::Enum => flags = flags | AdtFlags::IS_ENUM, + AdtKind::Union => flags = flags | AdtFlags::IS_UNION, + AdtKind::Struct => {} } AdtDefData { did: did, @@ -1569,6 +1571,8 @@ impl<'a, 'gcx, 'tcx, 'container> AdtDefData<'gcx, 'container> { pub fn adt_kind(&self) -> AdtKind { if self.flags.get().intersects(AdtFlags::IS_ENUM) { AdtKind::Enum + } else if self.flags.get().intersects(AdtFlags::IS_UNION) { + AdtKind::Union } else { AdtKind::Struct } diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 4b13d13fb705..cd2eb4d2b58b 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -383,7 +383,7 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> { // Checks that a field is in scope. fn check_field(&mut self, span: Span, def: ty::AdtDef<'tcx>, field: ty::FieldDef<'tcx>) { - if def.adt_kind() == ty::AdtKind::Struct && + if def.adt_kind() != ty::AdtKind::Enum && !field.vis.is_accessible_from(self.curitem, &self.tcx.map) { struct_span_err!(self.tcx.sess, span, E0451, "field `{}` of struct `{}` is private", field.name, self.tcx.item_path_str(def.did)) diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index b73b8b998876..bd47ff0b00b7 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -304,7 +304,8 @@ pub fn check_safety_of_destructor_if_necessary<'a, 'gcx, 'tcx>( tcx.item_path_str(def_id), variant), ty::AdtKind::Struct => format!("struct {}", - tcx.item_path_str(def_id)) + tcx.item_path_str(def_id)), + ty::AdtKind::Union => unimplemented_unions!(), }; span_note!( &mut err, diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index f2f3163dde7c..7f9de2becee6 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1069,6 +1069,16 @@ fn convert_struct_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, adt } +fn convert_union_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, + it: &hir::Item, + def: &hir::VariantData) + -> ty::AdtDefMaster<'tcx> +{ + let did = ccx.tcx.map.local_def_id(it.id); + let variants = vec![convert_struct_variant(ccx, did, it.name, ConstInt::Infer(0), def)]; + ccx.tcx.intern_adt_def(did, ty::AdtKind::Union, variants) +} + fn evaluate_disr_expr(ccx: &CrateCtxt, repr_ty: attr::IntType, e: &hir::Expr) -> Option { debug!("disr expr, checking {}", pprust::expr_to_string(e)); diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 683d5277359e..b40124bd7741 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -292,6 +292,9 @@ declare_features! ( // Macros 1.1 (active, rustc_macro, "1.13.0", Some(35900)), + + // Allows untagged unions `union U { ... }` + (active, untagged_unions, "1.13.0", Some(32836)), ); declare_features! ( @@ -953,6 +956,12 @@ impl<'a> Visitor for PostExpansionVisitor<'a> { } } + ast::ItemKind::Union(..) => { + gate_feature_post!(&self, untagged_unions, + i.span, + "unions are unstable and not fully implemented"); + } + ast::ItemKind::DefaultImpl(..) => { gate_feature_post!(&self, optin_builtin_traits, i.span, diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 92ec0fdb3de3..290a59cf1e59 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -5102,6 +5102,25 @@ impl<'a> Parser<'a> { Ok((class_name, ItemKind::Struct(vdata, generics), None)) } + /// Parse union Foo { ... } + fn parse_item_union(&mut self) -> PResult<'a, ItemInfo> { + let class_name = self.parse_ident()?; + let mut generics = self.parse_generics()?; + + let vdata = if self.token.is_keyword(keywords::Where) { + generics.where_clause = self.parse_where_clause()?; + VariantData::Struct(self.parse_record_struct_body()?, ast::DUMMY_NODE_ID) + } else if self.token == token::OpenDelim(token::Brace) { + VariantData::Struct(self.parse_record_struct_body()?, ast::DUMMY_NODE_ID) + } else { + let token_str = self.this_token_to_string(); + return Err(self.fatal(&format!("expected `where` or `{{` after union \ + name, found `{}`", token_str))) + }; + + Ok((class_name, ItemKind::Union(vdata, generics), None)) + } + pub fn parse_record_struct_body(&mut self) -> PResult<'a, Vec> { let mut fields = Vec::new(); if self.eat(&token::OpenDelim(token::Brace)) { @@ -5938,6 +5957,18 @@ impl<'a> Parser<'a> { maybe_append(attrs, extra_attrs)); return Ok(Some(item)); } + if self.eat_keyword(keywords::Union) { + // UNION ITEM + let (ident, item_, extra_attrs) = self.parse_item_union()?; + let last_span = self.last_span; + let item = self.mk_item(lo, + last_span.hi, + ident, + item_, + visibility, + maybe_append(attrs, extra_attrs)); + return Ok(Some(item)); + } self.parse_macro_use_or_failure(attrs,macros_allowed,attributes_allowed,lo,visibility) } From 641d8e9e4c12b3753cf4e2a9ac901ad08ea90e00 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 10 Aug 2016 21:00:17 +0300 Subject: [PATCH 129/443] Some better support for unions through the compiler --- src/librustc/hir/check_attr.rs | 13 +++-- src/librustc/hir/map/def_collector.rs | 3 +- src/librustc/infer/error_reporting.rs | 4 +- src/librustc/middle/dead.rs | 20 ++++---- src/librustc/middle/expr_use_visitor.rs | 51 +++++++++++-------- src/librustc/middle/stability.rs | 9 ++-- src/librustc/traits/coherence.rs | 2 +- src/librustc/traits/error_reporting.rs | 1 + src/librustc/ty/item_path.rs | 1 + src/librustc/ty/layout.rs | 3 ++ src/librustc/ty/mod.rs | 10 ++-- src/librustc/ty/relate.rs | 7 +++ src/librustc/ty/sty.rs | 7 +-- src/librustc/ty/util.rs | 17 ++++--- src/librustc_borrowck/borrowck/check_loans.rs | 4 +- .../borrowck/gather_loans/gather_moves.rs | 2 +- .../borrowck/gather_loans/move_error.rs | 1 + .../borrowck/mir/elaborate_drops.rs | 4 +- src/librustc_borrowck/borrowck/mir/mod.rs | 2 +- src/librustc_const_eval/check_match.rs | 7 +-- src/librustc_const_eval/eval.rs | 3 +- src/librustc_driver/test.rs | 1 + .../calculate_svh/svh_visitor.rs | 1 + src/librustc_lint/bad_style.rs | 2 +- src/librustc_lint/builtin.rs | 17 +++++-- src/librustc_lint/unused.rs | 1 + src/librustc_mir/hair/cx/expr.rs | 5 +- src/librustc_mir/hair/cx/pattern.rs | 7 ++- src/librustc_mir/transform/type_check.rs | 4 +- src/librustc_passes/consts.rs | 1 + src/librustc_privacy/lib.rs | 10 ++-- src/librustc_resolve/lib.rs | 5 +- src/librustc_save_analysis/lib.rs | 5 +- src/librustc_trans/adt.rs | 3 ++ src/librustc_trans/collector.rs | 1 + src/librustc_trans/common.rs | 6 +-- src/librustc_trans/debuginfo/metadata.rs | 7 +++ src/librustc_trans/glue.rs | 3 ++ src/librustc_trans/type_of.rs | 2 +- src/librustc_typeck/astconv.rs | 2 +- src/librustc_typeck/check/_match.rs | 2 +- src/librustc_typeck/check/dropck.rs | 3 +- src/librustc_typeck/check/method/probe.rs | 3 +- src/librustc_typeck/check/method/suggest.rs | 47 +++++++++-------- src/librustc_typeck/check/mod.rs | 45 +++++++++------- src/librustc_typeck/check/wfcheck.rs | 3 ++ src/librustc_typeck/coherence/mod.rs | 3 +- src/librustc_typeck/coherence/orphan.rs | 7 ++- src/librustc_typeck/coherence/overlap.rs | 2 +- src/librustc_typeck/collect.rs | 3 +- src/librustc_typeck/variance/constraints.rs | 1 + 51 files changed, 241 insertions(+), 132 deletions(-) diff --git a/src/librustc/hir/check_attr.rs b/src/librustc/hir/check_attr.rs index 53624702c848..a2d4239388ac 100644 --- a/src/librustc/hir/check_attr.rs +++ b/src/librustc/hir/check_attr.rs @@ -18,6 +18,7 @@ use syntax::visit::Visitor; enum Target { Fn, Struct, + Union, Enum, Other, } @@ -27,6 +28,7 @@ impl Target { match item.node { ast::ItemKind::Fn(..) => Target::Fn, ast::ItemKind::Struct(..) => Target::Struct, + ast::ItemKind::Union(..) => Target::Union, ast::ItemKind::Enum(..) => Target::Enum, _ => Target::Other, } @@ -62,8 +64,10 @@ impl<'a> CheckAttrVisitor<'a> { let message = match &*name { "C" => { conflicting_reprs += 1; - if target != Target::Struct && target != Target::Enum { - "attribute should be applied to struct or enum" + if target != Target::Struct && + target != Target::Union && + target != Target::Enum { + "attribute should be applied to struct, enum or union" } else { continue } @@ -71,8 +75,9 @@ impl<'a> CheckAttrVisitor<'a> { "packed" => { // Do not increment conflicting_reprs here, because "packed" // can be used to modify another repr hint - if target != Target::Struct { - "attribute should be applied to struct" + if target != Target::Struct && + target != Target::Union { + "attribute should be applied to struct or union" } else { continue } diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs index 389d0a1d50d5..29fb19fd4215 100644 --- a/src/librustc/hir/map/def_collector.rs +++ b/src/librustc/hir/map/def_collector.rs @@ -331,7 +331,8 @@ impl<'ast> intravisit::Visitor<'ast> for DefCollector<'ast> { }); } } - hir::ItemStruct(ref struct_def, _) => { + hir::ItemStruct(ref struct_def, _) | + hir::ItemUnion(ref struct_def, _) => { // If this is a tuple-like struct, register the constructor. if !struct_def.is_struct() { this.create_def(struct_def.id(), diff --git a/src/librustc/infer/error_reporting.rs b/src/librustc/infer/error_reporting.rs index 0cd39882b7cd..efce0c8354ba 100644 --- a/src/librustc/infer/error_reporting.rs +++ b/src/librustc/infer/error_reporting.rs @@ -105,6 +105,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { match item.node { hir::ItemImpl(..) => "impl", hir::ItemStruct(..) => "struct", + hir::ItemUnion(..) => "union", hir::ItemEnum(..) => "enum", hir::ItemTrait(..) => "trait", hir::ItemFn(..) => "function body", @@ -1370,7 +1371,8 @@ impl<'a, 'gcx, 'tcx> Rebuilder<'a, 'gcx, 'tcx> { } hir::TyPath(ref maybe_qself, ref path) => { match self.tcx.expect_def(cur_ty.id) { - Def::Enum(did) | Def::TyAlias(did) | Def::Struct(did) => { + Def::Enum(did) | Def::TyAlias(did) | + Def::Struct(did) | Def::Union(did) => { let generics = self.tcx.lookup_generics(did); let expected = diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index 824383b11afc..9a63ad4b9859 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -86,7 +86,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { } fn lookup_and_handle_definition(&mut self, id: ast::NodeId) { - use ty::TypeVariants::{TyEnum, TyStruct}; + use ty::TypeVariants::{TyEnum, TyStruct, TyUnion}; let def = self.tcx.expect_def(id); @@ -96,7 +96,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { if self.tcx.trait_of_item(def.def_id()).is_some() => { if let Some(substs) = self.tcx.tables.borrow().item_substs.get(&id) { match substs.substs.type_at(0).sty { - TyEnum(tyid, _) | TyStruct(tyid, _) => { + TyEnum(tyid, _) | TyStruct(tyid, _) | TyUnion(tyid, _) => { self.check_def_id(tyid.did) } _ => {} @@ -132,10 +132,11 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { } fn handle_field_access(&mut self, lhs: &hir::Expr, name: ast::Name) { - if let ty::TyStruct(def, _) = self.tcx.expr_ty_adjusted(lhs).sty { - self.insert_def_id(def.struct_variant().field_named(name).did); - } else { - span_bug!(lhs.span, "named field access on non-struct") + match self.tcx.expr_ty_adjusted(lhs).sty { + ty::TyStruct(def, _) | ty::TyUnion(def, _) => { + self.insert_def_id(def.struct_variant().field_named(name).did); + } + _ => span_bug!(lhs.span, "named field access on non-struct"), } } @@ -148,7 +149,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { fn handle_field_pattern_match(&mut self, lhs: &hir::Pat, pats: &[codemap::Spanned]) { let variant = match self.tcx.node_id_to_type(lhs.id).sty { - ty::TyStruct(adt, _) | ty::TyEnum(adt, _) => { + ty::TyStruct(adt, _) | ty::TyUnion(adt, _) | ty::TyEnum(adt, _) => { adt.variant_of_def(self.tcx.expect_def(lhs.id)) } _ => span_bug!(lhs.span, "non-ADT in struct pattern") @@ -185,7 +186,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { match *node { ast_map::NodeItem(item) => { match item.node { - hir::ItemStruct(..) => { + hir::ItemStruct(..) | hir::ItemUnion(..) => { self.struct_has_extern_repr = item.attrs.iter().any(|attr| { attr::find_repr_attrs(self.tcx.sess.diagnostic(), attr) .contains(&attr::ReprExtern) @@ -423,7 +424,8 @@ impl<'a, 'tcx> DeadVisitor<'a, 'tcx> { | hir::ItemConst(..) | hir::ItemFn(..) | hir::ItemEnum(..) - | hir::ItemStruct(..) => true, + | hir::ItemStruct(..) + | hir::ItemUnion(..) => true, _ => false }; let ctor_id = get_struct_ctor_id(item); diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 798702e6fd65..7214049f6cd6 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -672,30 +672,36 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { // Select just those fields of the `with` // expression that will actually be used - if let ty::TyStruct(def, substs) = with_cmt.ty.sty { - // Consume those fields of the with expression that are needed. - for with_field in &def.struct_variant().fields { - if !contains_field_named(with_field, fields) { - let cmt_field = self.mc.cat_field( - &*with_expr, - with_cmt.clone(), - with_field.name, - with_field.ty(self.tcx(), substs) - ); - self.delegate_consume(with_expr.id, with_expr.span, cmt_field); + match with_cmt.ty.sty { + ty::TyStruct(def, substs) => { + // Consume those fields of the with expression that are needed. + for with_field in &def.struct_variant().fields { + if !contains_field_named(with_field, fields) { + let cmt_field = self.mc.cat_field( + &*with_expr, + with_cmt.clone(), + with_field.name, + with_field.ty(self.tcx(), substs) + ); + self.delegate_consume(with_expr.id, with_expr.span, cmt_field); + } } } - } else { - // the base expression should always evaluate to a - // struct; however, when EUV is run during typeck, it - // may not. This will generate an error earlier in typeck, - // so we can just ignore it. - if !self.tcx().sess.has_errors() { - span_bug!( - with_expr.span, - "with expression doesn't evaluate to a struct"); + ty::TyUnion(..) => { + unimplemented_unions!(); } - }; + _ => { + // the base expression should always evaluate to a + // struct; however, when EUV is run during typeck, it + // may not. This will generate an error earlier in typeck, + // so we can just ignore it. + if !self.tcx().sess.has_errors() { + span_bug!( + with_expr.span, + "with expression doesn't evaluate to a struct"); + } + } + } // walk the with expression so that complex expressions // are properly handled. @@ -1012,7 +1018,8 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { debug!("variant downcast_cmt={:?} pat={:?}", downcast_cmt, pat); delegate.matched_pat(pat, downcast_cmt, match_mode); } - Some(Def::Struct(..)) | Some(Def::TyAlias(..)) | Some(Def::AssociatedTy(..)) => { + Some(Def::Struct(..)) | Some(Def::Union(..)) | + Some(Def::TyAlias(..)) | Some(Def::AssociatedTy(..)) => { debug!("struct cmt_pat={:?} pat={:?}", cmt_pat, pat); delegate.matched_pat(pat, cmt_pat, match_mode); } diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index c20fcc3fe1dc..e6979c254533 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -561,7 +561,9 @@ pub fn check_expr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, e: &hir::Expr, hir::ExprField(ref base_e, ref field) => { span = field.span; match tcx.expr_ty_adjusted(base_e).sty { - ty::TyStruct(def, _) => def.struct_variant().field_named(field.node).did, + ty::TyStruct(def, _) | ty::TyUnion(def, _) => { + def.struct_variant().field_named(field.node).did + } _ => span_bug!(e.span, "stability::check_expr: named field access on non-struct") } @@ -579,7 +581,7 @@ pub fn check_expr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, e: &hir::Expr, hir::ExprStruct(_, ref expr_fields, _) => { let type_ = tcx.expr_ty(e); match type_.sty { - ty::TyStruct(def, _) => { + ty::TyStruct(def, _) | ty::TyUnion(def, _) => { // check the stability of each field that appears // in the construction expression. for field in expr_fields { @@ -647,7 +649,8 @@ pub fn check_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, pat: &hir::Pat, if is_internal(tcx, pat.span) { return; } let v = match tcx.pat_ty_opt(pat) { - Some(&ty::TyS { sty: ty::TyStruct(def, _), .. }) => def.struct_variant(), + Some(&ty::TyS { sty: ty::TyStruct(def, _), .. }) | + Some(&ty::TyS { sty: ty::TyUnion(def, _), .. }) => def.struct_variant(), Some(_) | None => return, }; match pat.node { diff --git a/src/librustc/traits/coherence.rs b/src/librustc/traits/coherence.rs index f856e110ea2a..0a7d3e6e76d8 100644 --- a/src/librustc/traits/coherence.rs +++ b/src/librustc/traits/coherence.rs @@ -224,7 +224,7 @@ fn fundamental_ty(tcx: TyCtxt, ty: Ty) -> bool { match ty.sty { ty::TyBox(..) | ty::TyRef(..) => true, - ty::TyEnum(def, _) | ty::TyStruct(def, _) => + ty::TyEnum(def, _) | ty::TyStruct(def, _) | ty::TyUnion(def, _) => def.is_fundamental(), ty::TyTrait(ref data) => tcx.has_attr(data.principal.def_id(), "fundamental"), diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 95e83d404a74..e5ebe96932d4 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -174,6 +174,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { match (type_category(a), type_category(b)) { (Some(cat_a), Some(cat_b)) => match (&a.sty, &b.sty) { (&ty::TyStruct(def_a, _), &ty::TyStruct(def_b, _)) | + (&ty::TyUnion(def_a, _), &ty::TyUnion(def_b, _)) | (&ty::TyEnum(def_a, _), &ty::TyEnum(def_b, _)) => def_a == def_b, _ => cat_a == cat_b diff --git a/src/librustc/ty/item_path.rs b/src/librustc/ty/item_path.rs index 42ec2b18fb02..ba8d33285092 100644 --- a/src/librustc/ty/item_path.rs +++ b/src/librustc/ty/item_path.rs @@ -263,6 +263,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // anything other than a simple path. match self_ty.sty { ty::TyStruct(adt_def, substs) | + ty::TyUnion(adt_def, substs) | ty::TyEnum(adt_def, substs) => { if substs.types().next().is_none() { // ignore regions self.push_item_path(buffer, adt_def.did); diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 622966ca5aba..ac5e3c6fa700 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -1256,6 +1256,9 @@ impl<'a, 'gcx, 'tcx> SizeSkeleton<'gcx> { } } + ty::TyUnion(..) => { + unimplemented_unions!(); + } ty::TyStruct(def, substs) | ty::TyEnum(def, substs) => { // Only newtypes and enums w/ nullable pointer optimization. if def.variants.is_empty() || def.variants.len() > 2 { diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 4cda74911138..ee2188e8e112 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -948,6 +948,7 @@ impl<'tcx> TraitPredicate<'tcx> { .flat_map(|t| t.walk()) .filter_map(|t| match t.sty { ty::TyStruct(adt_def, _) | + ty::TyUnion(adt_def, _) | ty::TyEnum(adt_def, _) => Some(adt_def.did), _ => @@ -1341,6 +1342,7 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> { } hir::ItemEnum(..) | hir::ItemStruct(..) | + hir::ItemUnion(..) | hir::ItemTy(..) | hir::ItemImpl(..) | hir::ItemConst(..) | @@ -1615,7 +1617,8 @@ impl<'a, 'gcx, 'tcx, 'container> AdtDefData<'gcx, 'container> { /// Asserts this is a struct and returns the struct's unique /// variant. pub fn struct_variant(&self) -> &VariantDefData<'gcx, 'container> { - assert_eq!(self.adt_kind(), AdtKind::Struct); + let adt_kind = self.adt_kind(); + assert!(adt_kind == AdtKind::Struct || adt_kind == AdtKind::Union); &self.variants[0] } @@ -1674,7 +1677,8 @@ impl<'a, 'gcx, 'tcx, 'container> AdtDefData<'gcx, 'container> { pub fn variant_of_def(&self, def: Def) -> &VariantDefData<'gcx, 'container> { match def { Def::Variant(_, vid) => self.variant_with_id(vid), - Def::Struct(..) | Def::TyAlias(..) | Def::AssociatedTy(..) => self.struct_variant(), + Def::Struct(..) | Def::Union(..) | + Def::TyAlias(..) | Def::AssociatedTy(..) => self.struct_variant(), _ => bug!("unexpected def {:?} in variant_of_def", def) } } @@ -2413,7 +2417,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { Def::Variant(enum_did, did) => { self.lookup_adt_def(enum_did).variant_with_id(did) } - Def::Struct(did) => { + Def::Struct(did) | Def::Union(did) => { self.lookup_adt_def(did).struct_variant() } _ => bug!("expect_variant_def used with unexpected def {:?}", def) diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index 5c157ff32e7b..dfae19487b6f 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -447,6 +447,13 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R, Ok(tcx.mk_struct(a_def, substs)) } + (&ty::TyUnion(a_def, a_substs), &ty::TyUnion(b_def, b_substs)) + if a_def == b_def => + { + let substs = relate_item_substs(relation, a_def.did, a_substs, b_substs)?; + Ok(tcx.mk_union(a_def, substs)) + } + (&ty::TyClosure(a_id, a_substs), &ty::TyClosure(b_id, b_substs)) if a_id == b_id => diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index b023cdad9ee2..165f86fbef53 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -922,7 +922,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { // FIXME(#24885): be smarter here, the AdtDefData::is_empty method could easily be made // more complete. match self.sty { - TyEnum(def, _) | TyStruct(def, _) => def.is_empty(), + TyEnum(def, _) | TyStruct(def, _) | TyUnion(def, _) => def.is_empty(), // FIXME(canndrew): There's no reason why these can't be uncommented, they're tested // and they don't break anything. But I'm keeping my changes small for now. @@ -985,7 +985,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { pub fn is_structural(&self) -> bool { match self.sty { - TyStruct(..) | TyTuple(_) | TyEnum(..) | + TyStruct(..) | TyUnion(..) | TyTuple(..) | TyEnum(..) | TyArray(..) | TyClosure(..) => true, _ => self.is_slice() | self.is_trait() } @@ -1204,6 +1204,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { match self.sty { TyTrait(ref tt) => Some(tt.principal.def_id()), TyStruct(def, _) | + TyUnion(def, _) | TyEnum(def, _) => Some(def.did), TyClosure(id, _) => Some(id), _ => None @@ -1212,7 +1213,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { pub fn ty_adt_def(&self) -> Option> { match self.sty { - TyStruct(adt, _) | TyEnum(adt, _) => Some(adt), + TyStruct(adt, _) | TyUnion(adt, _) | TyEnum(adt, _) => Some(adt), _ => None } } diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 971fc2cee804..ad209094600a 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -138,7 +138,7 @@ impl<'tcx> ParameterEnvironment<'tcx> { // FIXME: (@jroesch) float this code up tcx.infer_ctxt(None, Some(self.clone()), Reveal::ExactMatch).enter(|infcx| { let adt = match self_type.sty { - ty::TyStruct(struct_def, substs) => { + ty::TyStruct(struct_def, substs) | ty::TyUnion(struct_def, substs) => { for field in struct_def.all_fields() { let field_ty = field.ty(tcx, substs); if infcx.type_moves_by_default(field_ty, span) { @@ -183,7 +183,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn has_error_field(self, ty: Ty<'tcx>) -> bool { match ty.sty { - ty::TyStruct(def, substs) | ty::TyEnum(def, substs) => { + ty::TyStruct(def, substs) | ty::TyUnion(def, substs) | ty::TyEnum(def, substs) => { for field in def.all_fields() { let field_ty = field.ty(self, substs); if let TyError = field_ty.sty { @@ -203,7 +203,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { i: usize, variant: Option) -> Option> { match (&ty.sty, variant) { - (&TyStruct(def, substs), None) => { + (&TyStruct(def, substs), None) | + (&TyUnion(def, substs), None) => { def.struct_variant().fields.get(i).map(|f| f.ty(self, substs)) } (&TyEnum(def, substs), Some(vid)) => { @@ -225,7 +226,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { n: Name, variant: Option) -> Option> { match (&ty.sty, variant) { - (&TyStruct(def, substs), None) => { + (&TyStruct(def, substs), None) | + (&TyUnion(def, substs), None) => { def.struct_variant().find_field_named(n).map(|f| f.ty(self, substs)) } (&TyEnum(def, substs), Some(vid)) => { @@ -661,7 +663,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> { TyArray(ty, _) => { is_type_structurally_recursive(tcx, sp, seen, ty) } - TyStruct(def, substs) | TyEnum(def, substs) => { + TyStruct(def, substs) | TyUnion(def, substs) | TyEnum(def, substs) => { find_nonrepresentable(tcx, sp, seen, @@ -678,7 +680,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> { fn same_struct_or_enum<'tcx>(ty: Ty<'tcx>, def: ty::AdtDef<'tcx>) -> bool { match ty.sty { - TyStruct(ty_def, _) | TyEnum(ty_def, _) => { + TyStruct(ty_def, _) | TyUnion(ty_def, _) | TyEnum(ty_def, _) => { ty_def == def } _ => false @@ -688,6 +690,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> { fn same_type<'tcx>(a: Ty<'tcx>, b: Ty<'tcx>) -> bool { match (&a.sty, &b.sty) { (&TyStruct(did_a, ref substs_a), &TyStruct(did_b, ref substs_b)) | + (&TyUnion(did_a, ref substs_a), &TyUnion(did_b, ref substs_b)) | (&TyEnum(did_a, ref substs_a), &TyEnum(did_b, ref substs_b)) => { if did_a != did_b { return false; @@ -710,7 +713,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> { debug!("is_type_structurally_recursive: {:?}", ty); match ty.sty { - TyStruct(def, _) | TyEnum(def, _) => { + TyStruct(def, _) | TyUnion(def, _) | TyEnum(def, _) => { { // Iterate through stack of previously seen types. let mut iter = seen.iter(); diff --git a/src/librustc_borrowck/borrowck/check_loans.rs b/src/librustc_borrowck/borrowck/check_loans.rs index e86fa9a05f37..b4c6689c24b9 100644 --- a/src/librustc_borrowck/borrowck/check_loans.rs +++ b/src/librustc_borrowck/borrowck/check_loans.rs @@ -796,7 +796,9 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { } LpExtend(ref lp_base, _, LpInterior(_, InteriorField(_))) => { match lp_base.to_type().sty { - ty::TyStruct(def, _) | ty::TyEnum(def, _) if def.has_dtor() => { + ty::TyStruct(def, _) | + ty::TyUnion(def, _) | + ty::TyEnum(def, _) if def.has_dtor() => { // In the case where the owner implements drop, then // the path must be initialized to prevent a case of // partial reinitialization diff --git a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs index 9431dcdbcac8..3cf02fc85a46 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs @@ -178,7 +178,7 @@ fn check_and_get_illegal_move_origin<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, Categorization::Interior(ref b, mc::InteriorField(_)) | Categorization::Interior(ref b, mc::InteriorElement(Kind::Pattern, _)) => { match b.ty.sty { - ty::TyStruct(def, _) | ty::TyEnum(def, _) => { + ty::TyStruct(def, _) | ty::TyUnion(def, _) | ty::TyEnum(def, _) => { if def.has_dtor() { Some(cmt.clone()) } else { diff --git a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs index fc17633d63b9..61c85e393d2d 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs @@ -149,6 +149,7 @@ fn report_cannot_move_out_of<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, Categorization::Interior(ref b, mc::InteriorField(_)) => { match b.ty.sty { ty::TyStruct(def, _) | + ty::TyUnion(def, _) | ty::TyEnum(def, _) if def.has_dtor() => { let mut err = struct_span_err!(bccx, move_from.span, E0509, "cannot move out of type `{}`, \ diff --git a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs index 885bbe856c8f..c5d103453798 100644 --- a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs +++ b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs @@ -709,7 +709,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { fn open_drop<'a>(&mut self, c: &DropCtxt<'a, 'tcx>) -> BasicBlock { let ty = c.lvalue.ty(self.mir, self.tcx).to_ty(self.tcx); match ty.sty { - ty::TyStruct(def, substs) | ty::TyEnum(def, substs) => { + ty::TyStruct(def, substs) | ty::TyUnion(def, substs) | ty::TyEnum(def, substs) => { self.open_drop_for_adt(c, def, substs) } ty::TyTuple(tys) | ty::TyClosure(_, ty::ClosureSubsts { @@ -893,7 +893,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { let ty = c.lvalue.ty(self.mir, self.tcx).to_ty(self.tcx); match ty.sty { - ty::TyStruct(def, _) | ty::TyEnum(def, _) => { + ty::TyStruct(def, _) | ty::TyUnion(def, _) | ty::TyEnum(def, _) => { if def.has_dtor() { self.tcx.sess.span_warn( c.source_info.span, diff --git a/src/librustc_borrowck/borrowck/mir/mod.rs b/src/librustc_borrowck/borrowck/mir/mod.rs index 887c7deb86be..be408e2db5c3 100644 --- a/src/librustc_borrowck/borrowck/mir/mod.rs +++ b/src/librustc_borrowck/borrowck/mir/mod.rs @@ -261,7 +261,7 @@ fn lvalue_contents_drop_state_cannot_differ<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx lv, ty); true } - ty::TyStruct(def, _) | ty::TyEnum(def, _) if def.has_dtor() => { + ty::TyStruct(def, _) | ty::TyUnion(def, _) | ty::TyEnum(def, _) if def.has_dtor() => { debug!("lvalue_contents_drop_state_cannot_differ lv: {:?} ty: {:?} Drop => false", lv, ty); true diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs index e71a780dd89b..de28cbb7c9c9 100644 --- a/src/librustc_const_eval/check_match.rs +++ b/src/librustc_const_eval/check_match.rs @@ -566,7 +566,7 @@ fn construct_witness<'a,'tcx>(cx: &MatchCheckCtxt<'a,'tcx>, ctor: &Constructor, let pat = match left_ty.sty { ty::TyTuple(..) => PatKind::Tuple(pats.collect(), None), - ty::TyEnum(adt, _) | ty::TyStruct(adt, _) => { + ty::TyEnum(adt, _) | ty::TyStruct(adt, _) | ty::TyUnion(adt, _) => { let v = ctor.variant_for_adt(adt); match v.kind { VariantKind::Struct => { @@ -792,7 +792,8 @@ fn pat_constructors(cx: &MatchCheckCtxt, p: &Pat, PatKind::Struct(..) | PatKind::TupleStruct(..) | PatKind::Path(..) => match cx.tcx.expect_def(pat.id) { Def::Variant(_, id) => vec![Variant(id)], - Def::Struct(..) | Def::TyAlias(..) | Def::AssociatedTy(..) => vec![Single], + Def::Struct(..) | Def::Union(..) | + Def::TyAlias(..) | Def::AssociatedTy(..) => vec![Single], Def::Const(..) | Def::AssociatedConst(..) => span_bug!(pat.span, "const pattern should've been rewritten"), def => span_bug!(pat.span, "pat_constructors: unexpected definition {:?}", def), @@ -836,7 +837,7 @@ pub fn constructor_arity(_cx: &MatchCheckCtxt, ctor: &Constructor, ty: Ty) -> us _ => bug!() }, ty::TyRef(..) => 1, - ty::TyEnum(adt, _) | ty::TyStruct(adt, _) => { + ty::TyEnum(adt, _) | ty::TyStruct(adt, _) | ty::TyUnion(adt, _) => { ctor.variant_for_adt(adt).fields.len() } ty::TyArray(_, n) => n, diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index d71add3258fb..81fe19812ca4 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -258,7 +258,8 @@ pub fn const_expr_to_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, format!("floating point constants cannot be used in patterns")); } ty::TyEnum(adt_def, _) | - ty::TyStruct(adt_def, _) => { + ty::TyStruct(adt_def, _) | + ty::TyUnion(adt_def, _) => { if !tcx.has_attr(adt_def.did, "structural_match") { tcx.sess.add_lint( lint::builtin::ILLEGAL_STRUCT_OR_ENUM_CONSTANT_PATTERN, diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index 460a6e68a5c5..9f5f82c144cc 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -220,6 +220,7 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> { hir::ItemEnum(..) | hir::ItemStruct(..) | + hir::ItemUnion(..) | hir::ItemTrait(..) | hir::ItemImpl(..) | hir::ItemDefaultImpl(..) => { diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs index c1158dc2d5fe..d4a3ab59f9cb 100644 --- a/src/librustc_incremental/calculate_svh/svh_visitor.rs +++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs @@ -419,6 +419,7 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> { Def::AssociatedTy(..) | Def::TyParam(..) | Def::Struct(..) | + Def::Union(..) | Def::Trait(..) | Def::Method(..) | Def::Const(..) | diff --git a/src/librustc_lint/bad_style.rs b/src/librustc_lint/bad_style.rs index 0e130c3bb66b..1094d0ee12bb 100644 --- a/src/librustc_lint/bad_style.rs +++ b/src/librustc_lint/bad_style.rs @@ -111,7 +111,7 @@ impl LateLintPass for NonCamelCaseTypes { } match it.node { - hir::ItemTy(..) | hir::ItemStruct(..) => { + hir::ItemTy(..) | hir::ItemStruct(..) | hir::ItemUnion(..) => { self.check_case(cx, "type", it.name, it.span) } hir::ItemTrait(..) => { diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index a103386e2c98..571d1222baaa 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -116,7 +116,8 @@ impl LateLintPass for BoxPointers { hir::ItemFn(..) | hir::ItemTy(..) | hir::ItemEnum(..) | - hir::ItemStruct(..) => + hir::ItemStruct(..) | + hir::ItemUnion(..) => self.check_heap_type(cx, it.span, cx.tcx.node_id_to_type(it.id)), _ => () @@ -124,7 +125,8 @@ impl LateLintPass for BoxPointers { // If it's a struct, we also have to check the fields' types match it.node { - hir::ItemStruct(ref struct_def, _) => { + hir::ItemStruct(ref struct_def, _) | + hir::ItemUnion(ref struct_def, _) => { for struct_field in struct_def.fields() { self.check_heap_type(cx, struct_field.span, cx.tcx.node_id_to_type(struct_field.id)); @@ -348,6 +350,7 @@ impl LateLintPass for MissingDoc { hir::ItemMod(..) => "a module", hir::ItemEnum(..) => "an enum", hir::ItemStruct(..) => "a struct", + hir::ItemUnion(..) => "a union", hir::ItemTrait(_, _, _, ref items) => { // Issue #11592, traits are always considered exported, even when private. if it.vis == hir::Visibility::Inherited { @@ -467,6 +470,14 @@ impl LateLintPass for MissingCopyImplementations { let def = cx.tcx.lookup_adt_def(cx.tcx.map.local_def_id(item.id)); (def, cx.tcx.mk_struct(def, Substs::empty(cx.tcx))) } + hir::ItemUnion(_, ref ast_generics) => { + if ast_generics.is_parameterized() { + return; + } + let def = cx.tcx.lookup_adt_def(cx.tcx.map.local_def_id(item.id)); + (def, cx.tcx.mk_union(def, + cx.tcx.mk_substs(Substs::empty()))) + } hir::ItemEnum(_, ref ast_generics) => { if ast_generics.is_parameterized() { return; @@ -523,7 +534,7 @@ impl LateLintPass for MissingDebugImplementations { } match item.node { - hir::ItemStruct(..) | hir::ItemEnum(..) => {}, + hir::ItemStruct(..) | hir::ItemUnion(..) | hir::ItemEnum(..) => {}, _ => return, } diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index 924b768958d6..44f1cf7b5335 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -137,6 +137,7 @@ impl LateLintPass for UnusedResults { ty::TyNever => return, ty::TyBool => return, ty::TyStruct(def, _) | + ty::TyUnion(def, _) | ty::TyEnum(def, _) => { let attrs = cx.tcx.get_attrs(def.did); check_must_use(cx, &attrs[..], s.span) diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 6e8a5771eea9..0469d44de4ba 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -477,6 +477,9 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, }) } } + ty::TyUnion(..) => { + unimplemented_unions!(); + } ty::TyEnum(adt, substs) => { match cx.tcx.expect_def(expr.id) { Def::Variant(enum_id, variant_id) => { @@ -579,7 +582,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, body: block::to_expr_ref(cx, body) }, hir::ExprField(ref source, name) => { let index = match cx.tcx.expr_ty_adjusted(source).sty { - ty::TyStruct(adt_def, _) => + ty::TyStruct(adt_def, _) | ty::TyUnion(adt_def, _) => adt_def.variants[0].index_of_field_named(name.node), ref ty => span_bug!( diff --git a/src/librustc_mir/hair/cx/pattern.rs b/src/librustc_mir/hair/cx/pattern.rs index 0bd22cd2d930..30f79796aaa6 100644 --- a/src/librustc_mir/hair/cx/pattern.rs +++ b/src/librustc_mir/hair/cx/pattern.rs @@ -217,7 +217,9 @@ impl<'patcx, 'cx, 'gcx, 'tcx> PatCx<'patcx, 'cx, 'gcx, 'tcx> { PatKind::Struct(_, ref fields, _) => { let pat_ty = self.cx.tcx.node_id_to_type(pat.id); let adt_def = match pat_ty.sty { - ty::TyStruct(adt_def, _) | ty::TyEnum(adt_def, _) => adt_def, + ty::TyStruct(adt_def, _) | + ty::TyUnion(adt_def, _) | + ty::TyEnum(adt_def, _) => adt_def, _ => { span_bug!( pat.span, @@ -313,7 +315,8 @@ impl<'patcx, 'cx, 'gcx, 'tcx> PatCx<'patcx, 'cx, 'gcx, 'tcx> { } } - Def::Struct(..) | Def::TyAlias(..) | Def::AssociatedTy(..) => { + Def::Struct(..) | Def::Union(..) | + Def::TyAlias(..) | Def::AssociatedTy(..) => { PatternKind::Leaf { subpatterns: subpatterns } } diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs index 21d4ae595e8a..55bd51cd75ba 100644 --- a/src/librustc_mir/transform/type_check.rs +++ b/src/librustc_mir/transform/type_check.rs @@ -281,7 +281,9 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { (&adt_def.variants[variant_index], substs) } LvalueTy::Ty { ty } => match ty.sty { - ty::TyStruct(adt_def, substs) | ty::TyEnum(adt_def, substs) + ty::TyStruct(adt_def, substs) | + ty::TyUnion(adt_def, substs) | + ty::TyEnum(adt_def, substs) if adt_def.is_univariant() => { (&adt_def.variants[0], substs) } diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs index 2d1b6e1315f8..c3749bf4546f 100644 --- a/src/librustc_passes/consts.rs +++ b/src/librustc_passes/consts.rs @@ -440,6 +440,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> { fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node_ty: Ty<'tcx>) { match node_ty.sty { ty::TyStruct(def, _) | + ty::TyUnion(def, _) | ty::TyEnum(def, _) if def.has_dtor() => { v.add_qualif(ConstQualif::NEEDS_DROP); } diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index cd2eb4d2b58b..25601b6bfec7 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -174,7 +174,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> { self.update(trait_item.id, item_level); } } - hir::ItemStruct(ref def, _) => { + hir::ItemStruct(ref def, _) | hir::ItemUnion(ref def, _) => { if !def.is_struct() { self.update(def.id(), item_level); } @@ -321,8 +321,8 @@ impl<'b, 'a, 'tcx: 'a, 'v> Visitor<'v> for ReachEverythingInTheInterfaceVisitor< if let hir::TyPath(_, ref path) = ty.node { let def = self.ev.tcx.expect_def(ty.id); match def { - Def::Struct(def_id) | Def::Enum(def_id) | Def::TyAlias(def_id) | - Def::Trait(def_id) | Def::AssociatedTy(def_id, _) => { + Def::Struct(def_id) | Def::Union(def_id) | Def::Enum(def_id) | + Def::TyAlias(def_id) | Def::Trait(def_id) | Def::AssociatedTy(def_id, _) => { if let Some(node_id) = self.ev.tcx.map.as_local_node_id(def_id) { let item = self.ev.tcx.map.expect_item(node_id); if let Def::TyAlias(..) = def { @@ -943,8 +943,8 @@ impl<'a, 'tcx: 'a, 'v> Visitor<'v> for SearchInterfaceForPrivateItemsVisitor<'a, // free type aliases, but this isn't done yet. return } - Def::Struct(def_id) | Def::Enum(def_id) | Def::TyAlias(def_id) | - Def::Trait(def_id) | Def::AssociatedTy(def_id, _) => { + Def::Struct(def_id) | Def::Union(def_id) | Def::Enum(def_id) | + Def::TyAlias(def_id) | Def::Trait(def_id) | Def::AssociatedTy(def_id, _) => { // Non-local means public (private items can't leave their crate, modulo bugs) if let Some(node_id) = self.tcx.map.as_local_node_id(def_id) { let item = self.tcx.map.expect_item(node_id); diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 1224c694a4e6..db0704db33fd 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -2187,6 +2187,7 @@ impl<'a> Resolver<'a> { Def::Trait(_) | Def::Enum(_) | Def::Struct(_) | + Def::Union(_) | Def::TyAlias(_) => true, _ => false, }, @@ -2389,7 +2390,7 @@ impl<'a> Resolver<'a> { PatKind::Struct(ref path, _, _) => { self.resolve_pattern_path(pat.id, None, path, TypeNS, |def| { match def { - Def::Struct(..) | Def::Variant(..) | + Def::Struct(..) | Def::Union(..) | Def::Variant(..) | Def::TyAlias(..) | Def::AssociatedTy(..) => true, _ => false, } @@ -2735,7 +2736,7 @@ impl<'a> Resolver<'a> { // Look for a field with the same name in the current self_type. if let Some(resolution) = self.def_map.get(&node_id) { match resolution.base_def { - Def::Enum(did) | Def::TyAlias(did) | + Def::Enum(did) | Def::TyAlias(did) | Def::Union(did) | Def::Struct(did) | Def::Variant(_, did) if resolution.depth == 0 => { if let Some(fields) = self.structs.get(&did) { if fields.iter().any(|&field_name| name == field_name) { diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index db535e22f194..47f3a06de1bd 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -404,7 +404,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { } }; match self.tcx.expr_ty_adjusted(&hir_node).sty { - ty::TyStruct(def, _) => { + ty::TyStruct(def, _) | ty::TyUnion(def, _) => { let f = def.struct_variant().field_named(ident.node.name); let sub_span = self.span_utils.span_for_last_ident(expr.span); filter!(self.span_utils, sub_span, expr.span, None); @@ -423,7 +423,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { } ast::ExprKind::Struct(ref path, _, _) => { match self.tcx.expr_ty_adjusted(&hir_node).sty { - ty::TyStruct(def, _) => { + ty::TyStruct(def, _) | ty::TyUnion(def, _) => { let sub_span = self.span_utils.span_for_last_ident(path.span); filter!(self.span_utils, sub_span, path.span, None); Some(Data::TypeRefData(TypeRefData { @@ -487,6 +487,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { })) } Def::Struct(def_id) | + Def::Union(def_id) | Def::Enum(def_id) | Def::TyAlias(def_id) | Def::Trait(def_id) | diff --git a/src/librustc_trans/adt.rs b/src/librustc_trans/adt.rs index 2fb7a69d3618..069eef7895c8 100644 --- a/src/librustc_trans/adt.rs +++ b/src/librustc_trans/adt.rs @@ -176,6 +176,9 @@ fn represent_type_uncached<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, Univariant(mk_struct(cx, &ftys[..], packed, t)) } + ty::TyUnion(..) => { + unimplemented_unions!(); + } ty::TyClosure(_, ref substs) => { Univariant(mk_struct(cx, &substs.upvar_tys, false, t)) } diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index 47b3bb36cb93..4bea5d7e87fc 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -744,6 +744,7 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, // monomorphized Drop::drop() implementation. let destructor_did = match ty.sty { ty::TyStruct(def, _) | + ty::TyUnion(def, _) | ty::TyEnum(def, _) => def.destructor(), _ => None }; diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index f4682de7dff6..6ae6f8aead77 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -88,8 +88,8 @@ pub fn type_is_immediate<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) - return false; } match ty.sty { - ty::TyStruct(..) | ty::TyEnum(..) | ty::TyTuple(..) | ty::TyArray(_, _) | - ty::TyClosure(..) => { + ty::TyStruct(..) | ty::TyUnion(..) | ty::TyEnum(..) | + ty::TyTuple(..) | ty::TyArray(..) | ty::TyClosure(..) => { let llty = sizing_type_of(ccx, ty); llsize_of_alloc(ccx, llty) <= llsize_of_alloc(ccx, ccx.int_type()) } @@ -205,7 +205,7 @@ impl<'a, 'tcx> VariantInfo<'tcx> { -> Self { match ty.sty { - ty::TyStruct(adt, substs) | ty::TyEnum(adt, substs) => { + ty::TyStruct(adt, substs) | ty::TyUnion(adt, substs) | ty::TyEnum(adt, substs) => { let variant = match opt_def { None => adt.struct_variant(), Some(def) => adt.variant_of_def(def) diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index 67d4a0e044c9..f30880ac9beb 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -184,6 +184,10 @@ impl<'tcx> TypeMap<'tcx> { unique_type_id.push_str("struct "); from_def_id_and_substs(self, cx, def.did, substs, &mut unique_type_id); }, + ty::TyUnion(def, substs) => { + unique_type_id.push_str("union "); + from_def_id_and_substs(self, cx, def.did, substs, &mut unique_type_id); + }, ty::TyTuple(component_types) if component_types.is_empty() => { push_debuginfo_type_name(cx, type_, false, &mut unique_type_id); }, @@ -781,6 +785,9 @@ pub fn type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, unique_type_id, usage_site_span).finalize(cx) } + ty::TyUnion(..) => { + unimplemented_unions!(); + } ty::TyTuple(ref elements) => { prepare_tuple_metadata(cx, t, diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs index 9e1e415f62a6..5da9ef3646e6 100644 --- a/src/librustc_trans/glue.rs +++ b/src/librustc_trans/glue.rs @@ -470,6 +470,9 @@ fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, g: DropGlueK trans_exchange_free_ty(bcx, llbox, content_ty, DebugLoc::None) } } + ty::TyUnion(..) => { + unimplemented_unions!(); + } ty::TyTrait(..) => { // No support in vtable for distinguishing destroying with // versus without calling Drop::drop. Assert caller is diff --git a/src/librustc_trans/type_of.rs b/src/librustc_trans/type_of.rs index d5d8f049681d..b5565109306b 100644 --- a/src/librustc_trans/type_of.rs +++ b/src/librustc_trans/type_of.rs @@ -331,7 +331,7 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> // If this was an enum or struct, fill in the type now. match t.sty { - ty::TyEnum(..) | ty::TyStruct(..) | ty::TyClosure(..) + ty::TyEnum(..) | ty::TyStruct(..) | ty::TyUnion(..) | ty::TyClosure(..) if !t.is_simd() => { let repr = adt::represent_type(cx, t); adt::finish_type_of(cx, &repr, &mut llty); diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 6c9cc5f5e132..c445455ef2bc 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1476,7 +1476,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { span, partition_bounds(tcx, span, &[])) } - Def::Enum(did) | Def::TyAlias(did) | Def::Struct(did) => { + Def::Enum(did) | Def::TyAlias(did) | Def::Struct(did) | Def::Union(did) => { tcx.prohibit_type_params(base_segments.split_last().unwrap().1); self.ast_path_to_ty(rscope, span, diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index f8a2e82edc2a..5fdfa19190bd 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -510,7 +510,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Type check subpatterns. let substs = match pat_ty.sty { - ty::TyStruct(_, substs) | ty::TyEnum(_, substs) => substs, + ty::TyStruct(_, substs) | ty::TyUnion(_, substs) | ty::TyEnum(_, substs) => substs, _ => span_bug!(pat.span, "struct variant is not an ADT") }; self.check_struct_pat_fields(pat.span, fields, variant, substs, etc); diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index bd47ff0b00b7..3e37602169a7 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -45,6 +45,7 @@ pub fn check_drop_impl(ccx: &CrateCtxt, drop_impl_did: DefId) -> Result<(), ()> let dtor_predicates = ccx.tcx.lookup_predicates(drop_impl_did); match dtor_self_type.sty { ty::TyEnum(adt_def, self_to_impl_substs) | + ty::TyUnion(adt_def, self_to_impl_substs) | ty::TyStruct(adt_def, self_to_impl_substs) => { ensure_drop_params_and_item_params_correspond(ccx, drop_impl_did, @@ -495,7 +496,7 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'b, 'gcx, 'tcx>( fn has_dtor_of_interest<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, ty: Ty<'tcx>) -> bool { match ty.sty { - ty::TyEnum(def, _) | ty::TyStruct(def, _) => { + ty::TyEnum(def, _) | ty::TyStruct(def, _) | ty::TyUnion(def, _) => { def.is_dtorck(tcx) } ty::TyTrait(..) | ty::TyProjection(..) | ty::TyAnon(..) => { diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 2e2cb2765d93..edee73008687 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -293,7 +293,8 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { self.assemble_inherent_impl_candidates_for_type(data.principal.def_id()); } ty::TyEnum(def, _) | - ty::TyStruct(def, _) => { + ty::TyStruct(def, _) | + ty::TyUnion(def, _) => { self.assemble_inherent_impl_candidates_for_type(def.did); } ty::TyBox(_) => { diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index 46b3f503b6e7..6d8a73b8a6aa 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -164,30 +164,33 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // give a helping note that it has to be called as (x.f)(...). if let Some(expr) = rcvr_expr { for (ty, _) in self.autoderef(span, rcvr_ty) { - if let ty::TyStruct(def, substs) = ty.sty { - if let Some(field) = def.struct_variant().find_field_named(item_name) { - let snippet = tcx.sess.codemap().span_to_snippet(expr.span); - let expr_string = match snippet { - Ok(expr_string) => expr_string, - _ => "s".into() // Default to a generic placeholder for the - // expression when we can't generate a - // string snippet - }; + match ty.sty { + ty::TyStruct(def, substs) | ty::TyUnion(def, substs) => { + if let Some(field) = def.struct_variant().find_field_named(item_name) { + let snippet = tcx.sess.codemap().span_to_snippet(expr.span); + let expr_string = match snippet { + Ok(expr_string) => expr_string, + _ => "s".into() // Default to a generic placeholder for the + // expression when we can't generate a + // string snippet + }; - let field_ty = field.ty(tcx, substs); + let field_ty = field.ty(tcx, substs); - if self.is_fn_ty(&field_ty, span) { - err.span_note(span, &format!( - "use `({0}.{1})(...)` if you meant to call the function \ - stored in the `{1}` field", - expr_string, item_name)); - } else { - err.span_note(span, &format!( - "did you mean to write `{0}.{1}`?", - expr_string, item_name)); + if self.is_fn_ty(&field_ty, span) { + err.span_note(span, &format!( + "use `({0}.{1})(...)` if you meant to call the function \ + stored in the `{1}` field", + expr_string, item_name)); + } else { + err.span_note(span, &format!( + "did you mean to write `{0}.{1}`?", + expr_string, item_name)); + } + break; } - break; } + _ => {} } } } @@ -355,7 +358,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { rcvr_expr: Option<&hir::Expr>) -> bool { fn is_local(ty: Ty) -> bool { match ty.sty { - ty::TyEnum(def, _) | ty::TyStruct(def, _) => def.did.is_local(), + ty::TyEnum(def, _) | ty::TyStruct(def, _) | ty::TyUnion(def, _) => { + def.did.is_local() + } ty::TyTrait(ref tr) => tr.principal.def_id().is_local(), diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index be33f836cc6c..679ced1987e6 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -762,6 +762,9 @@ pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) { hir::ItemStruct(..) => { check_struct(ccx, it.id, it.span); } + hir::ItemUnion(..) => { + unimplemented_unions!(); + } hir::ItemTy(_, ref generics) => { let pty_ty = ccx.tcx.node_id_to_type(it.id); check_bounds_are_used(ccx, generics, pty_ty); @@ -2942,18 +2945,21 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let mut private_candidate = None; let mut autoderef = self.autoderef(expr.span, expr_t); while let Some((base_t, autoderefs)) = autoderef.next() { - if let ty::TyStruct(base_def, substs) = base_t.sty { - debug!("struct named {:?}", base_t); - if let Some(field) = base_def.struct_variant().find_field_named(field.node) { - let field_ty = self.field_ty(expr.span, field, substs); - if field.vis.is_accessible_from(self.body_id, &self.tcx().map) { - autoderef.finalize(lvalue_pref, Some(base)); - self.write_ty(expr.id, field_ty); - self.write_autoderef_adjustment(base.id, autoderefs); - return; + match base_t.sty { + ty::TyStruct(base_def, substs) | ty::TyUnion(base_def, substs) => { + debug!("struct named {:?}", base_t); + if let Some(field) = base_def.struct_variant().find_field_named(field.node) { + let field_ty = self.field_ty(expr.span, field, substs); + if field.vis.is_accessible_from(self.body_id, &self.tcx().map) { + autoderef.finalize(lvalue_pref, Some(base)); + self.write_ty(expr.id, field_ty); + self.write_autoderef_adjustment(base.id, autoderefs); + return; + } + private_candidate = Some((base_def.did, field_ty)); } - private_candidate = Some((base_def.did, field_ty)); } + _ => {} } } autoderef.unambiguous_final_ty(); @@ -2986,12 +2992,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { but no field with that name was found", field.node, actual) }, expr_t); - if let ty::TyRawPtr(..) = expr_t.sty { - err.note(&format!("`{0}` is a native pointer; perhaps you need to deref with \ - `(*{0}).{1}`", pprust::expr_to_string(base), field.node)); - } - if let ty::TyStruct(def, _) = expr_t.sty { - Self::suggest_field_names(&mut err, def.struct_variant(), field, vec![]); + match expr_t.sty { + ty::TyStruct(def, _) | ty::TyUnion(def, _) => { + Self::suggest_field_names(&mut err, def.struct_variant(), field, vec![]); + } + ty::TyRawPtr(..) => { + err.note(&format!("`{0}` is a native pointer; perhaps you need to deref with \ + `(*{0}).{1}`", pprust::expr_to_string(base), field.node)); + } + _ => {} } err.emit(); self.write_error(expr.id); @@ -3125,7 +3134,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { check_completeness: bool) { let tcx = self.tcx; let substs = match adt_ty.sty { - ty::TyStruct(_, substs) | ty::TyEnum(_, substs) => substs, + ty::TyStruct(_, substs) | ty::TyUnion(_, substs) | ty::TyEnum(_, substs) => substs, _ => span_bug!(span, "non-ADT passed to check_expr_struct_fields") }; @@ -3217,7 +3226,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.set_tainted_by_errors(); return None; } - Def::Variant(type_did, _) | Def::Struct(type_did) => { + Def::Variant(type_did, _) | Def::Struct(type_did) | Def::Union(type_did) => { Some((type_did, self.tcx.expect_variant_def(def))) } Def::TyAlias(did) => { diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 435442bd30a6..19bee13b6f60 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -142,6 +142,9 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { self.check_variances_for_type_defn(item, ast_generics); } + hir::ItemUnion(..) => { + unimplemented_unions!(); + } hir::ItemEnum(ref enum_def, ref ast_generics) => { self.check_type_defn(item, |fcx| { fcx.enum_variants(enum_def) diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index a20195bd801d..fba145efa950 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -242,7 +242,8 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { let self_type = tcx.lookup_item_type(impl_did); match self_type.ty.sty { ty::TyEnum(type_def, _) | - ty::TyStruct(type_def, _) => { + ty::TyStruct(type_def, _) | + ty::TyUnion(type_def, _) => { type_def.set_destructor(method_def_id.def_id()); } _ => { diff --git a/src/librustc_typeck/coherence/orphan.rs b/src/librustc_typeck/coherence/orphan.rs index bcce64cb110c..4c38475335ce 100644 --- a/src/librustc_typeck/coherence/orphan.rs +++ b/src/librustc_typeck/coherence/orphan.rs @@ -76,7 +76,8 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> { let self_ty = self.tcx.lookup_item_type(def_id).ty; match self_ty.sty { ty::TyEnum(def, _) | - ty::TyStruct(def, _) => { + ty::TyStruct(def, _) | + ty::TyUnion(def, _) => { self.check_def_id(item, def.did); } ty::TyTrait(ref data) => { @@ -293,7 +294,9 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> { { let self_ty = trait_ref.self_ty(); let opt_self_def_id = match self_ty.sty { - ty::TyStruct(self_def, _) | ty::TyEnum(self_def, _) => + ty::TyStruct(self_def, _) | + ty::TyUnion(self_def, _) | + ty::TyEnum(self_def, _) => Some(self_def.did), ty::TyBox(..) => self.tcx.lang_items.owned_box(), diff --git a/src/librustc_typeck/coherence/overlap.rs b/src/librustc_typeck/coherence/overlap.rs index f60fb9583a66..c4d925372f18 100644 --- a/src/librustc_typeck/coherence/overlap.rs +++ b/src/librustc_typeck/coherence/overlap.rs @@ -97,7 +97,7 @@ impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> { impl<'cx, 'tcx,'v> intravisit::Visitor<'v> for OverlapChecker<'cx, 'tcx> { fn visit_item(&mut self, item: &'v hir::Item) { match item.node { - hir::ItemEnum(..) | hir::ItemStruct(..) => { + hir::ItemEnum(..) | hir::ItemStruct(..) | hir::ItemUnion(..) => { let type_def_id = self.tcx.map.local_def_id(item.id); self.check_for_overlapping_inherent_impls(type_def_id); } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 7f9de2becee6..1d260b9dbb29 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -931,7 +931,8 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { tcx.trait_item_def_ids.borrow_mut().insert(ccx.tcx.map.local_def_id(it.id), trait_item_def_ids); }, - hir::ItemStruct(ref struct_def, _) => { + hir::ItemStruct(ref struct_def, _) | + hir::ItemUnion(ref struct_def, _) => { let def_id = ccx.tcx.map.local_def_id(it.id); let scheme = type_scheme_of_def_id(ccx, def_id); let predicates = predicates_of_item(ccx, it); diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs index e20e74be67cd..24eb29f45a5e 100644 --- a/src/librustc_typeck/variance/constraints.rs +++ b/src/librustc_typeck/variance/constraints.rs @@ -185,6 +185,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { hir::ItemTy(..) | hir::ItemEnum(..) | hir::ItemStruct(..) | + hir::ItemUnion(..) | hir::ItemTrait(..) => is_inferred = true, hir::ItemFn(..) => is_inferred = false, _ => cannot_happen!(), From 6792bd99febc646f22814b6759e31e622850f405 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 10 Aug 2016 21:00:17 +0300 Subject: [PATCH 130/443] Support unions in rustdoc --- src/librustdoc/clean/inline.rs | 19 +++++++ src/librustdoc/clean/mod.rs | 36 ++++++++++++- src/librustdoc/doctree.rs | 15 ++++++ src/librustdoc/fold.rs | 7 +++ src/librustdoc/html/item_type.rs | 4 ++ src/librustdoc/html/render.rs | 81 ++++++++++++++++++++++++++++-- src/librustdoc/html/static/main.js | 3 +- src/librustdoc/passes.rs | 2 +- src/librustdoc/visit_ast.rs | 24 ++++++++- src/librustdoc/visit_lib.rs | 1 + src/test/rustdoc/union.rs | 20 ++++++++ 11 files changed, 204 insertions(+), 8 deletions(-) create mode 100644 src/test/rustdoc/union.rs diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 20d4c4176554..4250979a2403 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -88,6 +88,11 @@ fn try_inline_def<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>, ret.extend(build_impls(cx, tcx, did)); clean::StructItem(build_struct(cx, tcx, did)) } + Def::Union(did) => { + record_extern_fqn(cx, did, clean::TypeUnion); + ret.extend(build_impls(cx, tcx, did)); + clean::UnionItem(build_union(cx, tcx, did)) + } Def::TyAlias(did) => { record_extern_fqn(cx, did, clean::TypeTypedef); ret.extend(build_impls(cx, tcx, did)); @@ -214,6 +219,20 @@ fn build_struct<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>, } } +fn build_union<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>, + did: DefId) -> clean::Union { + let t = tcx.lookup_item_type(did); + let predicates = tcx.lookup_predicates(did); + let variant = tcx.lookup_adt_def(did).struct_variant(); + + clean::Union { + struct_type: doctree::Plain, + generics: (&t.generics, &predicates, subst::TypeSpace).clean(cx), + fields: variant.fields.clean(cx), + fields_stripped: false, + } +} + fn build_type<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>, did: DefId) -> clean::ItemEnum { let t = tcx.lookup_item_type(did); diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 92bb265ca995..f8ec5a55e7d4 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -321,6 +321,7 @@ impl Item { pub fn has_stripped_fields(&self) -> Option { match self.inner { StructItem(ref _struct) => Some(_struct.fields_stripped), + UnionItem(ref union) => Some(union.fields_stripped), VariantItem(Variant { kind: StructVariant(ref vstruct)} ) => { Some(vstruct.fields_stripped) }, @@ -351,6 +352,7 @@ pub enum ItemEnum { ExternCrateItem(String, Option), ImportItem(Import), StructItem(Struct), + UnionItem(Union), EnumItem(Enum), FunctionItem(Function), ModuleItem(Module), @@ -414,6 +416,7 @@ impl Clean for doctree::Module { items.extend(self.extern_crates.iter().map(|x| x.clean(cx))); items.extend(self.imports.iter().flat_map(|x| x.clean(cx))); items.extend(self.structs.iter().map(|x| x.clean(cx))); + items.extend(self.unions.iter().map(|x| x.clean(cx))); items.extend(self.enums.iter().map(|x| x.clean(cx))); items.extend(self.fns.iter().map(|x| x.clean(cx))); items.extend(self.foreigns.iter().flat_map(|x| x.clean(cx))); @@ -1464,6 +1467,7 @@ pub enum TypeKind { TypeConst, TypeStatic, TypeStruct, + TypeUnion, TypeTrait, TypeVariant, TypeTypedef, @@ -1801,12 +1805,13 @@ impl<'tcx> Clean for ty::Ty<'tcx> { decl: (cx.map.local_def_id(0), &fty.sig).clean(cx), abi: fty.abi, }), - ty::TyUnion(..) => unimplemented_unions!(), ty::TyStruct(def, substs) | + ty::TyUnion(def, substs) | ty::TyEnum(def, substs) => { let did = def.did; let kind = match self.sty { ty::TyStruct(..) => TypeStruct, + ty::TyUnion(..) => TypeUnion, _ => TypeEnum, }; inline::record_extern_fqn(cx, did, kind); @@ -1929,6 +1934,14 @@ pub struct Struct { pub fields_stripped: bool, } +#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +pub struct Union { + pub struct_type: doctree::StructType, + pub generics: Generics, + pub fields: Vec, + pub fields_stripped: bool, +} + impl Clean for doctree::Struct { fn clean(&self, cx: &DocContext) -> Item { Item { @@ -1949,6 +1962,26 @@ impl Clean for doctree::Struct { } } +impl Clean for doctree::Union { + fn clean(&self, cx: &DocContext) -> Item { + Item { + name: Some(self.name.clean(cx)), + attrs: self.attrs.clean(cx), + source: self.whence.clean(cx), + def_id: cx.map.local_def_id(self.id), + visibility: self.vis.clean(cx), + stability: self.stab.clean(cx), + deprecation: self.depr.clean(cx), + inner: UnionItem(Union { + struct_type: self.struct_type, + generics: self.generics.clean(cx), + fields: self.fields.clean(cx), + fields_stripped: false, + }), + } + } +} + /// This is a more limited form of the standard Struct, different in that /// it lacks the things most items have (name, id, parameterization). Found /// only as a variant in an enum. @@ -2748,6 +2781,7 @@ fn register_def(cx: &DocContext, def: Def) -> DefId { Def::Enum(i) => (i, TypeEnum), Def::Trait(i) => (i, TypeTrait), Def::Struct(i) => (i, TypeStruct), + Def::Union(i) => (i, TypeUnion), Def::Mod(i) => (i, TypeModule), Def::Static(i, _) => (i, TypeStatic), Def::Variant(i, _) => (i, TypeEnum), diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs index 04d176c36c8c..cc62fcfa0aa8 100644 --- a/src/librustdoc/doctree.rs +++ b/src/librustdoc/doctree.rs @@ -30,6 +30,7 @@ pub struct Module { pub extern_crates: Vec, pub imports: Vec, pub structs: Vec, + pub unions: Vec, pub enums: Vec, pub fns: Vec, pub mods: Vec, @@ -62,6 +63,7 @@ impl Module { extern_crates: Vec::new(), imports : Vec::new(), structs : Vec::new(), + unions : Vec::new(), enums : Vec::new(), fns : Vec::new(), mods : Vec::new(), @@ -108,6 +110,19 @@ pub struct Struct { pub whence: Span, } +pub struct Union { + pub vis: hir::Visibility, + pub stab: Option, + pub depr: Option, + pub id: NodeId, + pub struct_type: StructType, + pub name: Name, + pub generics: hir::Generics, + pub attrs: hir::HirVec, + pub fields: hir::HirVec, + pub whence: Span, +} + pub struct Enum { pub vis: hir::Visibility, pub stab: Option, diff --git a/src/librustdoc/fold.rs b/src/librustdoc/fold.rs index 5595c749256d..8d6ab221c4fc 100644 --- a/src/librustdoc/fold.rs +++ b/src/librustdoc/fold.rs @@ -49,6 +49,13 @@ pub trait DocFolder : Sized { i.fields.iter().any(|f| f.is_stripped()); StructItem(i) }, + UnionItem(mut i) => { + let num_fields = i.fields.len(); + i.fields = i.fields.into_iter().filter_map(|x| self.fold_item(x)).collect(); + i.fields_stripped |= num_fields != i.fields.len() || + i.fields.iter().any(|f| f.is_stripped()); + UnionItem(i) + }, EnumItem(mut i) => { let num_variants = i.variants.len(); i.variants = i.variants.into_iter().filter_map(|x| self.fold_item(x)).collect(); diff --git a/src/librustdoc/html/item_type.rs b/src/librustdoc/html/item_type.rs index be1921792846..9ce3c79e2f19 100644 --- a/src/librustdoc/html/item_type.rs +++ b/src/librustdoc/html/item_type.rs @@ -40,6 +40,7 @@ pub enum ItemType { AssociatedType = 16, Constant = 17, AssociatedConst = 18, + Union = 19, } @@ -62,6 +63,7 @@ impl<'a> From<&'a clean::Item> for ItemType { clean::ExternCrateItem(..) => ItemType::ExternCrate, clean::ImportItem(..) => ItemType::Import, clean::StructItem(..) => ItemType::Struct, + clean::UnionItem(..) => ItemType::Union, clean::EnumItem(..) => ItemType::Enum, clean::FunctionItem(..) => ItemType::Function, clean::TypedefItem(..) => ItemType::Typedef, @@ -89,6 +91,7 @@ impl From for ItemType { fn from(kind: clean::TypeKind) -> ItemType { match kind { clean::TypeStruct => ItemType::Struct, + clean::TypeUnion => ItemType::Union, clean::TypeEnum => ItemType::Enum, clean::TypeFunction => ItemType::Function, clean::TypeTrait => ItemType::Trait, @@ -108,6 +111,7 @@ impl ItemType { ItemType::ExternCrate => "externcrate", ItemType::Import => "import", ItemType::Struct => "struct", + ItemType::Union => "union", ItemType::Enum => "enum", ItemType::Function => "fn", ItemType::Typedef => "type", diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 6d523ff38155..c1bb9d9f633b 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -1053,6 +1053,7 @@ impl DocFolder for Cache { // information if present. Some(&(ref fqp, ItemType::Trait)) | Some(&(ref fqp, ItemType::Struct)) | + Some(&(ref fqp, ItemType::Union)) | Some(&(ref fqp, ItemType::Enum)) => Some(&fqp[..fqp.len() - 1]), Some(..) => Some(&*self.stack), @@ -1106,7 +1107,8 @@ impl DocFolder for Cache { clean::TypedefItem(..) | clean::TraitItem(..) | clean::FunctionItem(..) | clean::ModuleItem(..) | clean::ForeignFunctionItem(..) | clean::ForeignStaticItem(..) | - clean::ConstantItem(..) | clean::StaticItem(..) + clean::ConstantItem(..) | clean::StaticItem(..) | + clean::UnionItem(..) if !self.stripped_mod => { // Reexported items mean that the same id can show up twice // in the rustdoc ast that we're looking at. We know, @@ -1141,7 +1143,8 @@ impl DocFolder for Cache { // Maintain the parent stack let orig_parent_is_trait_impl = self.parent_is_trait_impl; let parent_pushed = match item.inner { - clean::TraitItem(..) | clean::EnumItem(..) | clean::StructItem(..) => { + clean::TraitItem(..) | clean::EnumItem(..) | + clean::StructItem(..) | clean::UnionItem(..) => { self.parent_stack.push(item.def_id); self.parent_is_trait_impl = false; true @@ -1557,6 +1560,7 @@ impl<'a> fmt::Display for Item<'a> { clean::FunctionItem(..) => write!(fmt, "Function ")?, clean::TraitItem(..) => write!(fmt, "Trait ")?, clean::StructItem(..) => write!(fmt, "Struct ")?, + clean::UnionItem(..) => write!(fmt, "Union ")?, clean::EnumItem(..) => write!(fmt, "Enum ")?, clean::PrimitiveItem(..) => write!(fmt, "Primitive Type ")?, _ => {} @@ -1613,6 +1617,7 @@ impl<'a> fmt::Display for Item<'a> { item_function(fmt, self.cx, self.item, f), clean::TraitItem(ref t) => item_trait(fmt, self.cx, self.item, t), clean::StructItem(ref s) => item_struct(fmt, self.cx, self.item, s), + clean::UnionItem(ref s) => item_union(fmt, self.cx, self.item, s), clean::EnumItem(ref e) => item_enum(fmt, self.cx, self.item, e), clean::TypedefItem(ref t, _) => item_typedef(fmt, self.cx, self.item, t), clean::MacroItem(ref m) => item_macro(fmt, self.cx, self.item, m), @@ -1715,7 +1720,8 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context, ItemType::Trait => 9, ItemType::Function => 10, ItemType::Typedef => 12, - _ => 13 + ty as u8, + ItemType::Union => 13, + _ => 14 + ty as u8, } } @@ -1759,6 +1765,7 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context, ItemType::Import => ("reexports", "Reexports"), ItemType::Module => ("modules", "Modules"), ItemType::Struct => ("structs", "Structs"), + ItemType::Union => ("unions", "Unions"), ItemType::Enum => ("enums", "Enums"), ItemType::Function => ("functions", "Functions"), ItemType::Typedef => ("types", "Type Definitions"), @@ -2312,6 +2319,40 @@ fn item_struct(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All) } +fn item_union(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, + s: &clean::Union) -> fmt::Result { + write!(w, "
")?;
+    render_attributes(w, it)?;
+    render_union(w,
+                 it,
+                 Some(&s.generics),
+                 &s.fields,
+                 "",
+                 true)?;
+    write!(w, "
")?; + + document(w, cx, it)?; + let mut fields = s.fields.iter().filter_map(|f| { + match f.inner { + clean::StructFieldItem(ref ty) => Some((f, ty)), + _ => None, + } + }).peekable(); + if fields.peek().is_some() { + write!(w, "

Fields

")?; + for (field, ty) in fields { + write!(w, "{name}: {ty} + ", + shortty = ItemType::StructField, + stab = field.stability_class(), + name = field.name.as_ref().unwrap(), + ty = ty)?; + document(w, cx, field)?; + } + } + render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All) +} + fn item_enum(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, e: &clean::Enum) -> fmt::Result { write!(w, "
")?;
@@ -2514,6 +2555,40 @@ fn render_struct(w: &mut fmt::Formatter, it: &clean::Item,
     Ok(())
 }
 
+fn render_union(w: &mut fmt::Formatter, it: &clean::Item,
+                g: Option<&clean::Generics>,
+                fields: &[clean::Item],
+                tab: &str,
+                structhead: bool) -> fmt::Result {
+    write!(w, "{}{}{}",
+           VisSpace(&it.visibility),
+           if structhead {"union "} else {""},
+           it.name.as_ref().unwrap())?;
+    if let Some(g) = g {
+        write!(w, "{}", g)?
+    }
+    if let Some(g) = g {
+        write!(w, "{}", WhereClause(g))?
+    }
+
+    write!(w, " {{\n{}", tab)?;
+    for field in fields {
+        if let clean::StructFieldItem(ref ty) = field.inner {
+            write!(w, "    {}{}: {},\n{}",
+                   VisSpace(&field.visibility),
+                   field.name.as_ref().unwrap(),
+                   *ty,
+                   tab)?;
+        }
+    }
+
+    if it.has_stripped_fields().unwrap() {
+        write!(w, "    // some fields omitted\n{}", tab)?;
+    }
+    write!(w, "}}")?;
+    Ok(())
+}
+
 #[derive(Copy, Clone)]
 enum AssocItemLink<'a> {
     Anchor(Option<&'a str>),
diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js
index de7e4d2483b4..9bb7246e7a92 100644
--- a/src/librustdoc/html/static/main.js
+++ b/src/librustdoc/html/static/main.js
@@ -34,7 +34,8 @@
                      "primitive",
                      "associatedtype",
                      "constant",
-                     "associatedconstant"];
+                     "associatedconstant",
+                     "union"];
 
     // used for special search precedence
     var TY_PRIMITIVE = itemTypes.indexOf("primitive");
diff --git a/src/librustdoc/passes.rs b/src/librustdoc/passes.rs
index b8e40790646a..c60e22824965 100644
--- a/src/librustdoc/passes.rs
+++ b/src/librustdoc/passes.rs
@@ -113,7 +113,7 @@ impl<'a> fold::DocFolder for Stripper<'a> {
             clean::TraitItem(..) | clean::FunctionItem(..) |
             clean::VariantItem(..) | clean::MethodItem(..) |
             clean::ForeignFunctionItem(..) | clean::ForeignStaticItem(..) |
-            clean::ConstantItem(..) => {
+            clean::ConstantItem(..) | clean::UnionItem(..) => {
                 if i.def_id.is_local() {
                     if !self.access_levels.is_exported(i.def_id) {
                         return None;
diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs
index e70fbf4463a2..16a6e994b5a0 100644
--- a/src/librustdoc/visit_ast.rs
+++ b/src/librustdoc/visit_ast.rs
@@ -108,6 +108,25 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
         }
     }
 
+    pub fn visit_union_data(&mut self, item: &hir::Item,
+                            name: ast::Name, sd: &hir::VariantData,
+                            generics: &hir::Generics) -> Union {
+        debug!("Visiting union");
+        let struct_type = struct_type_from_def(&*sd);
+        Union {
+            id: item.id,
+            struct_type: struct_type,
+            name: name,
+            vis: item.vis.clone(),
+            stab: self.stability(item.id),
+            depr: self.deprecation(item.id),
+            attrs: item.attrs.clone(),
+            generics: generics.clone(),
+            fields: sd.fields().iter().cloned().collect(),
+            whence: item.span
+        }
+    }
+
     pub fn visit_enum_def(&mut self, it: &hir::Item,
                           name: ast::Name, def: &hir::EnumDef,
                           params: &hir::Generics) -> Enum {
@@ -258,6 +277,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
             match def {
                 Def::Trait(did) |
                 Def::Struct(did) |
+                Def::Union(did) |
                 Def::Enum(did) |
                 Def::TyAlias(did) if !self_is_hidden => {
                     self.cx.access_levels.borrow_mut().map.insert(did, AccessLevel::Public);
@@ -365,8 +385,8 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
                 om.enums.push(self.visit_enum_def(item, name, ed, gen)),
             hir::ItemStruct(ref sd, ref gen) =>
                 om.structs.push(self.visit_variant_data(item, name, sd, gen)),
-            hir::ItemUnion(..) =>
-                unimplemented_unions!(),
+            hir::ItemUnion(ref sd, ref gen) =>
+                om.unions.push(self.visit_union_data(item, name, sd, gen)),
             hir::ItemFn(ref fd, ref unsafety, constness, ref abi, ref gen, _) =>
                 om.fns.push(self.visit_fn(item, name, &**fd, unsafety,
                                           constness, abi, gen)),
diff --git a/src/librustdoc/visit_lib.rs b/src/librustdoc/visit_lib.rs
index f6d89f7c1dc8..3af030706b73 100644
--- a/src/librustdoc/visit_lib.rs
+++ b/src/librustdoc/visit_lib.rs
@@ -73,6 +73,7 @@ impl<'a, 'b, 'tcx> LibEmbargoVisitor<'a, 'b, 'tcx> {
                     Def::ForeignMod(did) |
                     Def::Trait(did) |
                     Def::Struct(did) |
+                    Def::Union(did) |
                     Def::Enum(did) |
                     Def::TyAlias(did) |
                     Def::Fn(did) |
diff --git a/src/test/rustdoc/union.rs b/src/test/rustdoc/union.rs
new file mode 100644
index 000000000000..0dcc9098ad75
--- /dev/null
+++ b/src/test/rustdoc/union.rs
@@ -0,0 +1,20 @@
+// 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.
+
+#![feature(untagged_unions)]
+
+// @has union/union.U.html
+pub union U {
+    // @has - //pre "pub a: u8"
+    pub a: u8,
+    // @has - //pre "// some fields omitted"
+    // @!has - //pre "b: u16"
+    b: u16,
+}

From 5f9ef3c8b28c9a25be74bc2e41399a4c684f07b1 Mon Sep 17 00:00:00 2001
From: Vadim Petrochenkov 
Date: Mon, 15 Aug 2016 16:10:58 +0300
Subject: [PATCH 131/443] Implement encoding/decoding unions in metadata

Add well-formedness check
Implement some more missing code
---
 src/librustc/middle/expr_use_visitor.rs       |  6 +---
 src/librustc/ty/fast_reject.rs                |  5 +--
 src/librustc_metadata/decoder.rs              |  7 ++++
 src/librustc_typeck/check/dropck.rs           |  3 +-
 src/librustc_typeck/check/mod.rs              | 26 +++++++-------
 src/librustc_typeck/check/wfcheck.rs          | 34 ++++++++++---------
 src/test/compile-fail/attr-usage-repr.rs      |  2 +-
 src/test/compile-fail/issue-31769.rs          |  2 +-
 .../compile-fail/union-nonrepresentable.rs    | 18 ++++++++++
 src/test/compile-fail/union-unsized.rs        | 17 ++++++++++
 src/test/run-pass/auxiliary/union.rs          | 16 +++++++++
 src/test/run-pass/union-xcrate.rs             | 21 ++++++++++++
 12 files changed, 119 insertions(+), 38 deletions(-)
 create mode 100644 src/test/compile-fail/union-nonrepresentable.rs
 create mode 100644 src/test/compile-fail/union-unsized.rs
 create mode 100644 src/test/run-pass/auxiliary/union.rs
 create mode 100644 src/test/run-pass/union-xcrate.rs

diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs
index 7214049f6cd6..a6835802f1cf 100644
--- a/src/librustc/middle/expr_use_visitor.rs
+++ b/src/librustc/middle/expr_use_visitor.rs
@@ -414,7 +414,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
             }
 
             hir::ExprStruct(_, ref fields, ref opt_with) => {
-                self.walk_struct_expr(expr, fields, opt_with);
+                self.walk_struct_expr(fields, opt_with);
             }
 
             hir::ExprTup(ref exprs) => {
@@ -655,7 +655,6 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
     }
 
     fn walk_struct_expr(&mut self,
-                        _expr: &hir::Expr,
                         fields: &[hir::Field],
                         opt_with: &Option>) {
         // Consume the expressions supplying values for each field.
@@ -687,9 +686,6 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
                     }
                 }
             }
-            ty::TyUnion(..) => {
-                unimplemented_unions!();
-            }
             _ => {
                 // the base expression should always evaluate to a
                 // struct; however, when EUV is run during typeck, it
diff --git a/src/librustc/ty/fast_reject.rs b/src/librustc/ty/fast_reject.rs
index 23678d1e3774..f9ca2484d7ef 100644
--- a/src/librustc/ty/fast_reject.rs
+++ b/src/librustc/ty/fast_reject.rs
@@ -30,6 +30,7 @@ pub enum SimplifiedType {
     TupleSimplifiedType(usize),
     TraitSimplifiedType(DefId),
     StructSimplifiedType(DefId),
+    UnionSimplifiedType(DefId),
     ClosureSimplifiedType(DefId),
     AnonSimplifiedType(DefId),
     FunctionSimplifiedType(usize),
@@ -66,8 +67,8 @@ pub fn simplify_type<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
         ty::TyStruct(def, _) => {
             Some(StructSimplifiedType(def.did))
         }
-        ty::TyUnion(..) => {
-            unimplemented_unions!();
+        ty::TyUnion(def, _) => {
+            Some(UnionSimplifiedType(def.did))
         }
         ty::TyRef(_, mt) => {
             // since we introduce auto-refs during method lookup, we
diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs
index 9a13be8ade52..8775f58d0b22 100644
--- a/src/librustc_metadata/decoder.rs
+++ b/src/librustc_metadata/decoder.rs
@@ -133,6 +133,7 @@ enum Family {
     DefaultImpl,           // d
     Trait,                 // I
     Struct(VariantKind),   // S, s, u
+    Union,                 // U
     PublicField,           // g
     InheritedField,        // N
     Constant,              // C
@@ -160,6 +161,7 @@ fn item_family(item: rbml::Doc) -> Family {
       'S' => Struct(VariantKind::Struct),
       's' => Struct(VariantKind::Tuple),
       'u' => Struct(VariantKind::Unit),
+      'U' => Union,
       'g' => PublicField,
       'N' => InheritedField,
        c => bug!("unexpected family char: {}", c)
@@ -317,6 +319,7 @@ fn item_to_def_like(cdata: Cmd, item: rbml::Doc, did: DefId) -> DefLike {
         ImmStatic => DlDef(Def::Static(did, false)),
         MutStatic => DlDef(Def::Static(did, true)),
         Struct(..) => DlDef(Def::Struct(did)),
+        Union => DlDef(Def::Union(did)),
         Fn        => DlDef(Def::Fn(did)),
         Method | StaticMethod => {
             DlDef(Def::Method(did))
@@ -461,6 +464,10 @@ pub fn get_adt_def<'a, 'tcx>(cdata: Cmd,
             (ty::AdtKind::Struct,
              vec![get_struct_variant(cdata, doc, ctor_did.unwrap_or(did))])
         }
+        Union => {
+            (ty::AdtKind::Union,
+             vec![get_struct_variant(cdata, doc, did)])
+        }
         _ => bug!("get_adt_def called on a non-ADT {:?} - {:?}",
                   item_family(doc), did)
     };
diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs
index 3e37602169a7..88add66b7dcb 100644
--- a/src/librustc_typeck/check/dropck.rs
+++ b/src/librustc_typeck/check/dropck.rs
@@ -306,7 +306,8 @@ pub fn check_safety_of_destructor_if_necessary<'a, 'gcx, 'tcx>(
                                                      variant),
                         ty::AdtKind::Struct => format!("struct {}",
                                                        tcx.item_path_str(def_id)),
-                        ty::AdtKind::Union => unimplemented_unions!(),
+                        ty::AdtKind::Union => format!("union {}",
+                                                       tcx.item_path_str(def_id)),
                     };
                     span_note!(
                         &mut err,
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 679ced1987e6..e2954cecc9c4 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -713,16 +713,18 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
     fcx
 }
 
-pub fn check_struct(ccx: &CrateCtxt, id: ast::NodeId, span: Span) {
-    let tcx = ccx.tcx;
+fn check_struct(ccx: &CrateCtxt, id: ast::NodeId, span: Span) {
+    check_representable(ccx.tcx, span, id);
 
-    check_representable(tcx, span, id, "struct");
-
-    if tcx.lookup_simd(ccx.tcx.map.local_def_id(id)) {
-        check_simd(tcx, span, id);
+    if ccx.tcx.lookup_simd(ccx.tcx.map.local_def_id(id)) {
+        check_simd(ccx.tcx, span, id);
     }
 }
 
+fn check_union(ccx: &CrateCtxt, id: ast::NodeId, span: Span) {
+    check_representable(ccx.tcx, span, id);
+}
+
 pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) {
     debug!("check_item_type(it.id={}, it.name={})",
            it.id,
@@ -763,7 +765,7 @@ pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) {
         check_struct(ccx, it.id, it.span);
       }
       hir::ItemUnion(..) => {
-        unimplemented_unions!();
+        check_union(ccx, it.id, it.span);
       }
       hir::ItemTy(_, ref generics) => {
         let pty_ty = ccx.tcx.node_id_to_type(it.id);
@@ -1174,10 +1176,10 @@ fn check_const<'a, 'tcx>(ccx: &CrateCtxt<'a,'tcx>,
 /// Checks whether a type can be represented in memory. In particular, it
 /// identifies types that contain themselves without indirection through a
 /// pointer, which would mean their size is unbounded.
-pub fn check_representable<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                     sp: Span,
-                                     item_id: ast::NodeId,
-                                     _designation: &str) -> bool {
+fn check_representable<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                                 sp: Span,
+                                 item_id: ast::NodeId)
+                                 -> bool {
     let rty = tcx.node_id_to_type(item_id);
 
     // Check that it is possible to represent this type. This call identifies
@@ -1277,7 +1279,7 @@ pub fn check_enum_variants<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
         disr_vals.push(current_disr_val);
     }
 
-    check_representable(ccx.tcx, sp, id, "enum");
+    check_representable(ccx.tcx, sp, id);
 }
 
 impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> {
diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs
index 19bee13b6f60..7cc3be0a8906 100644
--- a/src/librustc_typeck/check/wfcheck.rs
+++ b/src/librustc_typeck/check/wfcheck.rs
@@ -136,17 +136,21 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
                 self.check_item_type(item);
             }
             hir::ItemStruct(ref struct_def, ref ast_generics) => {
-                self.check_type_defn(item, |fcx| {
+                self.check_type_defn(item, false, |fcx| {
                     vec![fcx.struct_variant(struct_def)]
                 });
 
                 self.check_variances_for_type_defn(item, ast_generics);
             }
-            hir::ItemUnion(..) => {
-                unimplemented_unions!();
+            hir::ItemUnion(ref struct_def, ref ast_generics) => {
+                self.check_type_defn(item, true, |fcx| {
+                    vec![fcx.struct_variant(struct_def)]
+                });
+
+                self.check_variances_for_type_defn(item, ast_generics);
             }
             hir::ItemEnum(ref enum_def, ref ast_generics) => {
-                self.check_type_defn(item, |fcx| {
+                self.check_type_defn(item, false, |fcx| {
                     fcx.enum_variants(enum_def)
                 });
 
@@ -219,24 +223,22 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
     }
 
     /// In a type definition, we check that to ensure that the types of the fields are well-formed.
-    fn check_type_defn(&mut self, item: &hir::Item, mut lookup_fields: F) where
-        F: for<'fcx, 'tcx> FnMut(&FnCtxt<'fcx, 'gcx, 'tcx>)
-                                 -> Vec>
+    fn check_type_defn(&mut self, item: &hir::Item, all_sized: bool, mut lookup_fields: F)
+        where F: for<'fcx, 'tcx> FnMut(&FnCtxt<'fcx, 'gcx, 'tcx>) -> Vec>
     {
         self.for_item(item).with_fcx(|fcx, this| {
             let variants = lookup_fields(fcx);
 
             for variant in &variants {
                 // For DST, all intermediate types must be sized.
-                if let Some((_, fields)) = variant.fields.split_last() {
-                    for field in fields {
-                        fcx.register_builtin_bound(
-                            field.ty,
-                            ty::BoundSized,
-                            traits::ObligationCause::new(field.span,
-                                                         fcx.body_id,
-                                                         traits::FieldSized));
-                    }
+                let unsized_len = if all_sized || variant.fields.is_empty() { 0 } else { 1 };
+                for field in &variant.fields[..variant.fields.len() - unsized_len] {
+                    fcx.register_builtin_bound(
+                        field.ty,
+                        ty::BoundSized,
+                        traits::ObligationCause::new(field.span,
+                                                     fcx.body_id,
+                                                     traits::FieldSized));
                 }
 
                 // All field types must be well-formed.
diff --git a/src/test/compile-fail/attr-usage-repr.rs b/src/test/compile-fail/attr-usage-repr.rs
index 9bad6a8389a5..b07d3e2f9067 100644
--- a/src/test/compile-fail/attr-usage-repr.rs
+++ b/src/test/compile-fail/attr-usage-repr.rs
@@ -11,7 +11,7 @@
 #![allow(dead_code)]
 #![feature(repr_simd)]
 
-#[repr(C)] //~ ERROR: attribute should be applied to struct or enum
+#[repr(C)] //~ ERROR: attribute should be applied to struct, enum or union
 fn f() {}
 
 #[repr(C)]
diff --git a/src/test/compile-fail/issue-31769.rs b/src/test/compile-fail/issue-31769.rs
index 4b5df7ea53ca..7f73d9076ec9 100644
--- a/src/test/compile-fail/issue-31769.rs
+++ b/src/test/compile-fail/issue-31769.rs
@@ -10,5 +10,5 @@
 
 fn main() {
     #[inline] struct Foo;  //~ ERROR attribute should be applied to function
-    #[repr(C)] fn foo() {} //~ ERROR attribute should be applied to struct or enum
+    #[repr(C)] fn foo() {} //~ ERROR attribute should be applied to struct, enum or union
 }
diff --git a/src/test/compile-fail/union-nonrepresentable.rs b/src/test/compile-fail/union-nonrepresentable.rs
new file mode 100644
index 000000000000..cb4683c2a0e1
--- /dev/null
+++ b/src/test/compile-fail/union-nonrepresentable.rs
@@ -0,0 +1,18 @@
+// 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.
+
+#![feature(untagged_unions)]
+
+union U { //~ ERROR recursive type `U` has infinite size
+    a: u8,
+    b: U,
+}
+
+fn main() {}
diff --git a/src/test/compile-fail/union-unsized.rs b/src/test/compile-fail/union-unsized.rs
new file mode 100644
index 000000000000..381122406d71
--- /dev/null
+++ b/src/test/compile-fail/union-unsized.rs
@@ -0,0 +1,17 @@
+// 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.
+
+#![feature(untagged_unions)]
+
+union U {
+    a: str, //~ ERROR the trait bound `str: std::marker::Sized` is not satisfied
+}
+
+fn main() {}
diff --git a/src/test/run-pass/auxiliary/union.rs b/src/test/run-pass/auxiliary/union.rs
new file mode 100644
index 000000000000..dc0ca7c81c00
--- /dev/null
+++ b/src/test/run-pass/auxiliary/union.rs
@@ -0,0 +1,16 @@
+// 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.
+
+#![feature(untagged_unions)]
+
+pub union U {
+    pub a: u8,
+    b: u16,
+}
diff --git a/src/test/run-pass/union-xcrate.rs b/src/test/run-pass/union-xcrate.rs
new file mode 100644
index 000000000000..2a76c96ef25f
--- /dev/null
+++ b/src/test/run-pass/union-xcrate.rs
@@ -0,0 +1,21 @@
+// 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.
+
+// aux-build:union.rs
+
+// #![feature(untagged_unions)]
+
+extern crate union;
+
+type A = union::U;
+
+fn main() {
+    assert_eq!(std::mem::size_of::(), 8);
+}

From c2ca1530dbcde745175569b9f5434fa6643e5766 Mon Sep 17 00:00:00 2001
From: Vadim Petrochenkov 
Date: Thu, 18 Aug 2016 15:43:24 +0300
Subject: [PATCH 132/443] Fix rebase + address comments

---
 src/librustc/middle/dead.rs                 | 2 +-
 src/librustc/middle/stability.rs            | 4 ++--
 src/librustc/ty/sty.rs                      | 2 +-
 src/librustc_lint/builtin.rs                | 3 +--
 src/librustc_typeck/check/method/suggest.rs | 7 ++++---
 src/librustc_typeck/collect.rs              | 5 +++++
 src/librustdoc/clean/inline.rs              | 2 +-
 src/librustdoc/html/item_type.rs            | 1 +
 src/librustdoc/html/render.rs               | 6 ++----
 9 files changed, 18 insertions(+), 14 deletions(-)

diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs
index 9a63ad4b9859..0b1d9e8d8f69 100644
--- a/src/librustc/middle/dead.rs
+++ b/src/librustc/middle/dead.rs
@@ -136,7 +136,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
             ty::TyStruct(def, _) | ty::TyUnion(def, _) => {
                 self.insert_def_id(def.struct_variant().field_named(name).did);
             }
-            _ => span_bug!(lhs.span, "named field access on non-struct"),
+            _ => span_bug!(lhs.span, "named field access on non-struct/union"),
         }
     }
 
diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs
index e6979c254533..aea1ee8d8240 100644
--- a/src/librustc/middle/stability.rs
+++ b/src/librustc/middle/stability.rs
@@ -565,7 +565,7 @@ pub fn check_expr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, e: &hir::Expr,
                     def.struct_variant().field_named(field.node).did
                 }
                 _ => span_bug!(e.span,
-                               "stability::check_expr: named field access on non-struct")
+                               "stability::check_expr: named field access on non-struct/union")
             }
         }
         hir::ExprTupField(ref base_e, ref field) => {
@@ -601,7 +601,7 @@ pub fn check_expr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, e: &hir::Expr,
                 _ => {
                     span_bug!(e.span,
                               "stability::check_expr: struct construction \
-                               of non-struct, type {:?}",
+                               of non-struct/union, type {:?}",
                               type_);
                 }
             }
diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs
index 165f86fbef53..d45fde925c51 100644
--- a/src/librustc/ty/sty.rs
+++ b/src/librustc/ty/sty.rs
@@ -112,7 +112,7 @@ pub enum TypeVariants<'tcx> {
     /// That is, even after substitution it is possible that there are type
     /// variables. This happens when the `TyEnum` corresponds to an enum
     /// definition and not a concrete use of it. This is true for `TyStruct`
-    /// as well.
+    /// and `TyUnion` as well.
     TyEnum(AdtDef<'tcx>, &'tcx Substs<'tcx>),
 
     /// A structure type, defined with `struct`.
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index 571d1222baaa..b55cad58e2fe 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -475,8 +475,7 @@ impl LateLintPass for MissingCopyImplementations {
                     return;
                 }
                 let def = cx.tcx.lookup_adt_def(cx.tcx.map.local_def_id(item.id));
-                (def, cx.tcx.mk_union(def,
-                                      cx.tcx.mk_substs(Substs::empty())))
+                (def, cx.tcx.mk_union(def, Substs::empty(cx.tcx)))
             }
             hir::ItemEnum(_, ref ast_generics) => {
                 if ast_generics.is_parameterized() {
diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs
index 6d8a73b8a6aa..e4ea9bb407d9 100644
--- a/src/librustc_typeck/check/method/suggest.rs
+++ b/src/librustc_typeck/check/method/suggest.rs
@@ -166,7 +166,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     for (ty, _) in self.autoderef(span, rcvr_ty) {
                         match ty.sty {
                             ty::TyStruct(def, substs) | ty::TyUnion(def, substs) => {
-                                if let Some(field) = def.struct_variant().find_field_named(item_name) {
+                                if let Some(field) = def.struct_variant().
+                                                         find_field_named(item_name) {
                                     let snippet = tcx.sess.codemap().span_to_snippet(expr.span);
                                     let expr_string = match snippet {
                                         Ok(expr_string) => expr_string,
@@ -179,8 +180,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
                                     if self.is_fn_ty(&field_ty, span) {
                                         err.span_note(span, &format!(
-                                            "use `({0}.{1})(...)` if you meant to call the function \
-                                             stored in the `{1}` field",
+                                            "use `({0}.{1})(...)` if you meant to call the \
+                                             function stored in the `{1}` field",
                                             expr_string, item_name));
                                     } else {
                                         err.span_note(span, &format!(
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 1d260b9dbb29..a100c919d6f4 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -1587,6 +1587,11 @@ fn type_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                         let substs = mk_item_substs(&ccx.icx(generics), item.span, def_id);
                         ccx.tcx.mk_struct(def, substs)
                     }
+                    ItemUnion(ref un, ref generics) => {
+                        let def = convert_union_def(ccx, item, un);
+                        let substs = mk_item_substs(&ccx.icx(generics), item.span, def_id);
+                        ccx.tcx.mk_union(def, substs)
+                    }
                     ItemDefaultImpl(..) |
                     ItemTrait(..) |
                     ItemImpl(..) |
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index 4250979a2403..b7e371e23f32 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -227,7 +227,7 @@ fn build_union<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
     clean::Union {
         struct_type: doctree::Plain,
-        generics: (&t.generics, &predicates, subst::TypeSpace).clean(cx),
+        generics: (t.generics, &predicates).clean(cx),
         fields: variant.fields.clean(cx),
         fields_stripped: false,
     }
diff --git a/src/librustdoc/html/item_type.rs b/src/librustdoc/html/item_type.rs
index 9ce3c79e2f19..b93dc17dbdd7 100644
--- a/src/librustdoc/html/item_type.rs
+++ b/src/librustdoc/html/item_type.rs
@@ -133,6 +133,7 @@ impl ItemType {
     pub fn name_space(&self) -> NameSpace {
         match *self {
             ItemType::Struct |
+            ItemType::Union |
             ItemType::Enum |
             ItemType::Module |
             ItemType::Typedef |
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index c1bb9d9f633b..6f66ce88df7a 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -2565,10 +2565,8 @@ fn render_union(w: &mut fmt::Formatter, it: &clean::Item,
            if structhead {"union "} else {""},
            it.name.as_ref().unwrap())?;
     if let Some(g) = g {
-        write!(w, "{}", g)?
-    }
-    if let Some(g) = g {
-        write!(w, "{}", WhereClause(g))?
+        write!(w, "{}", g)?;
+        write!(w, "{}", WhereClause(g))?;
     }
 
     write!(w, " {{\n{}", tab)?;

From 957971b63abbc816aebc6654dc68cf9ff15837d7 Mon Sep 17 00:00:00 2001
From: Vadim Petrochenkov 
Date: Thu, 18 Aug 2016 15:44:00 +0300
Subject: [PATCH 133/443] Implement layout calculation and add more trans stubs

---
 src/librustc/ty/layout.rs                | 72 ++++++++++++++++--
 src/librustc_mir/hair/cx/expr.rs         |  5 +-
 src/librustc_trans/adt.rs                | 96 ++++++++++++++++++++++--
 src/librustc_trans/debuginfo/metadata.rs |  5 +-
 src/test/run-pass/union-basic.rs         | 47 ++++++++++++
 5 files changed, 205 insertions(+), 20 deletions(-)
 create mode 100644 src/test/run-pass/union-basic.rs

diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs
index ac5e3c6fa700..9270057b5441 100644
--- a/src/librustc/ty/layout.rs
+++ b/src/librustc/ty/layout.rs
@@ -488,7 +488,7 @@ impl<'a, 'gcx, 'tcx> Struct {
 
         for field in fields {
             if !self.sized {
-                bug!("Struct::compute: field #{} of `{}` comes after unsized field",
+                bug!("Struct::extend: field #{} of `{}` comes after unsized field",
                      self.offset_after_field.len(), scapegoat);
             }
 
@@ -623,6 +623,54 @@ impl<'a, 'gcx, 'tcx> Struct {
     }
 }
 
+/// An untagged union.
+#[derive(PartialEq, Eq, Hash, Debug)]
+pub struct Union {
+    pub align: Align,
+
+    pub min_size: Size,
+
+    /// If true, no alignment padding is used.
+    pub packed: bool,
+}
+
+impl<'a, 'gcx, 'tcx> Union {
+    pub fn new(dl: &TargetDataLayout, packed: bool) -> Union {
+        Union {
+            align: if packed { dl.i8_align } else { dl.aggregate_align },
+            min_size: Size::from_bytes(0),
+            packed: packed,
+        }
+    }
+
+    /// Extend the Struct with more fields.
+    pub fn extend(&mut self, dl: &TargetDataLayout,
+                     fields: I,
+                     scapegoat: Ty<'gcx>)
+                     -> Result<(), LayoutError<'gcx>>
+    where I: Iterator>> {
+        for (index, field) in fields.enumerate() {
+            let field = field?;
+            if field.is_unsized() {
+                bug!("Union::extend: field #{} of `{}` is unsized",
+                     index, scapegoat);
+            }
+
+            if !self.packed {
+                self.align = self.align.max(field.align(dl));
+            }
+            self.min_size = cmp::max(self.min_size, field.size(dl));
+        }
+
+        Ok(())
+    }
+
+    /// Get the size with trailing aligment padding.
+    pub fn stride(&self) -> Size {
+        self.min_size.abi_align(self.align)
+    }
+}
+
 /// The first half of a fat pointer.
 /// - For a trait object, this is the address of the box.
 /// - For a slice, this is the base address.
@@ -690,6 +738,11 @@ pub enum Layout {
         non_zero: bool
     },
 
+    /// Untagged unions.
+    UntaggedUnion {
+        variants: Union,
+    },
+
     /// General-case enums: for each case there is a struct, and they
     /// all start with a field for the discriminant.
     General {
@@ -896,8 +949,14 @@ impl<'a, 'gcx, 'tcx> Layout {
                     non_zero: Some(def.did) == tcx.lang_items.non_zero()
                 }
             }
-            ty::TyUnion(..) => {
-                unimplemented_unions!();
+            ty::TyUnion(def, substs) => {
+                let fields = def.struct_variant().fields.iter().map(|field| {
+                    field.ty(tcx, substs).layout(infcx)
+                });
+                let packed = tcx.lookup_packed(def.did);
+                let mut un = Union::new(dl, packed);
+                un.extend(dl, fields, ty)?;
+                UntaggedUnion { variants: un }
             }
             ty::TyEnum(def, substs) => {
                 let hint = *tcx.lookup_repr_hints(def.did).get(0)
@@ -1118,7 +1177,7 @@ impl<'a, 'gcx, 'tcx> Layout {
     pub fn is_unsized(&self) -> bool {
         match *self {
             Scalar {..} | Vector {..} | FatPointer {..} |
-            CEnum {..} | General {..} |
+            CEnum {..} | UntaggedUnion {..} | General {..} |
             RawNullablePointer {..} |
             StructWrappedNullablePointer {..} => false,
 
@@ -1152,6 +1211,7 @@ impl<'a, 'gcx, 'tcx> Layout {
 
             CEnum { discr, .. } => Int(discr).size(dl),
             Array { size, .. } | General { size, .. } => size,
+            UntaggedUnion { ref variants } => variants.stride(),
 
             Univariant { ref variant, .. } |
             StructWrappedNullablePointer { nonnull: ref variant, .. } => {
@@ -1191,6 +1251,7 @@ impl<'a, 'gcx, 'tcx> Layout {
 
             CEnum { discr, .. } => Int(discr).align(dl),
             Array { align, .. } | General { align, .. } => align,
+            UntaggedUnion { ref variants } => variants.align,
 
             Univariant { ref variant, .. } |
             StructWrappedNullablePointer { nonnull: ref variant, .. } => {
@@ -1256,9 +1317,6 @@ impl<'a, 'gcx, 'tcx> SizeSkeleton<'gcx> {
                 }
             }
 
-            ty::TyUnion(..) => {
-                unimplemented_unions!();
-            }
             ty::TyStruct(def, substs) | ty::TyEnum(def, substs) => {
                 // Only newtypes and enums w/ nullable pointer optimization.
                 if def.variants.is_empty() || def.variants.len() > 2 {
diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs
index 0469d44de4ba..c8f660a2d9c7 100644
--- a/src/librustc_mir/hair/cx/expr.rs
+++ b/src/librustc_mir/hair/cx/expr.rs
@@ -459,7 +459,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
 
         hir::ExprStruct(_, ref fields, ref base) => {
             match expr_ty.sty {
-                ty::TyStruct(adt, substs) => {
+                ty::TyStruct(adt, substs) | ty::TyUnion(adt, substs) => {
                     let field_refs = field_refs(&adt.variants[0], fields);
                     ExprKind::Adt {
                         adt_def: adt,
@@ -477,9 +477,6 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                         })
                     }
                 }
-                ty::TyUnion(..) => {
-                    unimplemented_unions!();
-                }
                 ty::TyEnum(adt, substs) => {
                     match cx.tcx.expect_def(expr.id) {
                         Def::Variant(enum_id, variant_id) => {
diff --git a/src/librustc_trans/adt.rs b/src/librustc_trans/adt.rs
index 069eef7895c8..abbb9a5d4dbe 100644
--- a/src/librustc_trans/adt.rs
+++ b/src/librustc_trans/adt.rs
@@ -79,6 +79,8 @@ pub enum Repr<'tcx> {
     CEnum(IntType, Disr, Disr), // discriminant range (signedness based on the IntType)
     /// Single-case variants, and structs/tuples/records.
     Univariant(Struct<'tcx>),
+    /// Untagged unions.
+    UntaggedUnion(Union<'tcx>),
     /// General-case enums: for each case there is a struct, and they
     /// all start with a field for the discriminant.
     General(IntType, Vec>),
@@ -121,6 +123,15 @@ pub struct Struct<'tcx> {
     pub fields: Vec>,
 }
 
+/// For untagged unions.
+#[derive(Eq, PartialEq, Debug)]
+pub struct Union<'tcx> {
+    pub min_size: u64,
+    pub align: u32,
+    pub packed: bool,
+    pub fields: Vec>,
+}
+
 #[derive(Copy, Clone)]
 pub struct MaybeSizedValue {
     pub value: ValueRef,
@@ -176,8 +187,12 @@ fn represent_type_uncached<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
 
             Univariant(mk_struct(cx, &ftys[..], packed, t))
         }
-        ty::TyUnion(..) => {
-            unimplemented_unions!();
+        ty::TyUnion(def, substs) => {
+            let ftys = def.struct_variant().fields.iter().map(|field| {
+                monomorphize::field_ty(cx.tcx(), substs, field)
+            }).collect::>();
+            let packed = cx.tcx().lookup_packed(def.did);
+            UntaggedUnion(mk_union(cx, &ftys[..], packed, t))
         }
         ty::TyClosure(_, ref substs) => {
             Univariant(mk_struct(cx, &substs.upvar_tys, false, t))
@@ -482,6 +497,31 @@ fn mk_struct<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
     }
 }
 
+fn mk_union<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
+                      tys: &[Ty<'tcx>], packed: bool,
+                      _scapegoat: Ty<'tcx>)
+                      -> Union<'tcx> {
+    let mut min_size = 0;
+    let mut align = 0;
+    for llty in tys.iter().map(|&ty| type_of::sizing_type_of(cx, ty)) {
+        let field_size = machine::llsize_of_alloc(cx, llty);
+        if min_size < field_size {
+            min_size = field_size;
+        }
+        let field_align = machine::llalign_of_min(cx, llty);
+        if align < field_align {
+            align = field_align;
+        }
+    }
+
+    Union {
+        min_size: min_size,
+        align: align,
+        packed: packed,
+        fields: tys.to_vec(),
+    }
+}
+
 #[derive(Debug)]
 struct IntBounds {
     slo: i64,
@@ -646,7 +686,7 @@ pub fn incomplete_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
 pub fn finish_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                                 r: &Repr<'tcx>, llty: &mut Type) {
     match *r {
-        CEnum(..) | General(..) | RawNullablePointer { .. } => { }
+        CEnum(..) | General(..) | UntaggedUnion(..) | RawNullablePointer { .. } => { }
         Univariant(ref st) | StructWrappedNullablePointer { nonnull: ref st, .. } =>
             llty.set_struct_body(&struct_llfields(cx, st, false, false),
                                  st.packed)
@@ -690,6 +730,34 @@ fn generic_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                 }
             }
         }
+        UntaggedUnion(ref un) => {
+            // Use alignment-sized ints to fill all the union storage.
+            let (size, align) = (roundup(un.min_size, un.align), un.align);
+
+            let align_s = align as u64;
+            assert_eq!(size % align_s, 0); // Ensure division in align_units comes out evenly
+            let align_units = size / align_s;
+            let fill_ty = match align_s {
+                1 => Type::array(&Type::i8(cx), align_units),
+                2 => Type::array(&Type::i16(cx), align_units),
+                4 => Type::array(&Type::i32(cx), align_units),
+                8 if machine::llalign_of_min(cx, Type::i64(cx)) == 8 =>
+                                 Type::array(&Type::i64(cx), align_units),
+                a if a.count_ones() == 1 => Type::array(&Type::vector(&Type::i32(cx), a / 4),
+                                                              align_units),
+                _ => bug!("unsupported union alignment: {}", align)
+            };
+            match name {
+                None => {
+                    TypeContext::direct(Type::struct_(cx, &[fill_ty], un.packed))
+                }
+                Some(name) => {
+                    let mut llty = Type::named_struct(cx, name);
+                    llty.set_struct_body(&[fill_ty], un.packed);
+                    TypeContext::direct(llty)
+                }
+            }
+        }
         General(ity, ref sts) => {
             // We need a representation that has:
             // * The alignment of the most-aligned field
@@ -762,7 +830,7 @@ pub fn trans_switch<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
         RawNullablePointer { .. } | StructWrappedNullablePointer { .. } => {
             (BranchKind::Switch, Some(trans_get_discr(bcx, r, scrutinee, None, range_assert)))
         }
-        Univariant(..) => {
+        Univariant(..) | UntaggedUnion(..) => {
             // N.B.: Univariant means <= 1 enum variants (*not* == 1 variants).
             (BranchKind::Single, None)
         }
@@ -773,7 +841,7 @@ pub fn is_discr_signed<'tcx>(r: &Repr<'tcx>) -> bool {
     match *r {
         CEnum(ity, _, _) => ity.is_signed(),
         General(ity, _) => ity.is_signed(),
-        Univariant(..) => false,
+        Univariant(..) | UntaggedUnion(..) => false,
         RawNullablePointer { .. } => false,
         StructWrappedNullablePointer { .. } => false,
     }
@@ -794,7 +862,7 @@ pub fn trans_get_discr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr<'tcx>,
             load_discr(bcx, ity, ptr, Disr(0), Disr(cases.len() as u64 - 1),
                        range_assert)
         }
-        Univariant(..) => C_u8(bcx.ccx(), 0),
+        Univariant(..) | UntaggedUnion(..) => C_u8(bcx.ccx(), 0),
         RawNullablePointer { nndiscr, nnty, .. } =>  {
             let cmp = if nndiscr == Disr(0) { IntEQ } else { IntNE };
             let llptrty = type_of::sizing_type_of(bcx.ccx(), nnty);
@@ -856,8 +924,8 @@ pub fn trans_case<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr, discr: Disr)
         General(ity, _) => {
             C_integral(ll_inttype(bcx.ccx(), ity), discr.0, true)
         }
-        Univariant(..) => {
-            bug!("no cases for univariants or structs")
+        Univariant(..) | UntaggedUnion(..) => {
+            bug!("no cases for univariants, structs or unions")
         }
         RawNullablePointer { .. } |
         StructWrappedNullablePointer { .. } => {
@@ -884,6 +952,9 @@ pub fn trans_set_discr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr<'tcx>,
         Univariant(_) => {
             assert_eq!(discr, Disr(0));
         }
+        UntaggedUnion(..) => {
+            assert_eq!(discr, Disr(0));
+        }
         RawNullablePointer { nndiscr, nnty, ..} => {
             if discr != nndiscr {
                 let llptrty = type_of::sizing_type_of(bcx.ccx(), nnty);
@@ -939,6 +1010,11 @@ pub fn trans_field_ptr_builder<'blk, 'tcx>(bcx: &BlockAndBuilder<'blk, 'tcx>,
         General(_, ref cases) => {
             struct_field_ptr(bcx, &cases[discr.0 as usize], val, ix + 1, true)
         }
+        UntaggedUnion(ref un) => {
+            let ty = type_of::in_memory_type_of(bcx.ccx(), un.fields[ix]);
+            if bcx.is_unreachable() { return C_undef(ty.ptr_to()); }
+            bcx.pointercast(val.value, ty.ptr_to())
+        }
         RawNullablePointer { nndiscr, ref nullfields, .. } |
         StructWrappedNullablePointer { nndiscr, ref nullfields, .. } if discr != nndiscr => {
             // The unit-like case might have a nonzero number of unit-like fields.
@@ -1100,6 +1176,9 @@ pub fn trans_const<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, r: &Repr<'tcx>, discr
             contents.extend_from_slice(&[padding(ccx, max_sz - case.size)]);
             C_struct(ccx, &contents[..], false)
         }
+        UntaggedUnion(..) => {
+            unimplemented_unions!();
+        }
         Univariant(ref st) => {
             assert_eq!(discr, Disr(0));
             let contents = build_const_struct(ccx, st, vals);
@@ -1211,6 +1290,7 @@ pub fn const_get_field(r: &Repr, val: ValueRef, _discr: Disr,
     match *r {
         CEnum(..) => bug!("element access in C-like enum const"),
         Univariant(..) => const_struct_field(val, ix),
+        UntaggedUnion(..) => const_struct_field(val, 0),
         General(..) => const_struct_field(val, ix + 1),
         RawNullablePointer { .. } => {
             assert_eq!(ix, 0);
diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs
index f30880ac9beb..bd67a215d65e 100644
--- a/src/librustc_trans/debuginfo/metadata.rs
+++ b/src/librustc_trans/debuginfo/metadata.rs
@@ -1302,6 +1302,9 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> {
                     ]
                 }
             }
+            adt::UntaggedUnion(..) => {
+                unimplemented_unions!();
+            }
             adt::RawNullablePointer { nndiscr: non_null_variant_index, nnty, .. } => {
                 // As far as debuginfo is concerned, the pointer this enum
                 // represents is still wrapped in a struct. This is to make the
@@ -1616,7 +1619,7 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
         },
         adt::RawNullablePointer { .. }           |
         adt::StructWrappedNullablePointer { .. } |
-        adt::Univariant(..)                      => None,
+        adt::Univariant(..) | adt::UntaggedUnion(..) => None,
         adt::General(inttype, _) => Some(discriminant_type_metadata(inttype)),
     };
 
diff --git a/src/test/run-pass/union-basic.rs b/src/test/run-pass/union-basic.rs
new file mode 100644
index 000000000000..474c8b4b1810
--- /dev/null
+++ b/src/test/run-pass/union-basic.rs
@@ -0,0 +1,47 @@
+// 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.
+
+#![feature(untagged_unions)]
+
+use std::mem::{size_of, align_of, zeroed};
+
+union U {
+    a: u8,
+}
+
+union U64 {
+    a: u64,
+}
+
+union W {
+    a: u8,
+    b: u64,
+}
+
+fn main() {
+    assert_eq!(size_of::(), 1);
+    assert_eq!(size_of::(), 8);
+    assert_eq!(size_of::(), 8);
+    assert_eq!(align_of::(), 1);
+    assert_eq!(align_of::(), align_of::());
+    assert_eq!(align_of::(), align_of::());
+
+    let u = U { a: 10 };
+    assert_eq!(u.a, 10);
+    let U { a } = u;
+    assert_eq!(a, 10);
+
+    let mut w: W = unsafe { zeroed() };
+    assert_eq!(w.a, 0);
+    assert_eq!(w.b, 0);
+    // w.a = 1;
+    // assert_eq!(w.a, 0);
+    // assert_eq!(w.b, 0);
+}

From f3b41c18a8dfbcfec4b2a9e8d9e6a921189e3eea Mon Sep 17 00:00:00 2001
From: Vadim Petrochenkov 
Date: Thu, 18 Aug 2016 18:31:47 +0300
Subject: [PATCH 134/443] Check fields in union patters/expressions

Make parsing of union items backward compatible
Add some tests
---
 src/librustc_typeck/check/_match.rs           | 49 ++++++++-------
 src/librustc_typeck/check/mod.rs              | 31 +++++-----
 src/libsyntax/parse/parser.rs                 |  4 +-
 src/test/compile-fail/issue-17800.rs          |  2 +-
 src/test/compile-fail/issue-19922.rs          |  2 +-
 src/test/compile-fail/issue-4736.rs           |  2 +-
 src/test/compile-fail/numeric-fields.rs       |  2 +-
 .../struct-fields-hints-no-dupe.rs            |  2 +-
 src/test/compile-fail/struct-fields-hints.rs  |  2 +-
 .../compile-fail/struct-fields-too-many.rs    |  2 +-
 .../compile-fail/suggest-private-fields.rs    |  8 +--
 src/test/compile-fail/union-empty.rs          | 15 +++++
 src/test/compile-fail/union-fields.rs         | 34 ++++++++++
 src/test/run-pass/union-backcomp.rs           | 23 +++++++
 src/test/run-pass/union-basic.rs              |  8 +++
 src/test/run-pass/union-drop.rs               | 26 ++++++++
 src/test/run-pass/union-pat-refutability.rs   | 62 +++++++++++++++++++
 17 files changed, 227 insertions(+), 47 deletions(-)
 create mode 100644 src/test/compile-fail/union-empty.rs
 create mode 100644 src/test/compile-fail/union-fields.rs
 create mode 100644 src/test/run-pass/union-backcomp.rs
 create mode 100644 src/test/run-pass/union-drop.rs
 create mode 100644 src/test/run-pass/union-pat-refutability.rs

diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index 5fdfa19190bd..5c19fa2a66cf 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -11,7 +11,6 @@
 use hir::def::Def;
 use rustc::infer::{self, InferOk, TypeOrigin};
 use hir::pat_util::EnumerateAndAdjustIterator;
-use rustc::ty::subst::Substs;
 use rustc::ty::{self, Ty, TypeFoldable, LvaluePreference, VariantKind};
 use check::{FnCtxt, Expectation};
 use lint;
@@ -509,11 +508,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         self.demand_eqtype(pat.span, expected, pat_ty);
 
         // Type check subpatterns.
-        let substs = match pat_ty.sty {
-            ty::TyStruct(_, substs) | ty::TyUnion(_, substs) | ty::TyEnum(_, substs) => substs,
-            _ => span_bug!(pat.span, "struct variant is not an ADT")
-        };
-        self.check_struct_pat_fields(pat.span, fields, variant, substs, etc);
+        self.check_struct_pat_fields(pat_ty, pat.span, variant, fields, etc);
     }
 
     fn check_pat_path(&self,
@@ -658,19 +653,21 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         }
     }
 
-    /// `path` is the AST path item naming the type of this struct.
-    /// `fields` is the field patterns of the struct pattern.
-    /// `struct_fields` describes the type of each field of the struct.
-    /// `struct_id` is the ID of the struct.
-    /// `etc` is true if the pattern said '...' and false otherwise.
-    pub fn check_struct_pat_fields(&self,
-                                   span: Span,
-                                   fields: &'gcx [Spanned],
-                                   variant: ty::VariantDef<'tcx>,
-                                   substs: &Substs<'tcx>,
-                                   etc: bool) {
+    fn check_struct_pat_fields(&self,
+                               adt_ty: Ty<'tcx>,
+                               span: Span,
+                               variant: ty::VariantDef<'tcx>,
+                               fields: &'gcx [Spanned],
+                               etc: bool) {
         let tcx = self.tcx;
 
+        let (substs, kind_name) = match adt_ty.sty {
+            ty::TyEnum(_, substs) => (substs, "variant"),
+            ty::TyStruct(_, substs) => (substs, "struct"),
+            ty::TyUnion(_, substs) => (substs, "union"),
+            _ => span_bug!(span, "struct pattern is not an ADT")
+        };
+
         // Index the struct fields' types.
         let field_map = variant.fields
             .iter()
@@ -700,11 +697,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                         .map(|f| self.field_ty(span, f, substs))
                         .unwrap_or_else(|| {
                             struct_span_err!(tcx.sess, span, E0026,
-                                             "struct `{}` does not have a field named `{}`",
+                                             "{} `{}` does not have a field named `{}`",
+                                             kind_name,
                                              tcx.item_path_str(variant.did),
                                              field.name)
                                 .span_label(span,
-                                            &format!("struct `{}` does not have field `{}`",
+                                            &format!("{} `{}` does not have field `{}`",
+                                                     kind_name,
                                                      tcx.item_path_str(variant.did),
                                                      field.name))
                                 .emit();
@@ -717,8 +716,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             self.check_pat(&field.pat, field_ty);
         }
 
-        // Report an error if not all the fields were specified.
-        if !etc {
+        // Report an error if incorrect number of the fields were specified.
+        if kind_name == "union" {
+            if fields.len() > 1 {
+                tcx.sess.span_err(span, "union patterns can have at most one field");
+            }
+            if fields.is_empty() && !etc {
+                tcx.sess.span_err(span, "union patterns without `..` \
+                                         should have at least one field");
+            }
+        } else if !etc {
             for field in variant.fields
                 .iter()
                 .filter(|field| !used_fields.contains_key(&field.name)) {
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index e2954cecc9c4..f8ee9efee7a5 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -3109,17 +3109,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                             ty: Ty<'tcx>,
                             variant: ty::VariantDef<'tcx>,
                             field: &hir::Field,
-                            skip_fields: &[hir::Field]) {
+                            skip_fields: &[hir::Field],
+                            kind_name: &str) {
         let mut err = self.type_error_struct_with_diag(
             field.name.span,
             |actual| if let ty::TyEnum(..) = ty.sty {
                 struct_span_err!(self.tcx.sess, field.name.span, E0559,
-                                 "struct variant `{}::{}` has no field named `{}`",
-                                 actual, variant.name.as_str(), field.name.node)
+                                 "{} `{}::{}` has no field named `{}`",
+                                 kind_name, actual, variant.name.as_str(), field.name.node)
             } else {
                 struct_span_err!(self.tcx.sess, field.name.span, E0560,
-                                 "structure `{}` has no field named `{}`",
-                                 actual, field.name.node)
+                                 "{} `{}` has no field named `{}`",
+                                 kind_name, actual, field.name.node)
             },
             ty);
         // prevent all specified fields from being suggested
@@ -3135,8 +3136,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                 ast_fields: &'gcx [hir::Field],
                                 check_completeness: bool) {
         let tcx = self.tcx;
-        let substs = match adt_ty.sty {
-            ty::TyStruct(_, substs) | ty::TyUnion(_, substs) | ty::TyEnum(_, substs) => substs,
+        let (substs, kind_name) = match adt_ty.sty {
+            ty::TyEnum(_, substs) => (substs, "variant"),
+            ty::TyStruct(_, substs) => (substs, "struct"),
+            ty::TyUnion(_, substs) => (substs, "union"),
             _ => span_bug!(span, "non-ADT passed to check_expr_struct_fields")
         };
 
@@ -3175,7 +3178,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
                     err.emit();
                 } else {
-                    self.report_unknown_field(adt_ty, variant, field, ast_fields);
+                    self.report_unknown_field(adt_ty, variant, field, ast_fields, kind_name);
                 }
             }
 
@@ -3184,11 +3187,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             self.check_expr_coercable_to_type(&field.expr, expected_field_type);
         }
 
-            // Make sure the programmer specified all the fields.
-        if check_completeness &&
-            !error_happened &&
-            !remaining_fields.is_empty()
-        {
+        // Make sure the programmer specified correct number of fields.
+        if kind_name == "union" {
+            if ast_fields.len() != 1 {
+                tcx.sess.span_err(span, "union expressions should have exactly one field");
+            }
+        } else if check_completeness && !error_happened && !remaining_fields.is_empty() {
             span_err!(tcx.sess, span, E0063,
                       "missing field{} {} in initializer of `{}`",
                       if remaining_fields.len() == 1 {""} else {"s"},
@@ -3198,7 +3202,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                       .join(", "),
                       adt_ty);
         }
-
     }
 
     fn check_struct_fields_on_error(&self,
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 290a59cf1e59..ec9dc1bae5ad 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -5957,8 +5957,10 @@ impl<'a> Parser<'a> {
                                     maybe_append(attrs, extra_attrs));
             return Ok(Some(item));
         }
-        if self.eat_keyword(keywords::Union) {
+        if self.check_keyword(keywords::Union) &&
+                self.look_ahead(1, |t| t.is_ident() && !t.is_any_keyword()) {
             // UNION ITEM
+            self.bump();
             let (ident, item_, extra_attrs) = self.parse_item_union()?;
             let last_span = self.last_span;
             let item = self.mk_item(lo,
diff --git a/src/test/compile-fail/issue-17800.rs b/src/test/compile-fail/issue-17800.rs
index 58d580a5c1a1..d5f1614c14d2 100644
--- a/src/test/compile-fail/issue-17800.rs
+++ b/src/test/compile-fail/issue-17800.rs
@@ -18,7 +18,7 @@ enum MyOption {
 fn main() {
     match MyOption::MySome(42) {
         MyOption::MySome { x: 42 } => (),
-        //~^ ERROR struct `MyOption::MySome` does not have a field named `x`
+        //~^ ERROR variant `MyOption::MySome` does not have a field named `x`
         //~| ERROR pattern does not mention field `0`
         _ => (),
     }
diff --git a/src/test/compile-fail/issue-19922.rs b/src/test/compile-fail/issue-19922.rs
index e3ced3028098..a8350fe0986c 100644
--- a/src/test/compile-fail/issue-19922.rs
+++ b/src/test/compile-fail/issue-19922.rs
@@ -14,5 +14,5 @@ enum Homura {
 
 fn main() {
     let homura = Homura::Akemi { kaname: () };
-    //~^ ERROR struct variant `Homura::Akemi` has no field named `kaname`
+    //~^ ERROR variant `Homura::Akemi` has no field named `kaname`
 }
diff --git a/src/test/compile-fail/issue-4736.rs b/src/test/compile-fail/issue-4736.rs
index a8a1b1482fc0..c93e75042dd1 100644
--- a/src/test/compile-fail/issue-4736.rs
+++ b/src/test/compile-fail/issue-4736.rs
@@ -13,5 +13,5 @@
 struct NonCopyable(());
 
 fn main() {
-    let z = NonCopyable{ p: () }; //~ ERROR structure `NonCopyable` has no field named `p`
+    let z = NonCopyable{ p: () }; //~ ERROR struct `NonCopyable` has no field named `p`
 }
diff --git a/src/test/compile-fail/numeric-fields.rs b/src/test/compile-fail/numeric-fields.rs
index 480d2dcddddd..c4aff9471b8a 100644
--- a/src/test/compile-fail/numeric-fields.rs
+++ b/src/test/compile-fail/numeric-fields.rs
@@ -13,7 +13,7 @@
 struct S(u8, u16);
 
 fn main() {
-    let s = S{0b1: 10, 0: 11}; //~ ERROR structure `S` has no field named `0b1`
+    let s = S{0b1: 10, 0: 11}; //~ ERROR struct `S` has no field named `0b1`
     match s {
         S{0: a, 0x1: b, ..} => {} //~ ERROR does not have a field named `0x1`
     }
diff --git a/src/test/compile-fail/struct-fields-hints-no-dupe.rs b/src/test/compile-fail/struct-fields-hints-no-dupe.rs
index 8df9ffd6cc73..5f1f8ca856f9 100644
--- a/src/test/compile-fail/struct-fields-hints-no-dupe.rs
+++ b/src/test/compile-fail/struct-fields-hints-no-dupe.rs
@@ -17,7 +17,7 @@ struct A {
 fn main() {
     let a = A {
         foo : 5,
-        bar : 42,//~ ERROR structure `A` has no field named `bar`
+        bar : 42,//~ ERROR struct `A` has no field named `bar`
         //~^ HELP did you mean `barr`?
         car : 9,
     };
diff --git a/src/test/compile-fail/struct-fields-hints.rs b/src/test/compile-fail/struct-fields-hints.rs
index 37001f1e60a0..4ba1fd2f7bb3 100644
--- a/src/test/compile-fail/struct-fields-hints.rs
+++ b/src/test/compile-fail/struct-fields-hints.rs
@@ -17,7 +17,7 @@ struct A {
 fn main() {
     let a = A {
         foo : 5,
-        bar : 42,//~ ERROR structure `A` has no field named `bar`
+        bar : 42,//~ ERROR struct `A` has no field named `bar`
         //~^ HELP did you mean `car`?
     };
 }
diff --git a/src/test/compile-fail/struct-fields-too-many.rs b/src/test/compile-fail/struct-fields-too-many.rs
index 9244a9d4f9d0..5d16573f2f1e 100644
--- a/src/test/compile-fail/struct-fields-too-many.rs
+++ b/src/test/compile-fail/struct-fields-too-many.rs
@@ -15,6 +15,6 @@ struct BuildData {
 fn main() {
     let foo = BuildData {
         foo: 0,
-        bar: 0 //~ ERROR structure `BuildData` has no field named `bar`
+        bar: 0 //~ ERROR struct `BuildData` has no field named `bar`
     };
 }
diff --git a/src/test/compile-fail/suggest-private-fields.rs b/src/test/compile-fail/suggest-private-fields.rs
index 9c61f618e690..41bd00a518c5 100644
--- a/src/test/compile-fail/suggest-private-fields.rs
+++ b/src/test/compile-fail/suggest-private-fields.rs
@@ -22,16 +22,16 @@ struct A {
 fn main () {
     // external crate struct
     let k = B {
-        aa: 20, //~ ERROR structure `xc::B` has no field named `aa`
+        aa: 20, //~ ERROR struct `xc::B` has no field named `aa`
         //~^ HELP did you mean `a`?
-        bb: 20, //~ ERROR structure `xc::B` has no field named `bb`
+        bb: 20, //~ ERROR struct `xc::B` has no field named `bb`
         //~^ HELP did you mean `a`?
     };
     // local crate struct
     let l = A {
-        aa: 20, //~ ERROR structure `A` has no field named `aa`
+        aa: 20, //~ ERROR struct `A` has no field named `aa`
         //~^ HELP did you mean `a`?
-        bb: 20, //~ ERROR structure `A` has no field named `bb`
+        bb: 20, //~ ERROR struct `A` has no field named `bb`
         //~^ HELP did you mean `b`?
     };
 }
diff --git a/src/test/compile-fail/union-empty.rs b/src/test/compile-fail/union-empty.rs
new file mode 100644
index 000000000000..ce5bbf60fee2
--- /dev/null
+++ b/src/test/compile-fail/union-empty.rs
@@ -0,0 +1,15 @@
+// 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.
+
+#![feature(untagged_unions)]
+
+union U {} //~ ERROR unions cannot have zero fields
+
+fn main() {}
diff --git a/src/test/compile-fail/union-fields.rs b/src/test/compile-fail/union-fields.rs
new file mode 100644
index 000000000000..2bd1b8a7b32c
--- /dev/null
+++ b/src/test/compile-fail/union-fields.rs
@@ -0,0 +1,34 @@
+// 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.
+
+#![feature(untagged_unions)]
+
+union U {
+    a: u8,
+    b: u16,
+}
+
+fn main() {
+    let u = U {}; //~ ERROR union expressions should have exactly one field
+    let u = U { a: 0 }; // OK
+    let u = U { a: 0, b: 1 }; //~ ERROR union expressions should have exactly one field
+    let u = U { a: 0, b: 1, c: 2 }; //~ ERROR union expressions should have exactly one field
+                                    //~^ ERROR union `U` has no field named `c`
+    let u = U { ..u }; //~ ERROR union expressions should have exactly one field
+                       //~^ ERROR functional record update syntax requires a struct
+
+    let U {} = u; //~ ERROR union patterns without `..` should have at least one field
+    let U { a } = u; // OK
+    let U { a, b } = u; //~ ERROR union patterns can have at most one field
+    let U { a, b, c } = u; //~ ERROR union patterns can have at most one field
+                           //~^ ERROR union `U` does not have a field named `c`
+    let U { .. } = u; // OK
+    let U { a, .. } = u; // OK
+}
diff --git a/src/test/run-pass/union-backcomp.rs b/src/test/run-pass/union-backcomp.rs
new file mode 100644
index 000000000000..c1210dd62121
--- /dev/null
+++ b/src/test/run-pass/union-backcomp.rs
@@ -0,0 +1,23 @@
+// 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.
+
+#![feature(untagged_unions)]
+
+fn main() {
+    let union = 10;
+
+    union;
+
+    union as u8;
+
+    union U {
+        a: u8,
+    }
+}
diff --git a/src/test/run-pass/union-basic.rs b/src/test/run-pass/union-basic.rs
index 474c8b4b1810..dee86b232b48 100644
--- a/src/test/run-pass/union-basic.rs
+++ b/src/test/run-pass/union-basic.rs
@@ -25,6 +25,12 @@ union W {
     b: u64,
 }
 
+#[repr(C)]
+union Y {
+    f1: u16,
+    f2: [u8; 4],
+}
+
 fn main() {
     assert_eq!(size_of::(), 1);
     assert_eq!(size_of::(), 8);
@@ -32,6 +38,8 @@ fn main() {
     assert_eq!(align_of::(), 1);
     assert_eq!(align_of::(), align_of::());
     assert_eq!(align_of::(), align_of::());
+    assert_eq!(size_of::(), 4);
+    assert_eq!(align_of::(), 2);
 
     let u = U { a: 10 };
     assert_eq!(u.a, 10);
diff --git a/src/test/run-pass/union-drop.rs b/src/test/run-pass/union-drop.rs
new file mode 100644
index 000000000000..467403ff2e12
--- /dev/null
+++ b/src/test/run-pass/union-drop.rs
@@ -0,0 +1,26 @@
+// 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.
+
+// Drop works for union itself.
+
+#![feature(untagged_unions)]
+
+union U {
+    a: u8
+}
+
+impl Drop for U {
+    fn drop(&mut self) {}
+}
+
+fn main() {
+    // 'unions are not fully implemented', src/librustc_trans/glue.rs:567
+    // let u = U { a: 1 };
+}
diff --git a/src/test/run-pass/union-pat-refutability.rs b/src/test/run-pass/union-pat-refutability.rs
new file mode 100644
index 000000000000..6b39eed7ac94
--- /dev/null
+++ b/src/test/run-pass/union-pat-refutability.rs
@@ -0,0 +1,62 @@
+// 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.
+
+#![feature(untagged_unions)]
+
+#[repr(u32)]
+enum Tag { I, F }
+
+#[repr(C)]
+union U {
+    i: i32,
+    f: f32,
+}
+
+#[repr(C)]
+struct Value {
+    tag: Tag,
+    u: U,
+}
+
+fn is_zero(v: Value) -> bool {
+    unsafe {
+        match v {
+            Value { tag: Tag::I, u: U { i: 0 } } => true,
+            Value { tag: Tag::F, u: U { f: 0.0 } } => true,
+            _ => false,
+        }
+    }
+}
+
+union W {
+    a: u8,
+    b: u8,
+}
+
+fn refut(w: W) {
+    match w {
+        W { a: 10 } => {
+            panic!();
+        }
+        W { b } => {
+            assert_eq!(b, 11);
+        }
+    }
+}
+
+fn main() {
+    // ICE
+    // let v = Value { tag: Tag::I, u: U { i: 1 } };
+    // assert_eq!(is_zero(v), false);
+
+    // ICE
+    // let w = W { a: 11 };
+    // refut(w);
+}

From e88d4ca0e1bb7c3b0a446788ea0c010aaea65ffc Mon Sep 17 00:00:00 2001
From: Vadim Petrochenkov 
Date: Thu, 18 Aug 2016 20:12:28 +0300
Subject: [PATCH 135/443] Make accesses to union fields unsafe

---
 src/librustc/middle/effect.rs               | 24 +++++++++++++++++----
 src/test/compile-fail/union-unsafe.rs       | 23 ++++++++++++++++++++
 src/test/run-pass/union-basic.rs            | 20 ++++++++++-------
 src/test/run-pass/union-pat-refutability.rs | 14 ++++++------
 4 files changed, 63 insertions(+), 18 deletions(-)
 create mode 100644 src/test/compile-fail/union-unsafe.rs

diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs
index 250ad80f5af6..e52eba68da19 100644
--- a/src/librustc/middle/effect.rs
+++ b/src/librustc/middle/effect.rs
@@ -13,15 +13,14 @@
 use self::RootUnsafeContext::*;
 
 use dep_graph::DepNode;
-use hir::def::Def;
 use ty::{self, Ty, TyCtxt};
 use ty::MethodCall;
 
 use syntax::ast;
 use syntax_pos::Span;
-use hir;
-use hir::intravisit;
-use hir::intravisit::{FnKind, Visitor};
+use hir::{self, PatKind};
+use hir::def::Def;
+use hir::intravisit::{self, FnKind, Visitor};
 
 #[derive(Copy, Clone)]
 struct UnsafeContext {
@@ -178,11 +177,28 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EffectCheckVisitor<'a, 'tcx> {
                     self.require_unsafe(expr.span, "use of mutable static");
                 }
             }
+            hir::ExprField(ref base_expr, field) => {
+                if let ty::TyUnion(..) = self.tcx.expr_ty_adjusted(base_expr).sty {
+                    self.require_unsafe(field.span, "access to union field");
+                }
+            }
             _ => {}
         }
 
         intravisit::walk_expr(self, expr);
     }
+
+    fn visit_pat(&mut self, pat: &hir::Pat) {
+        if let PatKind::Struct(_, ref fields, _) = pat.node {
+            if let ty::TyUnion(..) = self.tcx.pat_ty(pat).sty {
+                for field in fields {
+                    self.require_unsafe(field.span, "matching on union field");
+                }
+            }
+        }
+
+        intravisit::walk_pat(self, pat);
+    }
 }
 
 pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
diff --git a/src/test/compile-fail/union-unsafe.rs b/src/test/compile-fail/union-unsafe.rs
new file mode 100644
index 000000000000..762ac5d87513
--- /dev/null
+++ b/src/test/compile-fail/union-unsafe.rs
@@ -0,0 +1,23 @@
+// 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.
+
+#![feature(untagged_unions)]
+
+union U {
+    a: u8
+}
+
+fn main() {
+    let u = U { a: 10 }; // OK
+    let a = u.a; //~ ERROR access to union field requires unsafe function or block
+    let U { a } = u; //~ ERROR matching on union field requires unsafe function or block
+    if let U { a: 11 } = u {} //~ ERROR matching on union field requires unsafe function or block
+    let U { .. } = u; // OK
+}
diff --git a/src/test/run-pass/union-basic.rs b/src/test/run-pass/union-basic.rs
index dee86b232b48..afbfe5bf92be 100644
--- a/src/test/run-pass/union-basic.rs
+++ b/src/test/run-pass/union-basic.rs
@@ -42,14 +42,18 @@ fn main() {
     assert_eq!(align_of::(), 2);
 
     let u = U { a: 10 };
-    assert_eq!(u.a, 10);
-    let U { a } = u;
-    assert_eq!(a, 10);
+    unsafe {
+        assert_eq!(u.a, 10);
+        let U { a } = u;
+        assert_eq!(a, 10);
+    }
 
     let mut w: W = unsafe { zeroed() };
-    assert_eq!(w.a, 0);
-    assert_eq!(w.b, 0);
-    // w.a = 1;
-    // assert_eq!(w.a, 0);
-    // assert_eq!(w.b, 0);
+    unsafe {
+        assert_eq!(w.a, 0);
+        assert_eq!(w.b, 0);
+        // w.a = 1;
+        // assert_eq!(w.a, 0);
+        // assert_eq!(w.b, 0);
+    }
 }
diff --git a/src/test/run-pass/union-pat-refutability.rs b/src/test/run-pass/union-pat-refutability.rs
index 6b39eed7ac94..a57c1103a9b4 100644
--- a/src/test/run-pass/union-pat-refutability.rs
+++ b/src/test/run-pass/union-pat-refutability.rs
@@ -41,12 +41,14 @@ union W {
 }
 
 fn refut(w: W) {
-    match w {
-        W { a: 10 } => {
-            panic!();
-        }
-        W { b } => {
-            assert_eq!(b, 11);
+    unsafe {
+        match w {
+            W { a: 10 } => {
+                panic!();
+            }
+            W { b } => {
+                assert_eq!(b, 11);
+            }
         }
     }
 }

From bea0b15935a8cb5811eb80e3220e9ab786feb782 Mon Sep 17 00:00:00 2001
From: Vadim Petrochenkov 
Date: Fri, 19 Aug 2016 19:20:30 +0300
Subject: [PATCH 136/443] Implement drop translation and add lint for unions
 with drop fields

Fix some typeck bugs blocking drop tests
---
 src/librustc_lint/builtin.rs                  | 33 +++++++++++++
 src/librustc_lint/lib.rs                      |  1 +
 src/librustc_trans/glue.rs                    | 17 +++++--
 src/librustc_typeck/check/mod.rs              |  9 ++--
 src/librustc_typeck/collect.rs                |  3 +-
 .../union-with-drop-fields-lint.rs            | 40 +++++++++++++++
 src/test/run-pass/union-drop.rs               | 49 +++++++++++++++++--
 7 files changed, 136 insertions(+), 16 deletions(-)
 create mode 100644 src/test/compile-fail/union-with-drop-fields-lint.rs

diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index b55cad58e2fe..1702c1c0edc9 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -1164,3 +1164,36 @@ impl LateLintPass for UnstableFeatures {
         }
     }
 }
+
+/// Lint for unions that contain fields with possibly non-trivial destructors.
+pub struct UnionsWithDropFields;
+
+declare_lint! {
+    UNIONS_WITH_DROP_FIELDS,
+    Warn,
+    "use of unions that contain fields with possibly non-trivial drop code"
+}
+
+impl LintPass for UnionsWithDropFields {
+    fn get_lints(&self) -> LintArray {
+        lint_array!(UNIONS_WITH_DROP_FIELDS)
+    }
+}
+
+impl LateLintPass for UnionsWithDropFields {
+    fn check_item(&mut self, ctx: &LateContext, item: &hir::Item) {
+        if let hir::ItemUnion(ref vdata, _) = item.node {
+            let param_env = &ty::ParameterEnvironment::for_item(ctx.tcx, item.id);
+            for field in vdata.fields() {
+                let field_ty = ctx.tcx.node_id_to_type(field.id);
+                if ctx.tcx.type_needs_drop_given_env(field_ty, param_env) {
+                    ctx.span_lint(UNIONS_WITH_DROP_FIELDS,
+                                  field.span,
+                                  "union contains a field with possibly non-trivial drop code, \
+                                   drop code of union fields is ignored when dropping the union");
+                    return;
+                }
+            }
+        }
+    }
+}
diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs
index 0f0e9cfb3577..c3b752d605f9 100644
--- a/src/librustc_lint/lib.rs
+++ b/src/librustc_lint/lib.rs
@@ -128,6 +128,7 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
                  InvalidNoMangleItems,
                  PluginAsLibrary,
                  MutableTransmutes,
+                 UnionsWithDropFields,
                  );
 
     add_builtin_with_new!(sess,
diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs
index 5da9ef3646e6..0d62a63b89fc 100644
--- a/src/librustc_trans/glue.rs
+++ b/src/librustc_trans/glue.rs
@@ -267,7 +267,8 @@ pub fn implement_drop_glue<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
 
 fn trans_struct_drop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                                  t: Ty<'tcx>,
-                                 v0: ValueRef)
+                                 v0: ValueRef,
+                                 shallow_drop: bool)
                                  -> Block<'blk, 'tcx>
 {
     debug!("trans_struct_drop t: {}", t);
@@ -286,7 +287,9 @@ fn trans_struct_drop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
 
     // Issue #23611: schedule cleanup of contents, re-inspecting the
     // discriminant (if any) in case of variant swap in drop code.
-    bcx.fcx.schedule_drop_adt_contents(contents_scope, v0, t);
+    if !shallow_drop {
+        bcx.fcx.schedule_drop_adt_contents(contents_scope, v0, t);
+    }
 
     let (sized_args, unsized_args);
     let args: &[ValueRef] = if type_is_sized(tcx, t) {
@@ -470,9 +473,6 @@ fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, g: DropGlueK
                 trans_exchange_free_ty(bcx, llbox, content_ty, DebugLoc::None)
             }
         }
-        ty::TyUnion(..) => {
-            unimplemented_unions!();
-        }
         ty::TyTrait(..) => {
             // No support in vtable for distinguishing destroying with
             // versus without calling Drop::drop. Assert caller is
@@ -491,6 +491,13 @@ fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, g: DropGlueK
                 if def.dtor_kind().is_present() && !skip_dtor => {
             trans_struct_drop(bcx, t, v0)
         }
+        ty::TyUnion(def, _) => {
+            if def.dtor_kind().is_present() && !skip_dtor {
+                trans_struct_drop(bcx, t, v0, true)
+            } else {
+                bcx
+            }
+        }
         _ => {
             if bcx.fcx.type_needs_drop(t) {
                 drop_structural_ty(bcx, v0, t)
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index f8ee9efee7a5..f4fea5542b3d 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -3235,11 +3235,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 Some((type_did, self.tcx.expect_variant_def(def)))
             }
             Def::TyAlias(did) => {
-                if let Some(&ty::TyStruct(adt, _)) = self.tcx.opt_lookup_item_type(did)
-                                                             .map(|scheme| &scheme.ty.sty) {
-                    Some((did, adt.struct_variant()))
-                } else {
-                    None
+                match self.tcx.opt_lookup_item_type(did).map(|scheme| &scheme.ty.sty) {
+                    Some(&ty::TyStruct(adt, _)) |
+                    Some(&ty::TyUnion(adt, _)) => Some((did, adt.struct_variant())),
+                    _ => None,
                 }
             }
             _ => None
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index a100c919d6f4..31f28b3803d6 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -1450,7 +1450,8 @@ fn generics_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
 
                     ItemTy(_, ref generics) |
                     ItemEnum(_, ref generics) |
-                    ItemStruct(_, ref generics) => {
+                    ItemStruct(_, ref generics) |
+                    ItemUnion(_, ref generics) => {
                         allow_defaults = true;
                         generics
                     }
diff --git a/src/test/compile-fail/union-with-drop-fields-lint.rs b/src/test/compile-fail/union-with-drop-fields-lint.rs
new file mode 100644
index 000000000000..87a72efbe08e
--- /dev/null
+++ b/src/test/compile-fail/union-with-drop-fields-lint.rs
@@ -0,0 +1,40 @@
+// 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.
+
+#![feature(untagged_unions)]
+#![allow(dead_code)]
+#![deny(unions_with_drop_fields)]
+
+union U {
+    a: u8, // OK
+}
+
+union W {
+    a: String, //~ ERROR union contains a field with possibly non-trivial drop code
+    b: String, // OK, only one field is reported
+}
+
+struct S(String);
+
+// `S` doesn't implement `Drop` trait, but still has non-trivial destructor
+union Y {
+    a: S, //~ ERROR union contains a field with possibly non-trivial drop code
+}
+
+// We don't know if `T` is trivially-destructable or not until trans
+union J {
+    a: T, //~ ERROR union contains a field with possibly non-trivial drop code
+}
+
+union H {
+    a: T, // OK, `T` is `Copy`, no destructor
+}
+
+fn main() {}
diff --git a/src/test/run-pass/union-drop.rs b/src/test/run-pass/union-drop.rs
index 467403ff2e12..2ca68dc3b6e3 100644
--- a/src/test/run-pass/union-drop.rs
+++ b/src/test/run-pass/union-drop.rs
@@ -12,15 +12,54 @@
 
 #![feature(untagged_unions)]
 
+struct S;
+
 union U {
     a: u8
 }
 
-impl Drop for U {
-    fn drop(&mut self) {}
+union W {
+    a: S,
 }
 
-fn main() {
-    // 'unions are not fully implemented', src/librustc_trans/glue.rs:567
-    // let u = U { a: 1 };
+union Y {
+    a: S,
+}
+
+impl Drop for S {
+    fn drop(&mut self) {
+        unsafe { CHECK += 10; }
+    }
+}
+
+impl Drop for U {
+    fn drop(&mut self) {
+        unsafe { CHECK += 1; }
+    }
+}
+
+impl Drop for W {
+    fn drop(&mut self) {
+        unsafe { CHECK += 1; }
+    }
+}
+
+static mut CHECK: u8 = 0;
+
+fn main() {
+    unsafe {
+        assert_eq!(CHECK, 0);
+        {
+            let u = U { a: 1 };
+        }
+        assert_eq!(CHECK, 1); // 1, dtor of U is called
+        {
+            let w = W { a: S };
+        }
+        assert_eq!(CHECK, 2); // 2, not 11, dtor of S is not called
+        {
+            let y = Y { a: S };
+        }
+        assert_eq!(CHECK, 2); // 2, not 12, dtor of S is not called
+    }
 }

From 0cb19389b060c4d34c8e0654aabce8d39304ccca Mon Sep 17 00:00:00 2001
From: Vadim Petrochenkov 
Date: Fri, 19 Aug 2016 19:20:30 +0300
Subject: [PATCH 137/443] Fix buggy field access translation

---
 src/librustc/mir/repr.rs                     |  7 +++++--
 src/librustc/mir/tcx.rs                      |  2 +-
 src/librustc/mir/visit.rs                    |  3 ++-
 src/librustc_mir/build/expr/as_rvalue.rs     |  9 ++++++---
 src/librustc_mir/transform/deaggregator.rs   |  4 ++--
 src/librustc_mir/transform/qualify_consts.rs |  2 +-
 src/librustc_trans/mir/constant.rs           |  2 +-
 src/librustc_trans/mir/rvalue.rs             |  9 +++++----
 src/test/run-pass/union-basic.rs             |  6 +++---
 src/test/run-pass/union-pat-refutability.rs  | 10 ++++------
 10 files changed, 30 insertions(+), 24 deletions(-)

diff --git a/src/librustc/mir/repr.rs b/src/librustc/mir/repr.rs
index 8145c0aae3f7..a2abaa5e12f5 100644
--- a/src/librustc/mir/repr.rs
+++ b/src/librustc/mir/repr.rs
@@ -962,7 +962,10 @@ pub enum CastKind {
 pub enum AggregateKind<'tcx> {
     Vec,
     Tuple,
-    Adt(AdtDef<'tcx>, usize, &'tcx Substs<'tcx>),
+    /// The second field is variant number (discriminant), it's equal to 0
+    /// for struct and union expressions. The fourth field is active field
+    /// number and is present only for union expressions.
+    Adt(AdtDef<'tcx>, usize, &'tcx Substs<'tcx>, Option),
     Closure(DefId, ClosureSubsts<'tcx>),
 }
 
@@ -1069,7 +1072,7 @@ impl<'tcx> Debug for Rvalue<'tcx> {
                         }
                     }
 
-                    Adt(adt_def, variant, substs) => {
+                    Adt(adt_def, variant, substs, _) => {
                         let variant_def = &adt_def.variants[variant];
 
                         ppaux::parameterized(fmt, substs, variant_def.did,
diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs
index 76e5f8598c1c..a0ccc72aa1fc 100644
--- a/src/librustc/mir/tcx.rs
+++ b/src/librustc/mir/tcx.rs
@@ -187,7 +187,7 @@ impl<'tcx> Rvalue<'tcx> {
                             ops.iter().map(|op| op.ty(mir, tcx)).collect()
                         ))
                     }
-                    AggregateKind::Adt(def, _, substs) => {
+                    AggregateKind::Adt(def, _, substs, _) => {
                         Some(tcx.lookup_item_type(def.did).ty.subst(tcx, substs))
                     }
                     AggregateKind::Closure(did, substs) => {
diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs
index 2771880735c2..c2d0b2c686e7 100644
--- a/src/librustc/mir/visit.rs
+++ b/src/librustc/mir/visit.rs
@@ -536,7 +536,8 @@ macro_rules! make_mir_visitor {
                             }
                             AggregateKind::Adt(_adt_def,
                                                _variant_index,
-                                               ref $($mutability)* substs) => {
+                                               ref $($mutability)* substs,
+                                               _active_field_index) => {
                                 self.visit_substs(substs);
                             }
                             AggregateKind::Closure(ref $($mutability)* def_id,
diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs
index dafc53d3c154..6ea1fb503606 100644
--- a/src/librustc_mir/build/expr/as_rvalue.rs
+++ b/src/librustc_mir/build/expr/as_rvalue.rs
@@ -181,6 +181,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             ExprKind::Adt {
                 adt_def, variant_index, substs, fields, base
             } => { // see (*) above
+                let is_union = adt_def.adt_kind() == ty::AdtKind::Union;
+                let active_field_index = if is_union { Some(fields[0].name.index()) } else { None };
+
                 // first process the set of fields that were provided
                 // (evaluating them in order given by user)
                 let fields_map: FnvHashMap<_, _> =
@@ -204,11 +207,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                         })
                         .collect()
                 } else {
-                    field_names.iter().map(|n| fields_map[n].clone()).collect()
+                    field_names.iter().filter_map(|n| fields_map.get(n).cloned()).collect()
                 };
 
-                block.and(Rvalue::Aggregate(AggregateKind::Adt(adt_def, variant_index, substs),
-                                            fields))
+                let adt = AggregateKind::Adt(adt_def, variant_index, substs, active_field_index);
+                block.and(Rvalue::Aggregate(adt, fields))
             }
             ExprKind::Assign { .. } |
             ExprKind::AssignOp { .. } => {
diff --git a/src/librustc_mir/transform/deaggregator.rs b/src/librustc_mir/transform/deaggregator.rs
index cb3010a5cf43..77af02c18c60 100644
--- a/src/librustc_mir/transform/deaggregator.rs
+++ b/src/librustc_mir/transform/deaggregator.rs
@@ -57,7 +57,7 @@ impl<'tcx> MirPass<'tcx> for Deaggregator {
                 _ => span_bug!(src_info.span, "expected aggregate, not {:?}", rhs),
             };
             let (adt_def, variant, substs) = match agg_kind {
-                &AggregateKind::Adt(adt_def, variant, substs) => (adt_def, variant, substs),
+                &AggregateKind::Adt(adt_def, variant, substs, None) => (adt_def, variant, substs),
                 _ => span_bug!(src_info.span, "expected struct, not {:?}", rhs),
             };
             let n = bb.statements.len();
@@ -120,7 +120,7 @@ fn get_aggregate_statement_index<'a, 'tcx, 'b>(start: usize,
             _ => continue,
         };
         let (adt_def, variant) = match kind {
-            &AggregateKind::Adt(adt_def, variant, _) => (adt_def, variant),
+            &AggregateKind::Adt(adt_def, variant, _, None) => (adt_def, variant),
             _ => continue,
         };
         if operands.len() == 0 {
diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs
index 2fc90ab27a08..6c6a5f7fc74b 100644
--- a/src/librustc_mir/transform/qualify_consts.rs
+++ b/src/librustc_mir/transform/qualify_consts.rs
@@ -705,7 +705,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
             }
 
             Rvalue::Aggregate(ref kind, _) => {
-                if let AggregateKind::Adt(def, _, _) = *kind {
+                if let AggregateKind::Adt(def, _, _, _) = *kind {
                     if def.has_dtor() {
                         self.add(Qualif::NEEDS_DROP);
                         self.deny_drop();
diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs
index ade266a580e7..15dc7bb4421c 100644
--- a/src/librustc_trans/mir/constant.rs
+++ b/src/librustc_trans/mir/constant.rs
@@ -547,7 +547,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
                                                         self.monomorphize(&substs));
                 }
 
-                let val = if let mir::AggregateKind::Adt(adt_def, index, _) = *kind {
+                let val = if let mir::AggregateKind::Adt(adt_def, index, _, _) = *kind {
                     let repr = adt::represent_type(self.ccx, dest_ty);
                     let disr = Disr::from(adt_def.variants[index].disr_val);
                     adt::trans_const(self.ccx, &repr, disr, &fields)
diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs
index 13484cb7a4ec..21b019d7e24d 100644
--- a/src/librustc_trans/mir/rvalue.rs
+++ b/src/librustc_trans/mir/rvalue.rs
@@ -110,9 +110,9 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
 
             mir::Rvalue::Aggregate(ref kind, ref operands) => {
                 match *kind {
-                    mir::AggregateKind::Adt(adt_def, index, _) => {
+                    mir::AggregateKind::Adt(adt_def, variant_index, _, active_field_index) => {
                         let repr = adt::represent_type(bcx.ccx(), dest.ty.to_ty(bcx.tcx()));
-                        let disr = Disr::from(adt_def.variants[index].disr_val);
+                        let disr = Disr::from(adt_def.variants[variant_index].disr_val);
                         bcx.with_block(|bcx| {
                             adt::trans_set_discr(bcx, &repr, dest.llval, Disr::from(disr));
                         });
@@ -121,8 +121,9 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                             // Do not generate stores and GEPis for zero-sized fields.
                             if !common::type_is_zero_size(bcx.ccx(), op.ty) {
                                 let val = adt::MaybeSizedValue::sized(dest.llval);
-                                let lldest_i = adt::trans_field_ptr_builder(&bcx, &repr,
-                                                                            val, disr, i);
+                                let field_index = active_field_index.unwrap_or(i);
+                                let lldest_i = adt::trans_field_ptr_builder(&bcx, &repr, val,
+                                                                            disr, field_index);
                                 self.store_operand(&bcx, lldest_i, op);
                             }
                         }
diff --git a/src/test/run-pass/union-basic.rs b/src/test/run-pass/union-basic.rs
index afbfe5bf92be..a00bd73115a1 100644
--- a/src/test/run-pass/union-basic.rs
+++ b/src/test/run-pass/union-basic.rs
@@ -48,12 +48,12 @@ fn main() {
         assert_eq!(a, 10);
     }
 
-    let mut w: W = unsafe { zeroed() };
+    let mut w = W { b: 0 };
     unsafe {
         assert_eq!(w.a, 0);
         assert_eq!(w.b, 0);
         // w.a = 1;
-        // assert_eq!(w.a, 0);
-        // assert_eq!(w.b, 0);
+        assert_eq!(w.a, 0);
+        assert_eq!(w.b, 0);
     }
 }
diff --git a/src/test/run-pass/union-pat-refutability.rs b/src/test/run-pass/union-pat-refutability.rs
index a57c1103a9b4..e6144f35f1d5 100644
--- a/src/test/run-pass/union-pat-refutability.rs
+++ b/src/test/run-pass/union-pat-refutability.rs
@@ -54,11 +54,9 @@ fn refut(w: W) {
 }
 
 fn main() {
-    // ICE
-    // let v = Value { tag: Tag::I, u: U { i: 1 } };
-    // assert_eq!(is_zero(v), false);
+    let v = Value { tag: Tag::I, u: U { i: 1 } };
+    assert_eq!(is_zero(v), false);
 
-    // ICE
-    // let w = W { a: 11 };
-    // refut(w);
+    let w = W { a: 11 };
+    refut(w);
 }

From 2dc2fc5fc528aab7ba138f1a351df6f846dfec1d Mon Sep 17 00:00:00 2001
From: Vadim Petrochenkov 
Date: Mon, 22 Aug 2016 15:17:05 +0300
Subject: [PATCH 138/443] Fix rebase

---
 src/librustc_metadata/encoder.rs | 33 +++++++++++++++++++++++++++++++-
 1 file changed, 32 insertions(+), 1 deletion(-)

diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs
index e82742004c39..35f5eba4160d 100644
--- a/src/librustc_metadata/encoder.rs
+++ b/src/librustc_metadata/encoder.rs
@@ -1029,6 +1029,33 @@ impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> {
                                               def_to_u64(ctor_did));
                 }
             }
+            hir::ItemUnion(..) => {
+                let def = ecx.tcx.lookup_adt_def(def_id);
+                let variant = def.struct_variant();
+
+                encode_def_id_and_key(ecx, self.rbml_w, def_id);
+                encode_family(self.rbml_w, 'U');
+                self.encode_bounds_and_type_for_item(item.id);
+
+                encode_item_variances(self.rbml_w, ecx, item.id);
+                encode_name(self.rbml_w, item.name);
+                encode_attributes(self.rbml_w, &item.attrs);
+                encode_stability(self.rbml_w, stab);
+                encode_deprecation(self.rbml_w, depr);
+                self.encode_visibility(vis);
+                self.encode_repr_attrs(&item.attrs);
+
+                /* Encode def_ids for each field and method
+                for methods, write all the stuff get_trait_method
+                needs to know*/
+                self.encode_struct_fields(variant);
+
+                encode_inlined_item(ecx, self.rbml_w, InlinedItemRef::Item(def_id, item));
+                self.encode_mir(item.id);
+
+                // Encode inherent implementations for self union.
+                encode_inherent_implementations(ecx, self.rbml_w, def_id);
+            }
             hir::ItemDefaultImpl(unsafety, _) => {
                 encode_def_id_and_key(ecx, self.rbml_w, def_id);
                 encode_family(self.rbml_w, 'd');
@@ -1180,7 +1207,7 @@ impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> {
                 self.encode_addl_struct_info(def_id, struct_def.id(), item);
             }
             hir::ItemUnion(..) => {
-                unimplemented_unions!();
+                self.encode_addl_union_info(def_id);
             }
             hir::ItemImpl(_, _, _, _, _, ref ast_items) => {
                 self.encode_addl_impl_info(def_id, item.id, ast_items);
@@ -1217,6 +1244,10 @@ impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> {
         }
     }
 
+    fn encode_addl_union_info(&mut self, def_id: DefId) {
+        self.encode_fields(def_id);
+    }
+
     fn encode_addl_impl_info(&mut self,
                              def_id: DefId,
                              impl_id: ast::NodeId,

From d9b332bd69770cb716233b6998b11d345f6f184b Mon Sep 17 00:00:00 2001
From: Vadim Petrochenkov 
Date: Mon, 22 Aug 2016 19:56:14 +0300
Subject: [PATCH 139/443] Translate union constants

Fix alignment for packed unions
Add some missing privacy test
Get rid of `unimplemented_unions` macro
---
 src/librustc_const_eval/eval.rs              |  7 +-
 src/librustc_privacy/lib.rs                  |  5 +-
 src/librustc_trans/adt.rs                    | 23 +++++-
 src/librustc_trans/debuginfo/metadata.rs     |  9 ++-
 src/libsyntax/diagnostics/macros.rs          |  7 --
 src/libsyntax/feature_gate.rs                |  2 +-
 src/test/compile-fail/union-const-eval.rs    | 26 +++++++
 src/test/compile-fail/union-const-pat.rs     | 25 +++++++
 src/test/compile-fail/union-field-privacy.rs | 21 ++++++
 src/test/run-pass/union-const-trans.rs       | 27 +++++++
 src/test/run-pass/union-packed.rs            | 74 ++++++++++++++++++++
 11 files changed, 206 insertions(+), 20 deletions(-)
 create mode 100644 src/test/compile-fail/union-const-eval.rs
 create mode 100644 src/test/compile-fail/union-const-pat.rs
 create mode 100644 src/test/compile-fail/union-field-privacy.rs
 create mode 100644 src/test/run-pass/union-const-trans.rs
 create mode 100644 src/test/run-pass/union-packed.rs

diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs
index 81fe19812ca4..114b5e1331de 100644
--- a/src/librustc_const_eval/eval.rs
+++ b/src/librustc_const_eval/eval.rs
@@ -258,8 +258,7 @@ pub fn const_expr_to_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                 format!("floating point constants cannot be used in patterns"));
         }
         ty::TyEnum(adt_def, _) |
-        ty::TyStruct(adt_def, _) |
-        ty::TyUnion(adt_def, _) => {
+        ty::TyStruct(adt_def, _) => {
             if !tcx.has_attr(adt_def.did, "structural_match") {
                 tcx.sess.add_lint(
                     lint::builtin::ILLEGAL_STRUCT_OR_ENUM_CONSTANT_PATTERN,
@@ -272,6 +271,10 @@ pub fn const_expr_to_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                             tcx.item_path_str(adt_def.did)));
             }
         }
+        ty::TyUnion(..) => {
+            // Matching on union fields is unsafe, we can't hide it in constants
+            tcx.sess.span_err(span, "cannot use unions in constant patterns");
+        }
         _ => { }
     }
     let pat = match expr.node {
diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs
index 25601b6bfec7..6b291c693072 100644
--- a/src/librustc_privacy/lib.rs
+++ b/src/librustc_privacy/lib.rs
@@ -385,8 +385,9 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> {
     fn check_field(&mut self, span: Span, def: ty::AdtDef<'tcx>, field: ty::FieldDef<'tcx>) {
         if def.adt_kind() != ty::AdtKind::Enum &&
            !field.vis.is_accessible_from(self.curitem, &self.tcx.map) {
-            struct_span_err!(self.tcx.sess, span, E0451, "field `{}` of struct `{}` is private",
-                      field.name, self.tcx.item_path_str(def.did))
+            let kind_descr = if def.adt_kind() == ty::AdtKind::Union { "union" } else { "struct" };
+            struct_span_err!(self.tcx.sess, span, E0451, "field `{}` of {} `{}` is private",
+                      field.name, kind_descr, self.tcx.item_path_str(def.did))
                 .span_label(span, &format!("field `{}` is private", field.name))
                 .emit();
         }
diff --git a/src/librustc_trans/adt.rs b/src/librustc_trans/adt.rs
index abbb9a5d4dbe..7fd02ab82a3f 100644
--- a/src/librustc_trans/adt.rs
+++ b/src/librustc_trans/adt.rs
@@ -516,7 +516,7 @@ fn mk_union<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
 
     Union {
         min_size: min_size,
-        align: align,
+        align: if packed { 1 } else { align },
         packed: packed,
         fields: tys.to_vec(),
     }
@@ -1176,8 +1176,10 @@ pub fn trans_const<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, r: &Repr<'tcx>, discr
             contents.extend_from_slice(&[padding(ccx, max_sz - case.size)]);
             C_struct(ccx, &contents[..], false)
         }
-        UntaggedUnion(..) => {
-            unimplemented_unions!();
+        UntaggedUnion(ref un) => {
+            assert_eq!(discr, Disr(0));
+            let contents = build_const_union(ccx, un, vals[0]);
+            C_struct(ccx, &contents, un.packed)
         }
         Univariant(ref st) => {
             assert_eq!(discr, Disr(0));
@@ -1272,6 +1274,21 @@ fn build_const_struct<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     cfields
 }
 
+fn build_const_union<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
+                               un: &Union<'tcx>,
+                               field_val: ValueRef)
+                               -> Vec {
+    let mut cfields = vec![field_val];
+
+    let offset = machine::llsize_of_alloc(ccx, val_ty(field_val));
+    let size = roundup(un.min_size, un.align);
+    if offset != size {
+        cfields.push(padding(ccx, size - offset));
+    }
+
+    cfields
+}
+
 fn padding(ccx: &CrateContext, size: u64) -> ValueRef {
     C_undef(Type::array(&Type::i8(ccx), size))
 }
diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs
index bd67a215d65e..00493b018c10 100644
--- a/src/librustc_trans/debuginfo/metadata.rs
+++ b/src/librustc_trans/debuginfo/metadata.rs
@@ -786,7 +786,7 @@ pub fn type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                                     usage_site_span).finalize(cx)
         }
         ty::TyUnion(..) => {
-            unimplemented_unions!();
+            unimplemented!();
         }
         ty::TyTuple(ref elements) => {
             prepare_tuple_metadata(cx,
@@ -1302,9 +1302,6 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> {
                     ]
                 }
             }
-            adt::UntaggedUnion(..) => {
-                unimplemented_unions!();
-            }
             adt::RawNullablePointer { nndiscr: non_null_variant_index, nnty, .. } => {
                 // As far as debuginfo is concerned, the pointer this enum
                 // represents is still wrapped in a struct. This is to make the
@@ -1421,7 +1418,9 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> {
                     }
                 ]
             },
-            adt::CEnum(..) => span_bug!(self.span, "This should be unreachable.")
+            adt::CEnum(..) | adt::UntaggedUnion(..) => {
+                span_bug!(self.span, "This should be unreachable.")
+            }
         }
     }
 }
diff --git a/src/libsyntax/diagnostics/macros.rs b/src/libsyntax/diagnostics/macros.rs
index e2a7ec0a33de..25e0428248df 100644
--- a/src/libsyntax/diagnostics/macros.rs
+++ b/src/libsyntax/diagnostics/macros.rs
@@ -107,13 +107,6 @@ macro_rules! help {
     })
 }
 
-#[macro_export]
-macro_rules! unimplemented_unions {
-    () => ({
-        panic!("unions are not fully implemented");
-    })
-}
-
 #[macro_export]
 macro_rules! register_diagnostics {
     ($($code:tt),*) => (
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index b40124bd7741..287d33cc3e5b 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -959,7 +959,7 @@ impl<'a> Visitor for PostExpansionVisitor<'a> {
             ast::ItemKind::Union(..) => {
                 gate_feature_post!(&self, untagged_unions,
                                    i.span,
-                                   "unions are unstable and not fully implemented");
+                                   "unions are unstable and possibly buggy");
             }
 
             ast::ItemKind::DefaultImpl(..) => {
diff --git a/src/test/compile-fail/union-const-eval.rs b/src/test/compile-fail/union-const-eval.rs
new file mode 100644
index 000000000000..b2bf173c59c8
--- /dev/null
+++ b/src/test/compile-fail/union-const-eval.rs
@@ -0,0 +1,26 @@
+// 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.
+
+#![feature(untagged_unions)]
+
+union U {
+    a: usize,
+    b: usize,
+}
+
+const C: U = U { a: 10 };
+
+fn main() {
+    unsafe {
+        let a: [u8; C.a]; // OK
+        let b: [u8; C.b]; //~ ERROR constant evaluation error
+                          //~^ NOTE nonexistent struct field
+    }
+}
diff --git a/src/test/compile-fail/union-const-pat.rs b/src/test/compile-fail/union-const-pat.rs
new file mode 100644
index 000000000000..3d168980ed24
--- /dev/null
+++ b/src/test/compile-fail/union-const-pat.rs
@@ -0,0 +1,25 @@
+// 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.
+
+#![feature(untagged_unions)]
+
+union U {
+    a: usize,
+    b: usize,
+}
+
+const C: U = U { a: 10 };
+
+fn main() {
+    match C {
+        C => {} //~ ERROR cannot use unions in constant patterns
+        _ => {}
+    }
+}
diff --git a/src/test/compile-fail/union-field-privacy.rs b/src/test/compile-fail/union-field-privacy.rs
new file mode 100644
index 000000000000..d1f2bbbc3d03
--- /dev/null
+++ b/src/test/compile-fail/union-field-privacy.rs
@@ -0,0 +1,21 @@
+// 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.
+
+#![feature(untagged_unions)]
+
+mod m {
+    pub union U {
+        a: u8
+    }
+}
+
+fn main() {
+    let u = m::U { a: 0 }; //~ ERROR field `a` of union `m::U` is private
+}
diff --git a/src/test/run-pass/union-const-trans.rs b/src/test/run-pass/union-const-trans.rs
new file mode 100644
index 000000000000..bdae1a0eaf88
--- /dev/null
+++ b/src/test/run-pass/union-const-trans.rs
@@ -0,0 +1,27 @@
+// 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.
+
+#![feature(untagged_unions)]
+
+union U {
+    a: u64,
+    b: u64,
+}
+
+const C: U = U { b: 10 };
+
+fn main() {
+    unsafe {
+        let a = C.a;
+        let b = C.b;
+        assert_eq!(a, 10);
+        assert_eq!(b, 10);
+     }
+}
diff --git a/src/test/run-pass/union-packed.rs b/src/test/run-pass/union-packed.rs
new file mode 100644
index 000000000000..b1650ae3a7c1
--- /dev/null
+++ b/src/test/run-pass/union-packed.rs
@@ -0,0 +1,74 @@
+// 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.
+
+#![feature(untagged_unions)]
+
+use std::mem::{size_of, size_of_val, align_of, align_of_val};
+
+struct S {
+    a: u16,
+    b: [u8; 3],
+}
+
+#[repr(packed)]
+struct Sp {
+    a: u16,
+    b: [u8; 3],
+}
+
+union U {
+    a: u16,
+    b: [u8; 3],
+}
+
+#[repr(packed)]
+union Up {
+    a: u16,
+    b: [u8; 3],
+}
+
+const CS: S = S { a: 0, b: [0, 0, 0] };
+const CSP: Sp = Sp { a: 0, b: [0, 0, 0] };
+const CU: U = U { b: [0, 0, 0] };
+const CUP: Up = Up { b: [0, 0, 0] };
+
+fn main() {
+    let s = S { a: 0, b: [0, 0, 0] };
+    assert_eq!(size_of::(), 6);
+    assert_eq!(size_of_val(&s), 6);
+    assert_eq!(size_of_val(&CS), 6);
+    assert_eq!(align_of::(), 2);
+    assert_eq!(align_of_val(&s), 2);
+    assert_eq!(align_of_val(&CS), 2);
+
+    let sp = Sp { a: 0, b: [0, 0, 0] };
+    assert_eq!(size_of::(), 5);
+    assert_eq!(size_of_val(&sp), 5);
+    assert_eq!(size_of_val(&CSP), 5);
+    assert_eq!(align_of::(), 1);
+    assert_eq!(align_of_val(&sp), 1);
+    assert_eq!(align_of_val(&CSP), 1);
+
+    let u = U { b: [0, 0, 0] };
+    assert_eq!(size_of::(), 4);
+    assert_eq!(size_of_val(&u), 4);
+    assert_eq!(size_of_val(&CU), 4);
+    assert_eq!(align_of::(), 2);
+    assert_eq!(align_of_val(&u), 2);
+    assert_eq!(align_of_val(&CU), 2);
+
+    let up = Up { b: [0, 0, 0] };
+    assert_eq!(size_of::(), 3);
+    assert_eq!(size_of_val(&up), 3);
+    assert_eq!(size_of_val(&CUP), 3);
+    assert_eq!(align_of::(), 1);
+    assert_eq!(align_of_val(&up), 1);
+    assert_eq!(align_of_val(&CUP), 1);
+}

From 079c390d5089735b5eaa8b06ddb3beedcddbee7d Mon Sep 17 00:00:00 2001
From: Vadim Petrochenkov 
Date: Mon, 22 Aug 2016 21:11:22 +0300
Subject: [PATCH 140/443] Generate debuginfo for unions

---
 src/librustc_trans/debuginfo/metadata.rs | 106 ++++++++++++++++++++++-
 src/test/debuginfo/union-smoke.rs        |  49 +++++++++++
 2 files changed, 153 insertions(+), 2 deletions(-)
 create mode 100644 src/test/debuginfo/union-smoke.rs

diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs
index 00493b018c10..bdfeee37625e 100644
--- a/src/librustc_trans/debuginfo/metadata.rs
+++ b/src/librustc_trans/debuginfo/metadata.rs
@@ -786,7 +786,10 @@ pub fn type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                                     usage_site_span).finalize(cx)
         }
         ty::TyUnion(..) => {
-            unimplemented!();
+            prepare_union_metadata(cx,
+                                   t,
+                                   unique_type_id,
+                                   usage_site_span).finalize(cx)
         }
         ty::TyTuple(ref elements) => {
             prepare_tuple_metadata(cx,
@@ -1038,6 +1041,7 @@ enum MemberDescriptionFactory<'tcx> {
     StructMDF(StructMemberDescriptionFactory<'tcx>),
     TupleMDF(TupleMemberDescriptionFactory<'tcx>),
     EnumMDF(EnumMemberDescriptionFactory<'tcx>),
+    UnionMDF(UnionMemberDescriptionFactory<'tcx>),
     VariantMDF(VariantMemberDescriptionFactory<'tcx>)
 }
 
@@ -1054,6 +1058,9 @@ impl<'tcx> MemberDescriptionFactory<'tcx> {
             EnumMDF(ref this) => {
                 this.create_member_descriptions(cx)
             }
+            UnionMDF(ref this) => {
+                this.create_member_descriptions(cx)
+            }
             VariantMDF(ref this) => {
                 this.create_member_descriptions(cx)
             }
@@ -1154,7 +1161,6 @@ fn prepare_struct_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
     )
 }
 
-
 //=-----------------------------------------------------------------------------
 // Tuples
 //=-----------------------------------------------------------------------------
@@ -1209,6 +1215,66 @@ fn prepare_tuple_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
     )
 }
 
+//=-----------------------------------------------------------------------------
+// Unions
+//=-----------------------------------------------------------------------------
+
+struct UnionMemberDescriptionFactory<'tcx> {
+    variant: ty::VariantDef<'tcx>,
+    substs: &'tcx Substs<'tcx>,
+    span: Span,
+}
+
+impl<'tcx> UnionMemberDescriptionFactory<'tcx> {
+    fn create_member_descriptions<'a>(&self, cx: &CrateContext<'a, 'tcx>)
+                                      -> Vec {
+        self.variant.fields.iter().map(|field| {
+            let fty = monomorphize::field_ty(cx.tcx(), self.substs, field);
+            MemberDescription {
+                name: field.name.to_string(),
+                llvm_type: type_of::type_of(cx, fty),
+                type_metadata: type_metadata(cx, fty, self.span),
+                offset: FixedMemberOffset { bytes: 0 },
+                flags: FLAGS_NONE,
+            }
+        }).collect()
+    }
+}
+
+fn prepare_union_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
+                                    union_type: Ty<'tcx>,
+                                    unique_type_id: UniqueTypeId,
+                                    span: Span)
+                                    -> RecursiveTypeDescription<'tcx> {
+    let union_name = compute_debuginfo_type_name(cx, union_type, false);
+    let union_llvm_type = type_of::in_memory_type_of(cx, union_type);
+
+    let (union_def_id, variant, substs) = match union_type.sty {
+        ty::TyUnion(def, substs) => (def.did, def.struct_variant(), substs),
+        _ => bug!("prepare_union_metadata on a non-union")
+    };
+
+    let (containing_scope, _) = get_namespace_and_span_for_item(cx, union_def_id);
+
+    let union_metadata_stub = create_union_stub(cx,
+                                                union_llvm_type,
+                                                &union_name,
+                                                unique_type_id,
+                                                containing_scope);
+
+    create_and_register_recursive_type_forward_declaration(
+        cx,
+        union_type,
+        unique_type_id,
+        union_metadata_stub,
+        union_llvm_type,
+        UnionMDF(UnionMemberDescriptionFactory {
+            variant: variant,
+            substs: substs,
+            span: span,
+        })
+    )
+}
 
 //=-----------------------------------------------------------------------------
 // Enums
@@ -1798,6 +1864,42 @@ fn create_struct_stub(cx: &CrateContext,
     return metadata_stub;
 }
 
+fn create_union_stub(cx: &CrateContext,
+                     union_llvm_type: Type,
+                     union_type_name: &str,
+                     unique_type_id: UniqueTypeId,
+                     containing_scope: DIScope)
+                   -> DICompositeType {
+    let (union_size, union_align) = size_and_align_of(cx, union_llvm_type);
+
+    let unique_type_id_str = debug_context(cx).type_map
+                                              .borrow()
+                                              .get_unique_type_id_as_string(unique_type_id);
+    let name = CString::new(union_type_name).unwrap();
+    let unique_type_id = CString::new(unique_type_id_str.as_bytes()).unwrap();
+    let metadata_stub = unsafe {
+        // LLVMRustDIBuilderCreateUnionType() wants an empty array. A null
+        // pointer will lead to hard to trace and debug LLVM assertions
+        // later on in llvm/lib/IR/Value.cpp.
+        let empty_array = create_DIArray(DIB(cx), &[]);
+
+        llvm::LLVMRustDIBuilderCreateUnionType(
+            DIB(cx),
+            containing_scope,
+            name.as_ptr(),
+            unknown_file_metadata(cx),
+            UNKNOWN_LINE_NUMBER,
+            bytes_to_bits(union_size),
+            bytes_to_bits(union_align),
+            0, // Flags
+            empty_array,
+            0, // RuntimeLang
+            unique_type_id.as_ptr())
+    };
+
+    return metadata_stub;
+}
+
 /// Creates debug information for the given global variable.
 ///
 /// Adds the created metadata nodes directly to the crate's IR.
diff --git a/src/test/debuginfo/union-smoke.rs b/src/test/debuginfo/union-smoke.rs
new file mode 100644
index 000000000000..11ee5031ca77
--- /dev/null
+++ b/src/test/debuginfo/union-smoke.rs
@@ -0,0 +1,49 @@
+// 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.
+
+// min-lldb-version: 310
+
+// compile-flags:-g
+
+// === GDB TESTS ===================================================================================
+
+// gdb-command:run
+// gdb-command:print u
+// gdb-check:$1 = {a = 11 '\v', b = 11}
+// gdb-command:print union_smoke::SU
+// gdb-check:$2 = {a = 10 '\n', b = 10}
+
+// === LLDB TESTS ==================================================================================
+
+// lldb-command:run
+// lldb-command:print a
+// lldb-check:[...]$0 = {a = 11 '\v', b = 11}
+// lldb-command:print union_smoke::SU
+// lldb-check:[...]$1 = {a = 10 '\n', b = 10}
+
+#![allow(unused)]
+#![feature(omit_gdb_pretty_printer_section)]
+#![omit_gdb_pretty_printer_section]
+#![feature(untagged_unions)]
+
+union U {
+    a: u8,
+    b: u64,
+}
+
+static SU: U = U { a: 10 };
+
+fn main() {
+    let u = U { b: 11 };
+
+    zzz(); // #break
+}
+
+fn zzz() {()}

From 59ccb7b6dbaf3a590cf3a234661aa7dcc2188aed Mon Sep 17 00:00:00 2001
From: Vadim Petrochenkov 
Date: Wed, 24 Aug 2016 21:10:19 +0300
Subject: [PATCH 141/443] Support deriving some traits for unions

---
 src/libsyntax_ext/deriving/generic/mod.rs | 11 +++++++-
 src/test/compile-fail/union-derive.rs     | 30 ++++++++++++++++++++++
 src/test/run-pass/union-derive.rs         | 31 +++++++++++++++++++++++
 3 files changed, 71 insertions(+), 1 deletion(-)
 create mode 100644 src/test/compile-fail/union-derive.rs
 create mode 100644 src/test/run-pass/union-derive.rs

diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs
index 5c636d43a714..b37d53329839 100644
--- a/src/libsyntax_ext/deriving/generic/mod.rs
+++ b/src/libsyntax_ext/deriving/generic/mod.rs
@@ -410,9 +410,18 @@ impl<'a> TraitDef<'a> {
                     ast::ItemKind::Enum(ref enum_def, ref generics) => {
                         self.expand_enum_def(cx, enum_def, &item.attrs, item.ident, generics)
                     }
+                    ast::ItemKind::Union(ref struct_def, ref generics) => {
+                        if self.supports_unions {
+                            self.expand_struct_def(cx, &struct_def, item.ident, generics)
+                        } else {
+                            cx.span_err(mitem.span,
+                                        "this trait cannot be derived for unions");
+                            return;
+                        }
+                    }
                     _ => {
                         cx.span_err(mitem.span,
-                                    "`derive` may only be applied to structs and enums");
+                                    "`derive` may only be applied to structs, enums and unions");
                         return;
                     }
                 };
diff --git a/src/test/compile-fail/union-derive.rs b/src/test/compile-fail/union-derive.rs
new file mode 100644
index 000000000000..0f78e96f640c
--- /dev/null
+++ b/src/test/compile-fail/union-derive.rs
@@ -0,0 +1,30 @@
+// 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.
+
+// Most traits cannot be derived for unions.
+
+#![feature(untagged_unions)]
+
+#[derive(
+    Clone, //~ ERROR this trait cannot be derived for unions
+    PartialEq, //~ ERROR this trait cannot be derived for unions
+    Eq, //~ ERROR this trait cannot be derived for unions
+    PartialOrd, //~ ERROR this trait cannot be derived for unions
+    Ord, //~ ERROR this trait cannot be derived for unions
+    Hash, //~ ERROR this trait cannot be derived for unions
+    Default, //~ ERROR this trait cannot be derived for unions
+    Debug, //~ ERROR this trait cannot be derived for unions
+)]
+union U {
+    a: u8,
+    b: u16,
+}
+
+fn main() {}
diff --git a/src/test/run-pass/union-derive.rs b/src/test/run-pass/union-derive.rs
new file mode 100644
index 000000000000..b71c23990a47
--- /dev/null
+++ b/src/test/run-pass/union-derive.rs
@@ -0,0 +1,31 @@
+// 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.
+
+// Some traits can be derived for unions.
+
+#![feature(untagged_unions)]
+
+#[derive(
+    Copy,
+)]
+union U {
+    a: u8,
+    b: u16,
+}
+
+impl Clone for U {
+    fn clone(&self) -> Self { *self }
+}
+
+fn main() {
+    let u = U { b: 0 };
+    let u1 = u;
+    let u2 = u.clone();
+}

From 5f975e969b46278669940aa60e5aea50ba588531 Mon Sep 17 00:00:00 2001
From: Vadim Petrochenkov 
Date: Fri, 26 Aug 2016 16:54:58 +0300
Subject: [PATCH 142/443] Support unions in borrow checker

Add some more tests
---
 src/librustc_borrowck/borrowck/fragments.rs   |  4 +
 .../borrowck/gather_loans/restrictions.rs     | 30 +++++-
 src/librustc_borrowck/borrowck/mod.rs         |  5 -
 src/librustc_borrowck/borrowck/move_data.rs   | 57 ++++++++++-
 src/test/compile-fail/union-borrow-nested.rs  | 44 +++++++++
 src/test/compile-fail/union-borrow.rs         | 97 +++++++++++++++++++
 src/test/compile-fail/union-move-assign.rs    | 42 ++++++++
 src/test/compile-fail/union-move.rs           | 96 ++++++++++++++++++
 src/test/compile-fail/union-uninitialized.rs  | 30 ++++++
 src/test/run-pass/union-basic.rs              |  6 +-
 src/test/run-pass/union-drop-assign.rs        | 44 +++++++++
 src/test/run-pass/union-transmute.rs          | 40 ++++++++
 12 files changed, 484 insertions(+), 11 deletions(-)
 create mode 100644 src/test/compile-fail/union-borrow-nested.rs
 create mode 100644 src/test/compile-fail/union-borrow.rs
 create mode 100644 src/test/compile-fail/union-move-assign.rs
 create mode 100644 src/test/compile-fail/union-move.rs
 create mode 100644 src/test/compile-fail/union-uninitialized.rs
 create mode 100644 src/test/run-pass/union-drop-assign.rs
 create mode 100644 src/test/run-pass/union-transmute.rs

diff --git a/src/librustc_borrowck/borrowck/fragments.rs b/src/librustc_borrowck/borrowck/fragments.rs
index a8993724e670..86f396d8982b 100644
--- a/src/librustc_borrowck/borrowck/fragments.rs
+++ b/src/librustc_borrowck/borrowck/fragments.rs
@@ -461,6 +461,10 @@ fn add_fragment_siblings_for_extension<'a, 'tcx>(this: &MoveData<'tcx>,
             }
         }
 
+        (&ty::TyUnion(..), None) => {
+            // Do nothing, all union fields are moved/assigned together.
+        }
+
         (&ty::TyEnum(def, _), ref enum_variant_info) => {
             let variant = match *enum_variant_info {
                 Some((vid, ref _lp2)) => def.variant_with_id(vid),
diff --git a/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs b/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs
index d08f792b30c1..6193157fa7b3 100644
--- a/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs
+++ b/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs
@@ -89,7 +89,7 @@ impl<'a, 'tcx> RestrictionsContext<'a, 'tcx> {
                 self.restrict(cmt_base)
             }
 
-            Categorization::Interior(cmt_base, i) => {
+            Categorization::Interior(cmt_base, interior) => {
                 // R-Field
                 //
                 // Overwriting the base would not change the type of
@@ -99,8 +99,34 @@ impl<'a, 'tcx> RestrictionsContext<'a, 'tcx> {
                     Categorization::Downcast(_, variant_id) => Some(variant_id),
                     _ => None
                 };
+                let interior = interior.cleaned();
+                let base_ty = cmt_base.ty;
                 let result = self.restrict(cmt_base);
-                self.extend(result, &cmt, LpInterior(opt_variant_id, i.cleaned()))
+                if let ty::TyUnion(ref adt_def, _) = base_ty.sty {
+                    match result {
+                        RestrictionResult::Safe => RestrictionResult::Safe,
+                        RestrictionResult::SafeIf(base_lp, mut base_vec) => {
+                            for field in &adt_def.struct_variant().fields {
+                                let field = InteriorKind::InteriorField(mc::NamedField(field.name));
+                                let field_ty = if field == interior {
+                                    cmt.ty
+                                } else {
+                                    self.bccx.tcx.types.err // Doesn't matter
+                                };
+                                let sibling_lp_kind = LpExtend(base_lp.clone(), cmt.mutbl,
+                                                               LpInterior(opt_variant_id, field));
+                                let sibling_lp = Rc::new(LoanPath::new(sibling_lp_kind, field_ty));
+                                base_vec.push(sibling_lp);
+                            }
+
+                            let lp = new_lp(LpExtend(base_lp, cmt.mutbl,
+                                                     LpInterior(opt_variant_id, interior)));
+                            RestrictionResult::SafeIf(lp, base_vec)
+                        }
+                    }
+                } else {
+                    self.extend(result, &cmt, LpInterior(opt_variant_id, interior))
+                }
             }
 
             Categorization::StaticItem => {
diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs
index 67152ed04ec1..f5e20285e0c1 100644
--- a/src/librustc_borrowck/borrowck/mod.rs
+++ b/src/librustc_borrowck/borrowck/mod.rs
@@ -477,8 +477,6 @@ impl<'a, 'tcx> LoanPath<'tcx> {
                     base.common(&base2).map(|x| {
                         let xd = x.depth();
                         if base.depth() == xd && base2.depth() == xd {
-                            assert_eq!(base.ty, base2.ty);
-                            assert_eq!(self.ty, other.ty);
                             LoanPath {
                                 kind: LpExtend(Rc::new(x), a, LpInterior(opt_variant_id, id)),
                                 ty: self.ty,
@@ -495,7 +493,6 @@ impl<'a, 'tcx> LoanPath<'tcx> {
             (_, &LpExtend(ref other, _, LpDeref(_))) => self.common(&other),
             (&LpVar(id), &LpVar(id2)) => {
                 if id == id2 {
-                    assert_eq!(self.ty, other.ty);
                     Some(LoanPath { kind: LpVar(id), ty: self.ty })
                 } else {
                     None
@@ -503,7 +500,6 @@ impl<'a, 'tcx> LoanPath<'tcx> {
             }
             (&LpUpvar(id), &LpUpvar(id2)) => {
                 if id == id2 {
-                    assert_eq!(self.ty, other.ty);
                     Some(LoanPath { kind: LpUpvar(id), ty: self.ty })
                 } else {
                     None
@@ -1136,7 +1132,6 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
                 out.push(')');
             }
 
-
             LpExtend(ref lp_base, _, LpInterior(_, InteriorField(fname))) => {
                 self.append_autoderefd_loan_path_to_string(&lp_base, out);
                 match fname {
diff --git a/src/librustc_borrowck/borrowck/move_data.rs b/src/librustc_borrowck/borrowck/move_data.rs
index c9822a4fee74..b13291b8419d 100644
--- a/src/librustc_borrowck/borrowck/move_data.rs
+++ b/src/librustc_borrowck/borrowck/move_data.rs
@@ -21,7 +21,8 @@ use rustc::middle::dataflow::DataFlowOperator;
 use rustc::middle::dataflow::KillFrom;
 use rustc::middle::expr_use_visitor as euv;
 use rustc::middle::expr_use_visitor::MutateMode;
-use rustc::ty::TyCtxt;
+use rustc::middle::mem_categorization as mc;
+use rustc::ty::{self, TyCtxt};
 use rustc::util::nodemap::{FnvHashMap, NodeSet};
 
 use std::cell::RefCell;
@@ -364,6 +365,32 @@ impl<'a, 'tcx> MoveData<'tcx> {
                     lp: Rc>,
                     id: ast::NodeId,
                     kind: MoveKind) {
+        // Moving one union field automatically moves all its fields.
+        if let LpExtend(ref base_lp, mutbl, LpInterior(opt_variant_id, interior)) = lp.kind {
+            if let ty::TyUnion(ref adt_def, _) = base_lp.ty.sty {
+                for field in &adt_def.struct_variant().fields {
+                    let field = InteriorKind::InteriorField(mc::NamedField(field.name));
+                    let field_ty = if field == interior {
+                        lp.ty
+                    } else {
+                        tcx.types.err // Doesn't matter
+                    };
+                    let sibling_lp_kind = LpExtend(base_lp.clone(), mutbl,
+                                                   LpInterior(opt_variant_id, field));
+                    let sibling_lp = Rc::new(LoanPath::new(sibling_lp_kind, field_ty));
+                    self.add_move_helper(tcx, sibling_lp, id, kind);
+                }
+                return;
+            }
+        }
+
+        self.add_move_helper(tcx, lp.clone(), id, kind);
+    }
+
+    fn add_move_helper(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                       lp: Rc>,
+                       id: ast::NodeId,
+                       kind: MoveKind) {
         debug!("add_move(lp={:?}, id={}, kind={:?})",
                lp,
                id,
@@ -393,6 +420,34 @@ impl<'a, 'tcx> MoveData<'tcx> {
                           span: Span,
                           assignee_id: ast::NodeId,
                           mode: euv::MutateMode) {
+        // Assigning to one union field automatically assigns to all its fields.
+        if let LpExtend(ref base_lp, mutbl, LpInterior(opt_variant_id, interior)) = lp.kind {
+            if let ty::TyUnion(ref adt_def, _) = base_lp.ty.sty {
+                for field in &adt_def.struct_variant().fields {
+                    let field = InteriorKind::InteriorField(mc::NamedField(field.name));
+                    let field_ty = if field == interior {
+                        lp.ty
+                    } else {
+                        tcx.types.err // Doesn't matter
+                    };
+                    let sibling_lp_kind = LpExtend(base_lp.clone(), mutbl,
+                                                   LpInterior(opt_variant_id, field));
+                    let sibling_lp = Rc::new(LoanPath::new(sibling_lp_kind, field_ty));
+                    self.add_assignment_helper(tcx, sibling_lp, assign_id, span, assignee_id, mode);
+                }
+                return;
+            }
+        }
+
+        self.add_assignment_helper(tcx, lp.clone(), assign_id, span, assignee_id, mode);
+    }
+
+    pub fn add_assignment_helper(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                                 lp: Rc>,
+                                 assign_id: ast::NodeId,
+                                 span: Span,
+                                 assignee_id: ast::NodeId,
+                                 mode: euv::MutateMode) {
         debug!("add_assignment(lp={:?}, assign_id={}, assignee_id={}",
                lp, assign_id, assignee_id);
 
diff --git a/src/test/compile-fail/union-borrow-nested.rs b/src/test/compile-fail/union-borrow-nested.rs
new file mode 100644
index 000000000000..19975d79b60b
--- /dev/null
+++ b/src/test/compile-fail/union-borrow-nested.rs
@@ -0,0 +1,44 @@
+// 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.
+
+// ignore-tidy-linelength
+
+#![feature(untagged_unions)]
+
+#[derive(Clone, Copy)]
+struct S {
+    a: u8,
+    b: u16,
+}
+
+union U {
+    s: S,
+    c: u32,
+}
+
+impl Clone for U {
+    fn clone(&self) -> Self { *self }
+}
+impl Copy for U {}
+
+fn main() {
+    unsafe {
+        {
+            let mut u = U { s: S { a: 0, b: 1 } };
+            let ra = &mut u.s.a;
+            let b = u.s.b; // OK
+        }
+        {
+            let mut u = U { s: S { a: 0, b: 1 } };
+            let ra = &mut u.s.a;
+            let b = u.c; //~ ERROR cannot use `u.c` because it was mutably borrowed
+        }
+    }
+}
diff --git a/src/test/compile-fail/union-borrow.rs b/src/test/compile-fail/union-borrow.rs
new file mode 100644
index 000000000000..e8989a3c2d49
--- /dev/null
+++ b/src/test/compile-fail/union-borrow.rs
@@ -0,0 +1,97 @@
+// 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.
+
+// ignore-tidy-linelength
+
+#![feature(untagged_unions)]
+
+union U {
+    a: u8,
+    b: u64,
+}
+
+impl Clone for U {
+    fn clone(&self) -> Self { *self }
+}
+impl Copy for U {}
+
+fn main() {
+    unsafe {
+        let mut u = U { b: 0 };
+        // Imm borrow, same field
+        {
+            let ra = &u.a;
+            let ra2 = &u.a; // OK
+        }
+        {
+            let ra = &u.a;
+            let a = u.a; // OK
+        }
+        {
+            let ra = &u.a;
+            let rma = &mut u.a; //~ ERROR cannot borrow `u.a` as mutable because it is also borrowed as immutable
+        }
+        {
+            let ra = &u.a;
+            u.a = 1; //~ ERROR cannot assign to `u.a` because it is borrowed
+        }
+        // Imm borrow, other field
+        {
+            let ra = &u.a;
+            let rb = &u.b; // OK
+        }
+        {
+            let ra = &u.a;
+            let b = u.b; // OK
+        }
+        {
+            let ra = &u.a;
+            let rmb = &mut u.b; //~ ERROR cannot borrow `u` (via `u.b`) as mutable because `u` is also borrowed as immutable (via `u.a`)
+        }
+        {
+            let ra = &u.a;
+            u.b = 1; //~ ERROR cannot assign to `u.b` because it is borrowed
+        }
+        // Mut borrow, same field
+        {
+            let rma = &mut u.a;
+            let ra = &u.a; //~ ERROR cannot borrow `u.a` as immutable because it is also borrowed as mutable
+        }
+        {
+            let ra = &mut u.a;
+            let a = u.a; //~ ERROR cannot use `u.a` because it was mutably borrowed
+        }
+        {
+            let rma = &mut u.a;
+            let rma2 = &mut u.a; //~ ERROR cannot borrow `u.a` as mutable more than once at a time
+        }
+        {
+            let rma = &mut u.a;
+            u.a = 1; //~ ERROR cannot assign to `u.a` because it is borrowed
+        }
+        // Mut borrow, other field
+        {
+            let rma = &mut u.a;
+            let rb = &u.b; //~ ERROR cannot borrow `u` (via `u.b`) as immutable because `u` is also borrowed as mutable (via `u.a`)
+        }
+        {
+            let ra = &mut u.a;
+            let b = u.b; //~ ERROR cannot use `u.b` because it was mutably borrowed
+        }
+        {
+            let rma = &mut u.a;
+            let rmb2 = &mut u.b; //~ ERROR cannot borrow `u` (via `u.b`) as mutable more than once at a time
+        }
+        {
+            let rma = &mut u.a;
+            u.b = 1; //~ ERROR cannot assign to `u.b` because it is borrowed
+        }
+    }
+}
diff --git a/src/test/compile-fail/union-move-assign.rs b/src/test/compile-fail/union-move-assign.rs
new file mode 100644
index 000000000000..d4d7bc6b0f7c
--- /dev/null
+++ b/src/test/compile-fail/union-move-assign.rs
@@ -0,0 +1,42 @@
+// 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.
+
+#![feature(untagged_unions)]
+
+// Non-copy
+struct A;
+struct B;
+
+union U {
+    a: A,
+    b: B,
+}
+
+fn main() {
+    unsafe {
+        {
+            let mut u = U { a: A };
+            let a = u.a;
+            let a = u.a; //~ ERROR use of moved value: `u.a`
+        }
+        {
+            let mut u = U { a: A };
+            let a = u.a;
+            u.a = A;
+            let a = u.a; // OK
+        }
+        {
+            let mut u = U { a: A };
+            let a = u.a;
+            u.b = B;
+            let a = u.a; // OK
+        }
+    }
+}
diff --git a/src/test/compile-fail/union-move.rs b/src/test/compile-fail/union-move.rs
new file mode 100644
index 000000000000..5320244cf43b
--- /dev/null
+++ b/src/test/compile-fail/union-move.rs
@@ -0,0 +1,96 @@
+// 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.
+
+#![feature(untagged_unions)]
+
+#[derive(Clone, Copy)]
+struct Copy;
+struct NonCopy;
+
+union Unn {
+    n1: NonCopy,
+    n2: NonCopy,
+}
+union Ucc {
+    c1: Copy,
+    c2: Copy,
+}
+union Ucn {
+    c: Copy,
+    n: NonCopy,
+}
+
+fn main() {
+    unsafe {
+        // 2 NonCopy
+        {
+            let mut u = Unn { n1: NonCopy };
+            let a = u.n1;
+            let a = u.n1; //~ ERROR use of moved value: `u.n1`
+        }
+        {
+            let mut u = Unn { n1: NonCopy };
+            let a = u.n1;
+            let a = u; //~ ERROR use of partially moved value: `u`
+        }
+        {
+            let mut u = Unn { n1: NonCopy };
+            let a = u.n1;
+            let a = u.n2; //~ ERROR use of moved value: `u.n2`
+        }
+        // 2 Copy
+        {
+            let mut u = Ucc { c1: Copy };
+            let a = u.c1;
+            let a = u.c1; // OK
+        }
+        {
+            let mut u = Ucc { c1: Copy };
+            let a = u.c1;
+            let a = u; // OK
+        }
+        {
+            let mut u = Ucc { c1: Copy };
+            let a = u.c1;
+            let a = u.c2; // OK
+        }
+        // 1 Copy, 1 NonCopy
+        {
+            let mut u = Ucn { c: Copy };
+            let a = u.c;
+            let a = u.c; // OK
+        }
+        {
+            let mut u = Ucn { c: Copy };
+            let a = u.n;
+            let a = u.n; //~ ERROR use of moved value: `u.n`
+        }
+        {
+            let mut u = Ucn { c: Copy };
+            let a = u.n;
+            let a = u.c; //~ ERROR use of moved value: `u.c`
+        }
+        {
+            let mut u = Ucn { c: Copy };
+            let a = u.c;
+            let a = u.n; // OK
+        }
+        {
+            let mut u = Ucn { c: Copy };
+            let a = u.c;
+            let a = u; // OK
+        }
+        {
+            let mut u = Ucn { c: Copy };
+            let a = u.n;
+            let a = u; //~ ERROR use of partially moved value: `u`
+        }
+    }
+}
diff --git a/src/test/compile-fail/union-uninitialized.rs b/src/test/compile-fail/union-uninitialized.rs
new file mode 100644
index 000000000000..36e062f8464e
--- /dev/null
+++ b/src/test/compile-fail/union-uninitialized.rs
@@ -0,0 +1,30 @@
+// 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.
+
+#![feature(untagged_unions)]
+
+struct S {
+    a: u8,
+}
+
+union U {
+    a: u8,
+}
+
+fn main() {
+    unsafe {
+        let mut s: S;
+        let mut u: U;
+        s.a = 0;
+        u.a = 0;
+        let sa = s.a; //~ ERROR use of possibly uninitialized variable: `s.a`
+        let ua = u.a; //~ ERROR use of possibly uninitialized variable: `u.a`
+    }
+}
diff --git a/src/test/run-pass/union-basic.rs b/src/test/run-pass/union-basic.rs
index a00bd73115a1..1651aa901b96 100644
--- a/src/test/run-pass/union-basic.rs
+++ b/src/test/run-pass/union-basic.rs
@@ -52,8 +52,8 @@ fn main() {
     unsafe {
         assert_eq!(w.a, 0);
         assert_eq!(w.b, 0);
-        // w.a = 1;
-        assert_eq!(w.a, 0);
-        assert_eq!(w.b, 0);
+        w.a = 1;
+        assert_eq!(w.a, 1);
+        assert_eq!(w.b, 1);
     }
 }
diff --git a/src/test/run-pass/union-drop-assign.rs b/src/test/run-pass/union-drop-assign.rs
new file mode 100644
index 000000000000..0da68e43f32a
--- /dev/null
+++ b/src/test/run-pass/union-drop-assign.rs
@@ -0,0 +1,44 @@
+// 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.
+
+// Drop works for union itself.
+
+#![feature(untagged_unions)]
+
+struct S;
+
+union U {
+    a: S
+}
+
+impl Drop for S {
+    fn drop(&mut self) {
+        unsafe { CHECK += 10; }
+    }
+}
+
+impl Drop for U {
+    fn drop(&mut self) {
+        unsafe { CHECK += 1; }
+    }
+}
+
+static mut CHECK: u8 = 0;
+
+fn main() {
+    unsafe {
+        let mut u = U { a: S };
+        assert_eq!(CHECK, 0);
+        u = U { a: S };
+        assert_eq!(CHECK, 1); // union itself is assigned, union is dropped, field is not dropped
+        u.a = S;
+        assert_eq!(CHECK, 11); // union field is assigned, field is dropped
+    }
+}
diff --git a/src/test/run-pass/union-transmute.rs b/src/test/run-pass/union-transmute.rs
new file mode 100644
index 000000000000..4eb66268ab8e
--- /dev/null
+++ b/src/test/run-pass/union-transmute.rs
@@ -0,0 +1,40 @@
+// 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.
+
+#![feature(core_float)]
+#![feature(float_extras)]
+#![feature(untagged_unions)]
+
+extern crate core;
+use core::num::Float;
+
+union U {
+    a: (u8, u8),
+    b: u16,
+}
+
+union W {
+    a: u32,
+    b: f32,
+}
+
+fn main() {
+    unsafe {
+        let mut u = U { a: (1, 1) };
+        assert_eq!(u.b, (1 << 8) + 1);
+        u.b = (2 << 8) + 2;
+        assert_eq!(u.a, (2, 2));
+
+        let mut w = W { a: 0b0_11111111_00000000000000000000000 };
+        assert_eq!(w.b, f32::infinity());
+        w.b = f32::neg_infinity();
+        assert_eq!(w.a, 0b1_11111111_00000000000000000000000);
+    }
+}

From e67c2282afa3c527da49618b928280564e92868f Mon Sep 17 00:00:00 2001
From: Vadim Petrochenkov 
Date: Fri, 26 Aug 2016 19:23:42 +0300
Subject: [PATCH 143/443] Fix rebase, fix some tests

---
 src/librustc_trans/adt.rs                      |  4 ++--
 src/librustc_trans/debuginfo/mod.rs            |  2 +-
 src/librustc_trans/glue.rs                     |  2 +-
 src/test/compile-fail/deriving-non-type.rs     | 18 +++++++++---------
 src/test/debuginfo/union-smoke.rs              | 17 +++++++++--------
 .../incremental/struct_change_field_name.rs    |  2 +-
 6 files changed, 23 insertions(+), 22 deletions(-)

diff --git a/src/librustc_trans/adt.rs b/src/librustc_trans/adt.rs
index 7fd02ab82a3f..15a9d58c9b57 100644
--- a/src/librustc_trans/adt.rs
+++ b/src/librustc_trans/adt.rs
@@ -749,12 +749,12 @@ fn generic_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
             };
             match name {
                 None => {
-                    TypeContext::direct(Type::struct_(cx, &[fill_ty], un.packed))
+                    Type::struct_(cx, &[fill_ty], un.packed)
                 }
                 Some(name) => {
                     let mut llty = Type::named_struct(cx, name);
                     llty.set_struct_body(&[fill_ty], un.packed);
-                    TypeContext::direct(llty)
+                    llty
                 }
             }
         }
diff --git a/src/librustc_trans/debuginfo/mod.rs b/src/librustc_trans/debuginfo/mod.rs
index a3a7a79fb58b..20a33498475a 100644
--- a/src/librustc_trans/debuginfo/mod.rs
+++ b/src/librustc_trans/debuginfo/mod.rs
@@ -421,7 +421,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                 // Only "class" methods are generally understood by LLVM,
                 // so avoid methods on other types (e.g. `<*mut T>::null`).
                 match impl_self_ty.sty {
-                    ty::TyStruct(..) | ty::TyEnum(..) => {
+                    ty::TyStruct(..) | ty::TyUnion(..) | ty::TyEnum(..) => {
                         Some(type_metadata(cx, impl_self_ty, syntax_pos::DUMMY_SP))
                     }
                     _ => None
diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs
index 0d62a63b89fc..bb77db8fd694 100644
--- a/src/librustc_trans/glue.rs
+++ b/src/librustc_trans/glue.rs
@@ -489,7 +489,7 @@ fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, g: DropGlueK
         }
         ty::TyStruct(def, _) | ty::TyEnum(def, _)
                 if def.dtor_kind().is_present() && !skip_dtor => {
-            trans_struct_drop(bcx, t, v0)
+            trans_struct_drop(bcx, t, v0, false)
         }
         ty::TyUnion(def, _) => {
             if def.dtor_kind().is_present() && !skip_dtor {
diff --git a/src/test/compile-fail/deriving-non-type.rs b/src/test/compile-fail/deriving-non-type.rs
index 5b215f3ccd96..84dd22435b88 100644
--- a/src/test/compile-fail/deriving-non-type.rs
+++ b/src/test/compile-fail/deriving-non-type.rs
@@ -12,29 +12,29 @@
 
 struct S;
 
-#[derive(PartialEq)] //~ ERROR: `derive` may only be applied to structs and enums
+#[derive(PartialEq)] //~ ERROR: `derive` may only be applied to structs, enums and unions
 trait T { }
 
-#[derive(PartialEq)] //~ ERROR: `derive` may only be applied to structs and enums
+#[derive(PartialEq)] //~ ERROR: `derive` may only be applied to structs, enums and unions
 impl S { }
 
-#[derive(PartialEq)] //~ ERROR: `derive` may only be applied to structs and enums
+#[derive(PartialEq)] //~ ERROR: `derive` may only be applied to structs, enums and unions
 impl T for S { }
 
-#[derive(PartialEq)] //~ ERROR: `derive` may only be applied to structs and enums
+#[derive(PartialEq)] //~ ERROR: `derive` may only be applied to structs, enums and unions
 static s: usize = 0;
 
-#[derive(PartialEq)] //~ ERROR: `derive` may only be applied to structs and enums
+#[derive(PartialEq)] //~ ERROR: `derive` may only be applied to structs, enums and unions
 const c: usize = 0;
 
-#[derive(PartialEq)] //~ ERROR: `derive` may only be applied to structs and enums
+#[derive(PartialEq)] //~ ERROR: `derive` may only be applied to structs, enums and unions
 mod m { }
 
-#[derive(PartialEq)] //~ ERROR: `derive` may only be applied to structs and enums
+#[derive(PartialEq)] //~ ERROR: `derive` may only be applied to structs, enums and unions
 extern "C" { }
 
-#[derive(PartialEq)] //~ ERROR: `derive` may only be applied to structs and enums
+#[derive(PartialEq)] //~ ERROR: `derive` may only be applied to structs, enums and unions
 type A = usize;
 
-#[derive(PartialEq)] //~ ERROR: `derive` may only be applied to structs and enums
+#[derive(PartialEq)] //~ ERROR: `derive` may only be applied to structs, enums and unions
 fn main() { }
diff --git a/src/test/debuginfo/union-smoke.rs b/src/test/debuginfo/union-smoke.rs
index 11ee5031ca77..17dea300ff9d 100644
--- a/src/test/debuginfo/union-smoke.rs
+++ b/src/test/debuginfo/union-smoke.rs
@@ -16,17 +16,17 @@
 
 // gdb-command:run
 // gdb-command:print u
-// gdb-check:$1 = {a = 11 '\v', b = 11}
+// gdb-check:$1 = {a = {__0 = 2 '\002', __1 = 2 '\002'}, b = 514}
 // gdb-command:print union_smoke::SU
-// gdb-check:$2 = {a = 10 '\n', b = 10}
+// gdb-check:$2 = {a = {__0 = 1 '\001', __1 = 1 '\001'}, b = 257}
 
 // === LLDB TESTS ==================================================================================
 
 // lldb-command:run
 // lldb-command:print a
-// lldb-check:[...]$0 = {a = 11 '\v', b = 11}
+// lldb-check:[...]$0 = {a = {__0 = 2 '\002', __1 = 2 '\002'}, b = 514}
 // lldb-command:print union_smoke::SU
-// lldb-check:[...]$1 = {a = 10 '\n', b = 10}
+// lldb-check:[...]$1 = {a = {__0 = 1 '\001', __1 = 1 '\001'}, b = 257}
 
 #![allow(unused)]
 #![feature(omit_gdb_pretty_printer_section)]
@@ -34,14 +34,15 @@
 #![feature(untagged_unions)]
 
 union U {
-    a: u8,
-    b: u64,
+    a: (u8, u8),
+    b: u16,
 }
 
-static SU: U = U { a: 10 };
+static mut SU: U = U { a: (1, 1) };
 
 fn main() {
-    let u = U { b: 11 };
+    let u = U { b: (2 << 8) + 2 };
+    unsafe { SU = U { a: (1, 1) } }
 
     zzz(); // #break
 }
diff --git a/src/test/incremental/struct_change_field_name.rs b/src/test/incremental/struct_change_field_name.rs
index ba469c62002e..c27294442e7a 100644
--- a/src/test/incremental/struct_change_field_name.rs
+++ b/src/test/incremental/struct_change_field_name.rs
@@ -37,7 +37,7 @@ pub struct Y {
 #[rustc_dirty(label="TypeckItemBody", cfg="cfail2")]
 pub fn use_X() -> u32 {
     let x: X = X { x: 22 };
-    //[cfail2]~^ ERROR structure `X` has no field named `x`
+    //[cfail2]~^ ERROR struct `X` has no field named `x`
     x.x as u32
     //[cfail2]~^ ERROR attempted access of field `x`
 }

From 93067ca089ea570e4e2bdfc456958c81a4d1e092 Mon Sep 17 00:00:00 2001
From: Vadim Petrochenkov 
Date: Fri, 26 Aug 2016 19:23:42 +0300
Subject: [PATCH 144/443] Address comments and add requested tests

---
 src/librustc/middle/expr_use_visitor.rs       | 43 +++++-----
 src/librustc/ty/mod.rs                        |  2 +-
 .../borrowck/gather_loans/restrictions.rs     |  1 +
 src/librustc_borrowck/borrowck/move_data.rs   | 12 +--
 src/librustc_privacy/lib.rs                   | 23 +++---
 src/librustc_trans/glue.rs                    |  8 +-
 src/librustc_typeck/check/_match.rs           |  9 +--
 src/rt/rust_test_helpers.c                    | 21 +++++
 .../borrowck-union-borrow-nested.rs}          |  0
 .../borrowck-union-borrow.rs}                 |  0
 .../borrowck-union-move-assign.rs}            |  0
 .../borrowck-union-move.rs}                   |  0
 .../borrowck-union-uninitialized.rs}          |  0
 .../privacy/union-field-privacy-1.rs          | 30 +++++++
 .../privacy/union-field-privacy-2.rs          | 28 +++++++
 .../{ => union}/union-const-eval.rs           |  0
 .../{ => union}/union-const-pat.rs            |  0
 src/test/compile-fail/union/union-copy.rs     | 26 ++++++
 .../compile-fail/{ => union}/union-derive.rs  |  0
 .../compile-fail/{ => union}/union-empty.rs   |  0
 .../compile-fail/union/union-feature-gate.rs  | 15 ++++
 .../compile-fail/{ => union}/union-fields.rs  | 11 +--
 src/test/compile-fail/union/union-generic.rs  | 24 ++++++
 .../{ => union}/union-nonrepresentable.rs     |  0
 src/test/compile-fail/union/union-repr-c.rs   | 29 +++++++
 .../compile-fail/union/union-suggest-field.rs | 29 +++++++
 .../compile-fail/{ => union}/union-unsafe.rs  |  7 +-
 .../compile-fail/{ => union}/union-unsized.rs |  6 ++
 .../union-with-drop-fields-lint.rs            |  0
 .../run-pass/{ => union}/auxiliary/union.rs   |  0
 .../run-pass/{ => union}/union-backcomp.rs    |  4 +
 src/test/run-pass/{ => union}/union-basic.rs  |  0
 src/test/run-pass/union/union-c-interop.rs    | 47 +++++++++++
 .../run-pass/{ => union}/union-const-trans.rs |  0
 src/test/run-pass/{ => union}/union-derive.rs |  0
 .../run-pass/{ => union}/union-drop-assign.rs |  0
 src/test/run-pass/{ => union}/union-drop.rs   |  0
 src/test/run-pass/union/union-generic.rs      | 43 ++++++++++
 .../union/union-inherent-method.rs}           | 13 +--
 src/test/run-pass/union/union-macro.rs        | 33 ++++++++
 src/test/run-pass/union/union-overwrite.rs    | 80 +++++++++++++++++++
 src/test/run-pass/{ => union}/union-packed.rs | 30 +++++++
 .../{ => union}/union-pat-refutability.rs     |  0
 src/test/run-pass/union/union-trait-impl.rs   | 27 +++++++
 .../run-pass/{ => union}/union-transmute.rs   |  0
 .../union/union-with-drop-fields-lint.rs      | 42 ++++++++++
 src/test/run-pass/{ => union}/union-xcrate.rs |  0
 47 files changed, 582 insertions(+), 61 deletions(-)
 rename src/test/compile-fail/{union-borrow-nested.rs => borrowck/borrowck-union-borrow-nested.rs} (100%)
 rename src/test/compile-fail/{union-borrow.rs => borrowck/borrowck-union-borrow.rs} (100%)
 rename src/test/compile-fail/{union-move-assign.rs => borrowck/borrowck-union-move-assign.rs} (100%)
 rename src/test/compile-fail/{union-move.rs => borrowck/borrowck-union-move.rs} (100%)
 rename src/test/compile-fail/{union-uninitialized.rs => borrowck/borrowck-union-uninitialized.rs} (100%)
 create mode 100644 src/test/compile-fail/privacy/union-field-privacy-1.rs
 create mode 100644 src/test/compile-fail/privacy/union-field-privacy-2.rs
 rename src/test/compile-fail/{ => union}/union-const-eval.rs (100%)
 rename src/test/compile-fail/{ => union}/union-const-pat.rs (100%)
 create mode 100644 src/test/compile-fail/union/union-copy.rs
 rename src/test/compile-fail/{ => union}/union-derive.rs (100%)
 rename src/test/compile-fail/{ => union}/union-empty.rs (100%)
 create mode 100644 src/test/compile-fail/union/union-feature-gate.rs
 rename src/test/compile-fail/{ => union}/union-fields.rs (72%)
 create mode 100644 src/test/compile-fail/union/union-generic.rs
 rename src/test/compile-fail/{ => union}/union-nonrepresentable.rs (100%)
 create mode 100644 src/test/compile-fail/union/union-repr-c.rs
 create mode 100644 src/test/compile-fail/union/union-suggest-field.rs
 rename src/test/compile-fail/{ => union}/union-unsafe.rs (77%)
 rename src/test/compile-fail/{ => union}/union-unsized.rs (83%)
 rename src/test/compile-fail/{ => union}/union-with-drop-fields-lint.rs (100%)
 rename src/test/run-pass/{ => union}/auxiliary/union.rs (100%)
 rename src/test/run-pass/{ => union}/union-backcomp.rs (95%)
 rename src/test/run-pass/{ => union}/union-basic.rs (100%)
 create mode 100644 src/test/run-pass/union/union-c-interop.rs
 rename src/test/run-pass/{ => union}/union-const-trans.rs (100%)
 rename src/test/run-pass/{ => union}/union-derive.rs (100%)
 rename src/test/run-pass/{ => union}/union-drop-assign.rs (100%)
 rename src/test/run-pass/{ => union}/union-drop.rs (100%)
 create mode 100644 src/test/run-pass/union/union-generic.rs
 rename src/test/{compile-fail/union-field-privacy.rs => run-pass/union/union-inherent-method.rs} (78%)
 create mode 100644 src/test/run-pass/union/union-macro.rs
 create mode 100644 src/test/run-pass/union/union-overwrite.rs
 rename src/test/run-pass/{ => union}/union-packed.rs (81%)
 rename src/test/run-pass/{ => union}/union-pat-refutability.rs (100%)
 create mode 100644 src/test/run-pass/union/union-trait-impl.rs
 rename src/test/run-pass/{ => union}/union-transmute.rs (100%)
 create mode 100644 src/test/run-pass/union/union-with-drop-fields-lint.rs
 rename src/test/run-pass/{ => union}/union-xcrate.rs (100%)

diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs
index a6835802f1cf..541aeeb7d8dd 100644
--- a/src/librustc/middle/expr_use_visitor.rs
+++ b/src/librustc/middle/expr_use_visitor.rs
@@ -671,31 +671,28 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
 
         // Select just those fields of the `with`
         // expression that will actually be used
-        match with_cmt.ty.sty {
-            ty::TyStruct(def, substs) => {
-                // Consume those fields of the with expression that are needed.
-                for with_field in &def.struct_variant().fields {
-                    if !contains_field_named(with_field, fields) {
-                        let cmt_field = self.mc.cat_field(
-                            &*with_expr,
-                            with_cmt.clone(),
-                            with_field.name,
-                            with_field.ty(self.tcx(), substs)
-                        );
-                        self.delegate_consume(with_expr.id, with_expr.span, cmt_field);
-                    }
+        if let ty::TyStruct(def, substs) = with_cmt.ty.sty {
+            // Consume those fields of the with expression that are needed.
+            for with_field in &def.struct_variant().fields {
+                if !contains_field_named(with_field, fields) {
+                    let cmt_field = self.mc.cat_field(
+                        &*with_expr,
+                        with_cmt.clone(),
+                        with_field.name,
+                        with_field.ty(self.tcx(), substs)
+                    );
+                    self.delegate_consume(with_expr.id, with_expr.span, cmt_field);
                 }
             }
-            _ => {
-                // the base expression should always evaluate to a
-                // struct; however, when EUV is run during typeck, it
-                // may not. This will generate an error earlier in typeck,
-                // so we can just ignore it.
-                if !self.tcx().sess.has_errors() {
-                    span_bug!(
-                        with_expr.span,
-                        "with expression doesn't evaluate to a struct");
-                }
+        } else {
+            // the base expression should always evaluate to a
+            // struct; however, when EUV is run during typeck, it
+            // may not. This will generate an error earlier in typeck,
+            // so we can just ignore it.
+            if !self.tcx().sess.has_errors() {
+                span_bug!(
+                    with_expr.span,
+                    "with expression doesn't evaluate to a struct");
             }
         }
 
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index ee2188e8e112..e88f72f2d84b 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -1423,7 +1423,7 @@ bitflags! {
         const IS_PHANTOM_DATA     = 1 << 3,
         const IS_SIMD             = 1 << 4,
         const IS_FUNDAMENTAL      = 1 << 5,
-        const IS_UNION            = 1 << 7,
+        const IS_UNION            = 1 << 6,
     }
 }
 
diff --git a/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs b/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs
index 6193157fa7b3..c08dc9330b8f 100644
--- a/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs
+++ b/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs
@@ -102,6 +102,7 @@ impl<'a, 'tcx> RestrictionsContext<'a, 'tcx> {
                 let interior = interior.cleaned();
                 let base_ty = cmt_base.ty;
                 let result = self.restrict(cmt_base);
+                // Borrowing one union field automatically borrows all its fields.
                 if let ty::TyUnion(ref adt_def, _) = base_ty.sty {
                     match result {
                         RestrictionResult::Safe => RestrictionResult::Safe,
diff --git a/src/librustc_borrowck/borrowck/move_data.rs b/src/librustc_borrowck/borrowck/move_data.rs
index b13291b8419d..236a1a2835c2 100644
--- a/src/librustc_borrowck/borrowck/move_data.rs
+++ b/src/librustc_borrowck/borrowck/move_data.rs
@@ -442,12 +442,12 @@ impl<'a, 'tcx> MoveData<'tcx> {
         self.add_assignment_helper(tcx, lp.clone(), assign_id, span, assignee_id, mode);
     }
 
-    pub fn add_assignment_helper(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                 lp: Rc>,
-                                 assign_id: ast::NodeId,
-                                 span: Span,
-                                 assignee_id: ast::NodeId,
-                                 mode: euv::MutateMode) {
+    fn add_assignment_helper(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                             lp: Rc>,
+                             assign_id: ast::NodeId,
+                             span: Span,
+                             assignee_id: ast::NodeId,
+                             mode: euv::MutateMode) {
         debug!("add_assignment(lp={:?}, assign_id={}, assignee_id={}",
                lp, assign_id, assignee_id);
 
diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs
index 6b291c693072..179863c16fff 100644
--- a/src/librustc_privacy/lib.rs
+++ b/src/librustc_privacy/lib.rs
@@ -429,19 +429,24 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> {
                 let method = self.tcx.tables.borrow().method_map[&method_call];
                 self.check_method(expr.span, method.def_id);
             }
-            hir::ExprStruct(_, ref fields, _) => {
+            hir::ExprStruct(_, ref expr_fields, _) => {
                 let adt = self.tcx.expr_ty(expr).ty_adt_def().unwrap();
                 let variant = adt.variant_of_def(self.tcx.expect_def(expr.id));
                 // RFC 736: ensure all unmentioned fields are visible.
                 // Rather than computing the set of unmentioned fields
-                // (i.e. `all_fields - fields`), just check them all.
-                for field in variant.fields.iter() {
-                    let span = if let Some(f) = fields.iter().find(|f| f.name.node == field.name) {
-                        f.span
-                    } else {
-                        expr.span
-                    };
-                    self.check_field(span, adt, field);
+                // (i.e. `all_fields - fields`), just check them all,
+                // unless the ADT is a union, then unmentioned fields
+                // are not checked.
+                if adt.adt_kind() == ty::AdtKind::Union {
+                    for expr_field in expr_fields {
+                        self.check_field(expr.span, adt, variant.field_named(expr_field.name.node));
+                    }
+                } else {
+                    for field in &variant.fields {
+                        let expr_field = expr_fields.iter().find(|f| f.name.node == field.name);
+                        let span = if let Some(f) = expr_field { f.span } else { expr.span };
+                        self.check_field(span, adt, field);
+                    }
                 }
             }
             hir::ExprPath(..) => {
diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs
index bb77db8fd694..34c92f334d0a 100644
--- a/src/librustc_trans/glue.rs
+++ b/src/librustc_trans/glue.rs
@@ -265,13 +265,13 @@ pub fn implement_drop_glue<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     fcx.finish(bcx, DebugLoc::None);
 }
 
-fn trans_struct_drop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
+fn trans_custom_dtor<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                                  t: Ty<'tcx>,
                                  v0: ValueRef,
                                  shallow_drop: bool)
                                  -> Block<'blk, 'tcx>
 {
-    debug!("trans_struct_drop t: {}", t);
+    debug!("trans_custom_dtor t: {}", t);
     let tcx = bcx.tcx();
     let mut bcx = bcx;
 
@@ -489,11 +489,11 @@ fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, g: DropGlueK
         }
         ty::TyStruct(def, _) | ty::TyEnum(def, _)
                 if def.dtor_kind().is_present() && !skip_dtor => {
-            trans_struct_drop(bcx, t, v0, false)
+            trans_custom_dtor(bcx, t, v0, false)
         }
         ty::TyUnion(def, _) => {
             if def.dtor_kind().is_present() && !skip_dtor {
-                trans_struct_drop(bcx, t, v0, true)
+                trans_custom_dtor(bcx, t, v0, true)
             } else {
                 bcx
             }
diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index 5c19fa2a66cf..12fce4b928e0 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -718,12 +718,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
         // Report an error if incorrect number of the fields were specified.
         if kind_name == "union" {
-            if fields.len() > 1 {
-                tcx.sess.span_err(span, "union patterns can have at most one field");
+            if fields.len() != 1 {
+                tcx.sess.span_err(span, "union patterns should have exactly one field");
             }
-            if fields.is_empty() && !etc {
-                tcx.sess.span_err(span, "union patterns without `..` \
-                                         should have at least one field");
+            if etc {
+                tcx.sess.span_err(span, "`..` cannot be used in union patterns");
             }
         } else if !etc {
             for field in variant.fields
diff --git a/src/rt/rust_test_helpers.c b/src/rt/rust_test_helpers.c
index d2ebdcca80cf..7a04d377608d 100644
--- a/src/rt/rust_test_helpers.c
+++ b/src/rt/rust_test_helpers.c
@@ -247,3 +247,24 @@ double rust_interesting_average(uint64_t n, ...) {
 int32_t rust_int8_to_int32(int8_t x) {
     return (int32_t)x;
 }
+
+typedef union LARGE_INTEGER {
+  struct {
+    uint32_t LowPart;
+    uint32_t HighPart;
+  };
+  struct {
+    uint32_t LowPart;
+    uint32_t HighPart;
+  } u;
+  uint64_t QuadPart;
+} LARGE_INTEGER;
+
+LARGE_INTEGER increment_all_parts(LARGE_INTEGER li) {
+    li.LowPart += 1;
+    li.HighPart += 1;
+    li.u.LowPart += 1;
+    li.u.HighPart += 1;
+    li.QuadPart += 1;
+    return li;
+}
diff --git a/src/test/compile-fail/union-borrow-nested.rs b/src/test/compile-fail/borrowck/borrowck-union-borrow-nested.rs
similarity index 100%
rename from src/test/compile-fail/union-borrow-nested.rs
rename to src/test/compile-fail/borrowck/borrowck-union-borrow-nested.rs
diff --git a/src/test/compile-fail/union-borrow.rs b/src/test/compile-fail/borrowck/borrowck-union-borrow.rs
similarity index 100%
rename from src/test/compile-fail/union-borrow.rs
rename to src/test/compile-fail/borrowck/borrowck-union-borrow.rs
diff --git a/src/test/compile-fail/union-move-assign.rs b/src/test/compile-fail/borrowck/borrowck-union-move-assign.rs
similarity index 100%
rename from src/test/compile-fail/union-move-assign.rs
rename to src/test/compile-fail/borrowck/borrowck-union-move-assign.rs
diff --git a/src/test/compile-fail/union-move.rs b/src/test/compile-fail/borrowck/borrowck-union-move.rs
similarity index 100%
rename from src/test/compile-fail/union-move.rs
rename to src/test/compile-fail/borrowck/borrowck-union-move.rs
diff --git a/src/test/compile-fail/union-uninitialized.rs b/src/test/compile-fail/borrowck/borrowck-union-uninitialized.rs
similarity index 100%
rename from src/test/compile-fail/union-uninitialized.rs
rename to src/test/compile-fail/borrowck/borrowck-union-uninitialized.rs
diff --git a/src/test/compile-fail/privacy/union-field-privacy-1.rs b/src/test/compile-fail/privacy/union-field-privacy-1.rs
new file mode 100644
index 000000000000..4924fabafb0a
--- /dev/null
+++ b/src/test/compile-fail/privacy/union-field-privacy-1.rs
@@ -0,0 +1,30 @@
+// 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.
+
+#![feature(pub_restricted)]
+#![feature(untagged_unions)]
+
+mod m {
+    pub union U {
+        pub a: u8,
+        pub(super) b: u8,
+        c: u8,
+    }
+}
+
+fn main() {
+    let u = m::U { a: 0 }; // OK
+    let u = m::U { b: 0 }; // OK
+    let u = m::U { c: 0 }; //~ ERROR field `c` of union `m::U` is private
+
+    let m::U { a } = u; // OK
+    let m::U { b } = u; // OK
+    let m::U { c } = u; //~ ERROR field `c` of union `m::U` is private
+}
diff --git a/src/test/compile-fail/privacy/union-field-privacy-2.rs b/src/test/compile-fail/privacy/union-field-privacy-2.rs
new file mode 100644
index 000000000000..7151538f4125
--- /dev/null
+++ b/src/test/compile-fail/privacy/union-field-privacy-2.rs
@@ -0,0 +1,28 @@
+// 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.
+
+#![feature(pub_restricted)]
+#![feature(untagged_unions)]
+
+mod m {
+    pub union U {
+        pub a: u8,
+        pub(super) b: u8,
+        c: u8,
+    }
+}
+
+fn main() {
+    let u = m::U { a: 10 };
+
+    let a = u.a; // OK
+    let b = u.b; // OK
+    let c = u.c; //~ ERROR field `c` of struct `m::U` is private
+}
diff --git a/src/test/compile-fail/union-const-eval.rs b/src/test/compile-fail/union/union-const-eval.rs
similarity index 100%
rename from src/test/compile-fail/union-const-eval.rs
rename to src/test/compile-fail/union/union-const-eval.rs
diff --git a/src/test/compile-fail/union-const-pat.rs b/src/test/compile-fail/union/union-const-pat.rs
similarity index 100%
rename from src/test/compile-fail/union-const-pat.rs
rename to src/test/compile-fail/union/union-const-pat.rs
diff --git a/src/test/compile-fail/union/union-copy.rs b/src/test/compile-fail/union/union-copy.rs
new file mode 100644
index 000000000000..6e08ae0074d4
--- /dev/null
+++ b/src/test/compile-fail/union/union-copy.rs
@@ -0,0 +1,26 @@
+// 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.
+
+#![feature(untagged_unions)]
+
+union U {
+    a: u8
+}
+
+union W {
+    a: String
+}
+
+impl Clone for U { fn clone(&self) { panic!(); } }
+impl Clone for W { fn clone(&self) { panic!(); } }
+impl Copy for U {} // OK
+impl Copy for W {} //~ ERROR the trait `Copy` may not be implemented for this type
+
+fn main() {}
diff --git a/src/test/compile-fail/union-derive.rs b/src/test/compile-fail/union/union-derive.rs
similarity index 100%
rename from src/test/compile-fail/union-derive.rs
rename to src/test/compile-fail/union/union-derive.rs
diff --git a/src/test/compile-fail/union-empty.rs b/src/test/compile-fail/union/union-empty.rs
similarity index 100%
rename from src/test/compile-fail/union-empty.rs
rename to src/test/compile-fail/union/union-empty.rs
diff --git a/src/test/compile-fail/union/union-feature-gate.rs b/src/test/compile-fail/union/union-feature-gate.rs
new file mode 100644
index 000000000000..abfc4d909218
--- /dev/null
+++ b/src/test/compile-fail/union/union-feature-gate.rs
@@ -0,0 +1,15 @@
+// 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.
+
+union U { //~ ERROR unions are unstable and possibly buggy
+    a: u8,
+}
+
+fn main() {}
diff --git a/src/test/compile-fail/union-fields.rs b/src/test/compile-fail/union/union-fields.rs
similarity index 72%
rename from src/test/compile-fail/union-fields.rs
rename to src/test/compile-fail/union/union-fields.rs
index 2bd1b8a7b32c..a1721dda7dec 100644
--- a/src/test/compile-fail/union-fields.rs
+++ b/src/test/compile-fail/union/union-fields.rs
@@ -24,11 +24,12 @@ fn main() {
     let u = U { ..u }; //~ ERROR union expressions should have exactly one field
                        //~^ ERROR functional record update syntax requires a struct
 
-    let U {} = u; //~ ERROR union patterns without `..` should have at least one field
+    let U {} = u; //~ ERROR union patterns should have exactly one field
     let U { a } = u; // OK
-    let U { a, b } = u; //~ ERROR union patterns can have at most one field
-    let U { a, b, c } = u; //~ ERROR union patterns can have at most one field
+    let U { a, b } = u; //~ ERROR union patterns should have exactly one field
+    let U { a, b, c } = u; //~ ERROR union patterns should have exactly one field
                            //~^ ERROR union `U` does not have a field named `c`
-    let U { .. } = u; // OK
-    let U { a, .. } = u; // OK
+    let U { .. } = u; //~ ERROR union patterns should have exactly one field
+                      //~^ ERROR `..` cannot be used in union patterns
+    let U { a, .. } = u; //~ ERROR `..` cannot be used in union patterns
 }
diff --git a/src/test/compile-fail/union/union-generic.rs b/src/test/compile-fail/union/union-generic.rs
new file mode 100644
index 000000000000..e6586b0fb7f6
--- /dev/null
+++ b/src/test/compile-fail/union/union-generic.rs
@@ -0,0 +1,24 @@
+// 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.
+
+#![feature(untagged_unions)]
+
+use std::rc::Rc;
+
+union U {
+    a: T
+}
+
+fn main() {
+    let u = U { a: Rc::new(0u32) };
+    //~^ ERROR  the trait bound `std::rc::Rc: std::marker::Copy` is not satisfied
+    let u = U::> { a: Default::default() };
+    //~^ ERROR  the trait bound `std::rc::Rc: std::marker::Copy` is not satisfied
+}
diff --git a/src/test/compile-fail/union-nonrepresentable.rs b/src/test/compile-fail/union/union-nonrepresentable.rs
similarity index 100%
rename from src/test/compile-fail/union-nonrepresentable.rs
rename to src/test/compile-fail/union/union-nonrepresentable.rs
diff --git a/src/test/compile-fail/union/union-repr-c.rs b/src/test/compile-fail/union/union-repr-c.rs
new file mode 100644
index 000000000000..d7dfb126c932
--- /dev/null
+++ b/src/test/compile-fail/union/union-repr-c.rs
@@ -0,0 +1,29 @@
+// 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.
+
+#![feature(untagged_unions)]
+#![allow(unused)]
+#![deny(improper_ctypes)]
+
+#[repr(C)]
+union U {
+    a: u8,
+}
+
+union W {
+    a: u8,
+}
+
+extern "C" {
+    static FOREIGN1: U; // OK
+    static FOREIGN2: W; //~ ERROR found union without foreign-function-safe representation
+}
+
+fn main() {}
diff --git a/src/test/compile-fail/union/union-suggest-field.rs b/src/test/compile-fail/union/union-suggest-field.rs
new file mode 100644
index 000000000000..b05e9b6e2733
--- /dev/null
+++ b/src/test/compile-fail/union/union-suggest-field.rs
@@ -0,0 +1,29 @@
+// 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.
+
+#![feature(untagged_unions)]
+
+union U {
+    principal: u8,
+}
+
+impl U {
+    fn calculate(&self) {}
+}
+
+fn main() {
+    let u = U { principle: 0 }; //~ ERROR union `U` has no field named `principle`
+                                //~^ HELP did you mean `principal`?
+    let w = u.principial; //~ ERROR attempted access of field `principial` on type `U`
+                          //~^ HELP did you mean `principal`?
+
+    let y = u.calculate; //~ ERROR attempted to take value of method `calculate` on type `U`
+                         //~^ HELP maybe a `()` to call it is missing?
+}
diff --git a/src/test/compile-fail/union-unsafe.rs b/src/test/compile-fail/union/union-unsafe.rs
similarity index 77%
rename from src/test/compile-fail/union-unsafe.rs
rename to src/test/compile-fail/union/union-unsafe.rs
index 762ac5d87513..97e1ec2cba86 100644
--- a/src/test/compile-fail/union-unsafe.rs
+++ b/src/test/compile-fail/union/union-unsafe.rs
@@ -15,9 +15,10 @@ union U {
 }
 
 fn main() {
-    let u = U { a: 10 }; // OK
+    let mut u = U { a: 10 }; // OK
     let a = u.a; //~ ERROR access to union field requires unsafe function or block
+    u.a = 11; //~ ERROR access to union field requires unsafe function or block
     let U { a } = u; //~ ERROR matching on union field requires unsafe function or block
-    if let U { a: 11 } = u {} //~ ERROR matching on union field requires unsafe function or block
-    let U { .. } = u; // OK
+    if let U { a: 12 } = u {} //~ ERROR matching on union field requires unsafe function or block
+    // let U { .. } = u; // OK
 }
diff --git a/src/test/compile-fail/union-unsized.rs b/src/test/compile-fail/union/union-unsized.rs
similarity index 83%
rename from src/test/compile-fail/union-unsized.rs
rename to src/test/compile-fail/union/union-unsized.rs
index 381122406d71..a238eaf05250 100644
--- a/src/test/compile-fail/union-unsized.rs
+++ b/src/test/compile-fail/union/union-unsized.rs
@@ -12,6 +12,12 @@
 
 union U {
     a: str, //~ ERROR the trait bound `str: std::marker::Sized` is not satisfied
+    b: u8,
+}
+
+union W {
+    a: u8,
+    b: str, //~ ERROR the trait bound `str: std::marker::Sized` is not satisfied
 }
 
 fn main() {}
diff --git a/src/test/compile-fail/union-with-drop-fields-lint.rs b/src/test/compile-fail/union/union-with-drop-fields-lint.rs
similarity index 100%
rename from src/test/compile-fail/union-with-drop-fields-lint.rs
rename to src/test/compile-fail/union/union-with-drop-fields-lint.rs
diff --git a/src/test/run-pass/auxiliary/union.rs b/src/test/run-pass/union/auxiliary/union.rs
similarity index 100%
rename from src/test/run-pass/auxiliary/union.rs
rename to src/test/run-pass/union/auxiliary/union.rs
diff --git a/src/test/run-pass/union-backcomp.rs b/src/test/run-pass/union/union-backcomp.rs
similarity index 95%
rename from src/test/run-pass/union-backcomp.rs
rename to src/test/run-pass/union/union-backcomp.rs
index c1210dd62121..9394b618ddf2 100644
--- a/src/test/run-pass/union-backcomp.rs
+++ b/src/test/run-pass/union/union-backcomp.rs
@@ -10,7 +10,11 @@
 
 #![feature(untagged_unions)]
 
+fn union() {}
+
 fn main() {
+    union();
+
     let union = 10;
 
     union;
diff --git a/src/test/run-pass/union-basic.rs b/src/test/run-pass/union/union-basic.rs
similarity index 100%
rename from src/test/run-pass/union-basic.rs
rename to src/test/run-pass/union/union-basic.rs
diff --git a/src/test/run-pass/union/union-c-interop.rs b/src/test/run-pass/union/union-c-interop.rs
new file mode 100644
index 000000000000..a9f97620ebd4
--- /dev/null
+++ b/src/test/run-pass/union/union-c-interop.rs
@@ -0,0 +1,47 @@
+// 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.
+
+#![feature(untagged_unions)]
+
+#[derive(Copy)]
+#[repr(C)]
+struct LARGE_INTEGER_U {
+    LowPart: u32,
+    HighPart: u32,
+}
+
+#[derive(Copy)]
+#[repr(C)]
+union LARGE_INTEGER {
+  __unnamed__: LARGE_INTEGER_U,
+  u: LARGE_INTEGER_U,
+  QuadPart: u64,
+}
+
+impl Clone for LARGE_INTEGER_U { fn clone(&self) -> Self { *self } }
+impl Clone for LARGE_INTEGER { fn clone(&self) -> Self { *self } }
+
+#[link(name = "rust_test_helpers")]
+extern "C" {
+    fn increment_all_parts(_: LARGE_INTEGER) -> LARGE_INTEGER;
+}
+
+fn main() {
+    unsafe {
+        let mut li = LARGE_INTEGER { QuadPart: 0 };
+        let li_c = increment_all_parts(li);
+        li.__unnamed__.LowPart += 1;
+        li.__unnamed__.HighPart += 1;
+        li.u.LowPart += 1;
+        li.u.HighPart += 1;
+        li.QuadPart += 1;
+        assert_eq!(li.QuadPart, li_c.QuadPart);
+    }
+}
diff --git a/src/test/run-pass/union-const-trans.rs b/src/test/run-pass/union/union-const-trans.rs
similarity index 100%
rename from src/test/run-pass/union-const-trans.rs
rename to src/test/run-pass/union/union-const-trans.rs
diff --git a/src/test/run-pass/union-derive.rs b/src/test/run-pass/union/union-derive.rs
similarity index 100%
rename from src/test/run-pass/union-derive.rs
rename to src/test/run-pass/union/union-derive.rs
diff --git a/src/test/run-pass/union-drop-assign.rs b/src/test/run-pass/union/union-drop-assign.rs
similarity index 100%
rename from src/test/run-pass/union-drop-assign.rs
rename to src/test/run-pass/union/union-drop-assign.rs
diff --git a/src/test/run-pass/union-drop.rs b/src/test/run-pass/union/union-drop.rs
similarity index 100%
rename from src/test/run-pass/union-drop.rs
rename to src/test/run-pass/union/union-drop.rs
diff --git a/src/test/run-pass/union/union-generic.rs b/src/test/run-pass/union/union-generic.rs
new file mode 100644
index 000000000000..9293805edbf8
--- /dev/null
+++ b/src/test/run-pass/union/union-generic.rs
@@ -0,0 +1,43 @@
+// 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.
+
+#![feature(untagged_unions)]
+
+union MaybeItem {
+    elem: T::Item,
+    none: (),
+}
+
+union U {
+    a: A,
+    b: B,
+}
+
+unsafe fn union_transmute(a: A) -> B {
+    U { a: a }.b
+}
+
+fn main() {
+    unsafe {
+        let u = U::> { a: String::from("abcd") };
+
+        assert_eq!(u.b.len(), 4);
+        assert_eq!(u.b[0], b'a');
+
+        let b = union_transmute::<(u8, u8), u16>((1, 1));
+        assert_eq!(b, (1 << 8) + 1);
+
+        let v: Vec = vec![1, 2, 3];
+        let mut i = v.iter();
+        i.next();
+        let mi = MaybeItem::> { elem: i.next().unwrap() };
+        assert_eq!(*mi.elem, 2);
+    }
+}
diff --git a/src/test/compile-fail/union-field-privacy.rs b/src/test/run-pass/union/union-inherent-method.rs
similarity index 78%
rename from src/test/compile-fail/union-field-privacy.rs
rename to src/test/run-pass/union/union-inherent-method.rs
index d1f2bbbc3d03..adea27bd2546 100644
--- a/src/test/compile-fail/union-field-privacy.rs
+++ b/src/test/run-pass/union/union-inherent-method.rs
@@ -10,12 +10,15 @@
 
 #![feature(untagged_unions)]
 
-mod m {
-    pub union U {
-        a: u8
-    }
+union U {
+    a: u8,
+}
+
+impl U {
+    fn method(&self) -> u8 { unsafe { self.a } }
 }
 
 fn main() {
-    let u = m::U { a: 0 }; //~ ERROR field `a` of union `m::U` is private
+    let u = U { a: 10 };
+    assert_eq!(u.method(), 10);
 }
diff --git a/src/test/run-pass/union/union-macro.rs b/src/test/run-pass/union/union-macro.rs
new file mode 100644
index 000000000000..a23fbc3be9e2
--- /dev/null
+++ b/src/test/run-pass/union/union-macro.rs
@@ -0,0 +1,33 @@
+// 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.
+
+#![feature(untagged_unions)]
+
+macro_rules! duplicate {
+   ($i: item) => {
+        mod m1 {
+            $i
+        }
+        mod m2 {
+            $i
+        }
+   }
+}
+
+duplicate! {
+    pub union U {
+        pub a: u8
+    }
+}
+
+fn main() {
+    let u1 = m1::U { a: 0 };
+    let u2 = m2::U { a: 0 };
+}
diff --git a/src/test/run-pass/union/union-overwrite.rs b/src/test/run-pass/union/union-overwrite.rs
new file mode 100644
index 000000000000..9389a6237bca
--- /dev/null
+++ b/src/test/run-pass/union/union-overwrite.rs
@@ -0,0 +1,80 @@
+// 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.
+
+#![feature(untagged_unions)]
+
+#[repr(C)]
+struct Pair(T, U);
+#[repr(C)]
+struct Triple(T, T, T);
+
+#[repr(C)]
+union U {
+    a: Pair,
+    b: B,
+}
+
+#[repr(C)]
+union W {
+    a: A,
+    b: B,
+}
+
+#[cfg(target_endian = "little")]
+unsafe fn check() {
+    let mut u = U:: { b: 0xDE_DE };
+    u.a.0 = 0xBE;
+    assert_eq!(u.b, 0xDE_BE);
+
+    let mut u = U:: { b: 0xDEAD_DEAD };
+    u.a.0 = 0xBEEF;
+    assert_eq!(u.b, 0xDEAD_BEEF);
+
+    let mut u = U:: { b: 0xDEADBEEF_DEADBEEF };
+    u.a.0 = 0xBAADF00D;
+    assert_eq!(u.b, 0xDEADBEEF_BAADF00D);
+
+    let mut w = W::, u8>, u32> { b: 0xDEAD_DEAD };
+    w.a.0 = Triple(0, 0, 0);
+    assert_eq!(w.b, 0xDE00_0000);
+
+    let mut w = W::>, u32> { b: 0xDEAD_DEAD };
+    w.a.1 = Triple(0, 0, 0);
+    assert_eq!(w.b, 0x0000_00AD);
+}
+
+#[cfg(target_endian = "big")]
+unsafe fn check() {
+    let mut u = U:: { b: 0xDE_DE };
+    u.a.0 = 0xBE;
+    assert_eq!(u.b, 0xBE_DE);
+
+    let mut u = U:: { b: 0xDEAD_DEAD };
+    u.a.0 = 0xBEEF;
+    assert_eq!(u.b, 0xBEEF_DEAD);
+
+    let mut u = U:: { b: 0xDEADBEEF_DEADBEEF };
+    u.a.0 = 0xBAADF00D;
+    assert_eq!(u.b, 0xBAADF00D_DEADBEEF);
+
+    let mut w = W::, u8>, u32> { b: 0xDEAD_DEAD };
+    w.a.0 = Triple(0, 0, 0);
+    assert_eq!(w.b, 0x0000_00AD);
+
+    let mut w = W::>, u32> { b: 0xDEAD_DEAD };
+    w.a.1 = Triple(0, 0, 0);
+    assert_eq!(w.b, 0xDE00_0000);
+}
+
+fn main() {
+    unsafe {
+        check();
+    }
+}
diff --git a/src/test/run-pass/union-packed.rs b/src/test/run-pass/union/union-packed.rs
similarity index 81%
rename from src/test/run-pass/union-packed.rs
rename to src/test/run-pass/union/union-packed.rs
index b1650ae3a7c1..6a61280823e5 100644
--- a/src/test/run-pass/union-packed.rs
+++ b/src/test/run-pass/union/union-packed.rs
@@ -71,4 +71,34 @@ fn main() {
     assert_eq!(align_of::(), 1);
     assert_eq!(align_of_val(&up), 1);
     assert_eq!(align_of_val(&CUP), 1);
+
+    hybrid::check_hybrid();
+}
+
+mod hybrid {
+    use std::mem::size_of;
+
+    #[repr(packed)]
+    struct S1 {
+        a: u16,
+        b: u8,
+    }
+
+    #[repr(packed)]
+    union U {
+        s: S1,
+        c: u16,
+    }
+
+    #[repr(packed)]
+    struct S2 {
+        d: u8,
+        u: U,
+    }
+
+    pub fn check_hybrid() {
+        assert_eq!(size_of::(), 3);
+        assert_eq!(size_of::(), 3);
+        assert_eq!(size_of::(), 4);
+    }
 }
diff --git a/src/test/run-pass/union-pat-refutability.rs b/src/test/run-pass/union/union-pat-refutability.rs
similarity index 100%
rename from src/test/run-pass/union-pat-refutability.rs
rename to src/test/run-pass/union/union-pat-refutability.rs
diff --git a/src/test/run-pass/union/union-trait-impl.rs b/src/test/run-pass/union/union-trait-impl.rs
new file mode 100644
index 000000000000..a5a2be0133ab
--- /dev/null
+++ b/src/test/run-pass/union/union-trait-impl.rs
@@ -0,0 +1,27 @@
+// 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.
+
+#![feature(untagged_unions)]
+
+use std::fmt;
+
+union U {
+    a: u8
+}
+
+impl fmt::Display for U {
+    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+        unsafe { write!(f, "Oh hai {}", self.a) }
+    }
+}
+
+fn main() {
+    assert_eq!(U { a: 2 }.to_string(), "Oh hai 2");
+}
diff --git a/src/test/run-pass/union-transmute.rs b/src/test/run-pass/union/union-transmute.rs
similarity index 100%
rename from src/test/run-pass/union-transmute.rs
rename to src/test/run-pass/union/union-transmute.rs
diff --git a/src/test/run-pass/union/union-with-drop-fields-lint.rs b/src/test/run-pass/union/union-with-drop-fields-lint.rs
new file mode 100644
index 000000000000..5a1424830d07
--- /dev/null
+++ b/src/test/run-pass/union/union-with-drop-fields-lint.rs
@@ -0,0 +1,42 @@
+// 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.
+
+// ignore-pretty
+
+#![feature(untagged_unions)]
+#![allow(dead_code)]
+#![allow(unions_with_drop_fields)]
+
+union U {
+    a: u8, // OK
+}
+
+union W {
+    a: String, // OK
+    b: String, // OK
+}
+
+struct S(String);
+
+// `S` doesn't implement `Drop` trait, but still has non-trivial destructor
+union Y {
+    a: S, // OK
+}
+
+// We don't know if `T` is trivially-destructable or not until trans
+union J {
+    a: T, // OK
+}
+
+union H {
+    a: T, // OK
+}
+
+fn main() {}
diff --git a/src/test/run-pass/union-xcrate.rs b/src/test/run-pass/union/union-xcrate.rs
similarity index 100%
rename from src/test/run-pass/union-xcrate.rs
rename to src/test/run-pass/union/union-xcrate.rs

From 436cfe56534b405786816d4bbcccd11ed7571981 Mon Sep 17 00:00:00 2001
From: Vadim Petrochenkov 
Date: Fri, 26 Aug 2016 19:23:42 +0300
Subject: [PATCH 145/443] Fix type encoding/decoding for unions

Fix union debuginfo test on lldb
---
 src/librustc_metadata/decoder.rs           |  2 +-
 src/librustc_metadata/tydecode.rs          |  8 +++
 src/librustc_metadata/tyencode.rs          |  2 +-
 src/test/debuginfo/union-smoke.rs          |  6 +--
 src/test/run-pass/union/auxiliary/union.rs |  2 +-
 src/test/run-pass/union/union-basic.rs     | 59 +++++++++++++---------
 src/test/run-pass/union/union-xcrate.rs    | 21 --------
 7 files changed, 48 insertions(+), 52 deletions(-)
 delete mode 100644 src/test/run-pass/union/union-xcrate.rs

diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs
index 8775f58d0b22..aeb95e5670d6 100644
--- a/src/librustc_metadata/decoder.rs
+++ b/src/librustc_metadata/decoder.rs
@@ -291,7 +291,7 @@ fn maybe_item_name(item: rbml::Doc) -> Option {
 
 fn family_to_variant_kind<'tcx>(family: Family) -> Option {
     match family {
-        Struct(VariantKind::Struct) | Variant(VariantKind::Struct) =>
+        Struct(VariantKind::Struct) | Variant(VariantKind::Struct) | Union =>
             Some(ty::VariantKind::Struct),
         Struct(VariantKind::Tuple) | Variant(VariantKind::Tuple) =>
             Some(ty::VariantKind::Tuple),
diff --git a/src/librustc_metadata/tydecode.rs b/src/librustc_metadata/tydecode.rs
index f51299226fe7..55ff4817683d 100644
--- a/src/librustc_metadata/tydecode.rs
+++ b/src/librustc_metadata/tydecode.rs
@@ -472,6 +472,14 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> {
                 let def = self.tcx.lookup_adt_def(did);
                 return self.tcx.mk_struct(def, substs);
             }
+            'U' => {
+                assert_eq!(self.next(), '[');
+                let did = self.parse_def();
+                let substs = self.parse_substs();
+                assert_eq!(self.next(), ']');
+                let def = self.tcx.lookup_adt_def(did);
+                return self.tcx.mk_union(def, substs);
+            }
             'k' => {
                 assert_eq!(self.next(), '[');
                 let did = self.parse_def();
diff --git a/src/librustc_metadata/tyencode.rs b/src/librustc_metadata/tyencode.rs
index b334a21c07c7..bef3cf3a1940 100644
--- a/src/librustc_metadata/tyencode.rs
+++ b/src/librustc_metadata/tyencode.rs
@@ -171,7 +171,7 @@ pub fn enc_ty<'a, 'tcx>(w: &mut Cursor>, cx: &ctxt<'a, 'tcx>, t: Ty<'tcx
             write!(w, "]");
         }
         ty::TyUnion(def, substs) => {
-            write!(w, "u[{}|", (cx.ds)(cx.tcx, def.did));
+            write!(w, "U[{}|", (cx.ds)(cx.tcx, def.did));
             enc_substs(w, cx, substs);
             write!(w, "]");
         }
diff --git a/src/test/debuginfo/union-smoke.rs b/src/test/debuginfo/union-smoke.rs
index 17dea300ff9d..319927c979bf 100644
--- a/src/test/debuginfo/union-smoke.rs
+++ b/src/test/debuginfo/union-smoke.rs
@@ -23,10 +23,10 @@
 // === LLDB TESTS ==================================================================================
 
 // lldb-command:run
-// lldb-command:print a
-// lldb-check:[...]$0 = {a = {__0 = 2 '\002', __1 = 2 '\002'}, b = 514}
+// lldb-command:print u
+// lldb-check:[...]$0 = { a = ('\x02', '\x02') b = 514 }
 // lldb-command:print union_smoke::SU
-// lldb-check:[...]$1 = {a = {__0 = 1 '\001', __1 = 1 '\001'}, b = 257}
+// lldb-check:[...]$1 = 257
 
 #![allow(unused)]
 #![feature(omit_gdb_pretty_printer_section)]
diff --git a/src/test/run-pass/union/auxiliary/union.rs b/src/test/run-pass/union/auxiliary/union.rs
index dc0ca7c81c00..0231e38a729b 100644
--- a/src/test/run-pass/union/auxiliary/union.rs
+++ b/src/test/run-pass/union/auxiliary/union.rs
@@ -12,5 +12,5 @@
 
 pub union U {
     pub a: u8,
-    b: u16,
+    pub b: u16,
 }
diff --git a/src/test/run-pass/union/union-basic.rs b/src/test/run-pass/union/union-basic.rs
index 1651aa901b96..d23af4b41b73 100644
--- a/src/test/run-pass/union/union-basic.rs
+++ b/src/test/run-pass/union/union-basic.rs
@@ -8,38 +8,21 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// aux-build:union.rs
+
 #![feature(untagged_unions)]
 
+extern crate union;
 use std::mem::{size_of, align_of, zeroed};
 
 union U {
     a: u8,
+    b: u16
 }
 
-union U64 {
-    a: u64,
-}
-
-union W {
-    a: u8,
-    b: u64,
-}
-
-#[repr(C)]
-union Y {
-    f1: u16,
-    f2: [u8; 4],
-}
-
-fn main() {
-    assert_eq!(size_of::(), 1);
-    assert_eq!(size_of::(), 8);
-    assert_eq!(size_of::(), 8);
-    assert_eq!(align_of::(), 1);
-    assert_eq!(align_of::(), align_of::());
-    assert_eq!(align_of::(), align_of::());
-    assert_eq!(size_of::(), 4);
-    assert_eq!(align_of::(), 2);
+fn local() {
+    assert_eq!(size_of::(), 2);
+    assert_eq!(align_of::(), 2);
 
     let u = U { a: 10 };
     unsafe {
@@ -48,7 +31,7 @@ fn main() {
         assert_eq!(a, 10);
     }
 
-    let mut w = W { b: 0 };
+    let mut w = U { b: 0 };
     unsafe {
         assert_eq!(w.a, 0);
         assert_eq!(w.b, 0);
@@ -57,3 +40,29 @@ fn main() {
         assert_eq!(w.b, 1);
     }
 }
+
+fn xcrate() {
+    assert_eq!(size_of::(), 2);
+    assert_eq!(align_of::(), 2);
+
+    let u = union::U { a: 10 };
+    unsafe {
+        assert_eq!(u.a, 10);
+        let union::U { a } = u;
+        assert_eq!(a, 10);
+    }
+
+    let mut w = union::U { b: 0 };
+    unsafe {
+        assert_eq!(w.a, 0);
+        assert_eq!(w.b, 0);
+        w.a = 1;
+        assert_eq!(w.a, 1);
+        assert_eq!(w.b, 1);
+    }
+}
+
+fn main() {
+    local();
+    xcrate();
+}
diff --git a/src/test/run-pass/union/union-xcrate.rs b/src/test/run-pass/union/union-xcrate.rs
deleted file mode 100644
index 2a76c96ef25f..000000000000
--- a/src/test/run-pass/union/union-xcrate.rs
+++ /dev/null
@@ -1,21 +0,0 @@
-// 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.
-
-// aux-build:union.rs
-
-// #![feature(untagged_unions)]
-
-extern crate union;
-
-type A = union::U;
-
-fn main() {
-    assert_eq!(std::mem::size_of::(), 8);
-}

From 9d9c029a6674787d600e0ea40baa9ca55eb87103 Mon Sep 17 00:00:00 2001
From: Cobrand 
Date: Sat, 3 Sep 2016 12:41:02 +0200
Subject: [PATCH 146/443] doc: Contributing.md: mention of `make tidy`

---
 CONTRIBUTING.md | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 4e6cd6c9782a..4c0f93c3703a 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -151,6 +151,10 @@ Some common make targets are:
   command above as we only build the stage1 compiler, not the entire thing).
   You can also leave off the `-rpass` to run all stage1 test types.
 - `make check-stage1-coretest` - Run stage1 tests in `libcore`.
+- `make tidy` - Check that the source code is in compliance with Rust's style
+  guidelines. There is no official document describing Rust's full guidelines 
+  as of yet, but basic rules like 4 spaces for indentation and no more than 99
+  characters in a single line should be kept in mind when writing code.
 
 ## Pull Requests
 
@@ -177,6 +181,15 @@ you’re adding something to the standard library, try
 
 This will not rebuild the compiler, but will run the tests.
 
+Please make sure your pull request is in compliance with Rust's style
+guidelines by running
+
+    $ make tidy
+
+Make this check before every pull request (and every new commit in a pull
+request) ; you can add [git hooks](https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks)
+before every push to make sure you never forget to make this check.
+
 All pull requests are reviewed by another person. We have a bot,
 @rust-highfive, that will automatically assign a random person to review your
 request.

From 92aa7e42524ec0ce374a4463b8cff9a05b81af6f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?S=C3=A9bastien=20Marie?= 
Date: Sat, 3 Sep 2016 14:06:38 +0200
Subject: [PATCH 147/443] Use libraries from local-rust-root directory in
 configure when using --enable-local-rebuild

When using --enable-local-rebuild configure options, the configure
script will test rustc version. But when running it, it will not use the
libraries in the local-rust-root directory.

So use `LD_LIBRARY_PATH` environment variable to correct it.
---
 configure | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/configure b/configure
index bcc1faea3b5d..97e7ca6eaabf 100755
--- a/configure
+++ b/configure
@@ -901,7 +901,7 @@ then
     fi
 
     CMD="${CFG_LOCAL_RUST_ROOT}/bin/rustc${BIN_SUF}"
-    LRV=`$CMD --version`
+    LRV=`LD_LIBRARY_PATH=${CFG_LOCAL_RUST_ROOT}/lib $CMD --version`
     if [ $? -ne 0 ]
     then
         step_msg "failure while running $CMD --version"

From 72da8b82c14772980956a808e93ed6258c5691ba Mon Sep 17 00:00:00 2001
From: Joseph Dunne 
Date: Fri, 2 Sep 2016 11:15:56 +0100
Subject: [PATCH 148/443] Add rustc version info (git hash + date) to dist
 tarball

fixes #32444
---
 mk/dist.mk            | 1 +
 src/bootstrap/dist.rs | 8 ++++++++
 2 files changed, 9 insertions(+)

diff --git a/mk/dist.mk b/mk/dist.mk
index e81371037ac2..cb0bca01e6c4 100644
--- a/mk/dist.mk
+++ b/mk/dist.mk
@@ -76,6 +76,7 @@ tmp/dist/$$(SRC_PKG_NAME)-image: $(PKG_FILES)
 	@$(call E, making src image)
 	$(Q)rm -Rf tmp/dist/$(SRC_PKG_NAME)-image
 	$(Q)mkdir -p tmp/dist/$(SRC_PKG_NAME)-image/lib/rustlib/src/rust
+	$(Q)echo "$(CFG_VERSION)" > tmp/dist/$(SRC_PKG_NAME)-image/lib/rustlib/src/rust/version
 	$(Q)tar \
          -C $(S) \
          -f - \
diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs
index 9d18901eb000..31b7db168b48 100644
--- a/src/bootstrap/dist.rs
+++ b/src/bootstrap/dist.rs
@@ -388,6 +388,9 @@ pub fn rust_src(build: &Build) {
     // Rename directory, so that root folder of tarball has the correct name
     t!(fs::rename(&dst_src, &plain_dst_src));
 
+    // Create the version file
+    write_file(&plain_dst_src.join("version"), build.version.as_bytes());
+
     // Create plain source tarball
     let mut cmd = Command::new("tar");
     cmd.arg("-czf").arg(sanitize_sh(&distdir(build).join(&format!("{}.tar.gz", plain_name))))
@@ -431,3 +434,8 @@ fn sanitize_sh(path: &Path) -> String {
         Some(format!("/{}/{}", drive, &s[drive.len_utf8() + 2..]))
     }
 }
+
+fn write_file(path: &Path, data: &[u8]) {
+    let mut vf = t!(fs::File::create(path));
+    t!(vf.write_all(data));
+}

From 216cf9c124f8f8dd3c8d7e99ad6e6821a02edcae Mon Sep 17 00:00:00 2001
From: Guillaume Gomez 
Date: Sat, 3 Sep 2016 16:15:22 +0200
Subject: [PATCH 149/443] Add missing urls

---
 src/libcollections/btree/map.rs | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/src/libcollections/btree/map.rs b/src/libcollections/btree/map.rs
index 79840df1677e..624083a8eaf3 100644
--- a/src/libcollections/btree/map.rs
+++ b/src/libcollections/btree/map.rs
@@ -56,8 +56,12 @@ use self::Entry::*;
 /// however, performance is excellent.
 ///
 /// It is a logic error for a key to be modified in such a way that the key's ordering relative to
-/// any other key, as determined by the `Ord` trait, changes while it is in the map. This is
-/// normally only possible through `Cell`, `RefCell`, global state, I/O, or unsafe code.
+/// any other key, as determined by the [`Ord`] trait, changes while it is in the map. This is
+/// normally only possible through [`Cell`], [`RefCell`], global state, I/O, or unsafe code.
+///
+/// [`Ord`]: ../../std/cmp/trait.Ord.html
+/// [`Cell`]: ../../std/cell/struct.Cell.html
+/// [`RefCell`]: ../../std/cell/struct.RefCell.html
 ///
 /// # Examples
 ///
@@ -2020,7 +2024,7 @@ impl<'a, K: Ord, V> VacantEntry<'a, K, V> {
         self.key
     }
 
-    /// Sets the value of the entry with the VacantEntry's key,
+    /// Sets the value of the entry with the `VacantEntry`'s key,
     /// and returns a mutable reference to it.
     ///
     /// # Examples
@@ -2192,7 +2196,7 @@ impl<'a, K: Ord, V> OccupiedEntry<'a, K, V> {
         self.handle.into_kv_mut().1
     }
 
-    /// Sets the value of the entry with the OccupiedEntry's key,
+    /// Sets the value of the entry with the `OccupiedEntry`'s key,
     /// and returns the entry's old value.
     ///
     /// # Examples

From 4ec715becfeb4426a36245f9147a8ba4d4448df7 Mon Sep 17 00:00:00 2001
From: Alex Crichton 
Date: Sat, 3 Sep 2016 10:23:40 -0700
Subject: [PATCH 150/443] Add back feature accidentally removed

This feature was accidentally removed in
https://github.com/rust-lang/rust/pull/35957.
---
 src/libsyntax/feature_gate.rs | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index 683d5277359e..57db15f7947f 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -305,6 +305,7 @@ declare_features! (
     (removed, struct_inherit, "1.0.0", None),
     (removed, test_removed_feature, "1.0.0", None),
     (removed, visible_private_types, "1.0.0", None),
+    (removed, unsafe_no_drop_flag, "1.0.0", None),
 );
 
 declare_features! (

From 5652b62a6b1531d95c10c6d62ea57d5af95cd8d7 Mon Sep 17 00:00:00 2001
From: Corey Farwell 
Date: Fri, 19 Aug 2016 21:43:21 -0400
Subject: [PATCH 151/443] Indicate where `core::result::IntoIter` is created.

---
 src/libcore/result.rs | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/src/libcore/result.rs b/src/libcore/result.rs
index 49eb5619bc6b..94b6d5fa0031 100644
--- a/src/libcore/result.rs
+++ b/src/libcore/result.rs
@@ -902,7 +902,13 @@ impl<'a, T> ExactSizeIterator for IterMut<'a, T> {}
 #[unstable(feature = "fused", issue = "35602")]
 impl<'a, T> FusedIterator for IterMut<'a, T> {}
 
-/// An iterator over the value in a `Ok` variant of a `Result`.
+/// An iterator over the value in a `Ok` variant of a `Result`. This struct is
+/// created by the [`into_iter`] method on [`Result`][`Result`] (provided by
+/// the [`IntoIterator`] trait).
+///
+/// [`Result`]: enum.Result.html
+/// [`into_iter`]: ../iter/trait.IntoIterator.html#tymethod.into_iter
+/// [`IntoIterator`]: ../iter/trait.IntoIterator.html
 #[derive(Debug)]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct IntoIter { inner: Option }

From fe8438d4a2c96295dcee95af415b9762c84ec6c6 Mon Sep 17 00:00:00 2001
From: Josh Triplett 
Date: Sat, 3 Sep 2016 15:29:16 -0700
Subject: [PATCH 152/443] Fix "field is never used" warning to take unions into
 account

Rather than saying "struct or union" or adding logic to determine the
type of the item, just change the message to "field is never used",
dropping the "struct".

Update tests accordingly.
---
 src/librustc/middle/dead.rs               |  2 +-
 src/test/compile-fail/lint-dead-code-4.rs | 10 +++++-----
 2 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs
index 0b1d9e8d8f69..80d45def960d 100644
--- a/src/librustc/middle/dead.rs
+++ b/src/librustc/middle/dead.rs
@@ -548,7 +548,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for DeadVisitor<'a, 'tcx> {
     fn visit_struct_field(&mut self, field: &hir::StructField) {
         if self.should_warn_about_field(&field) {
             self.warn_dead_code(field.id, field.span,
-                                field.name, "struct field");
+                                field.name, "field");
         }
 
         intravisit::walk_struct_field(self, field);
diff --git a/src/test/compile-fail/lint-dead-code-4.rs b/src/test/compile-fail/lint-dead-code-4.rs
index 20cd13c1875d..3df089fc2004 100644
--- a/src/test/compile-fail/lint-dead-code-4.rs
+++ b/src/test/compile-fail/lint-dead-code-4.rs
@@ -14,7 +14,7 @@
 
 struct Foo {
     x: usize,
-    b: bool, //~ ERROR: struct field is never used
+    b: bool, //~ ERROR: field is never used
 }
 
 fn field_read(f: Foo) -> usize {
@@ -46,8 +46,8 @@ enum IJK {
     I, //~ ERROR variant is never used
     J {
         a: String,
-        b: i32, //~ ERROR struct field is never used
-        c: i32, //~ ERROR struct field is never used
+        b: i32, //~ ERROR field is never used
+        c: i32, //~ ERROR field is never used
     },
     K //~ ERROR variant is never used
 
@@ -68,9 +68,9 @@ fn field_match_in_patterns(b: XYZ) -> String {
 }
 
 struct Bar {
-    x: usize, //~ ERROR: struct field is never used
+    x: usize, //~ ERROR: field is never used
     b: bool,
-    c: bool, //~ ERROR: struct field is never used
+    c: bool, //~ ERROR: field is never used
     _guard: ()
 }
 

From 7c53eb97df4dc39c88e452d67b4f51d5bca336f6 Mon Sep 17 00:00:00 2001
From: ggomez 
Date: Mon, 29 Aug 2016 16:27:04 +0200
Subject: [PATCH 153/443] Add librustc metadata error codes to global check

---
 src/librustc_driver/lib.rs           | 1 +
 src/librustc_metadata/diagnostics.rs | 6 +++---
 src/librustc_metadata/lib.rs         | 2 ++
 3 files changed, 6 insertions(+), 3 deletions(-)

diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs
index 4e87c931cc19..401069666301 100644
--- a/src/librustc_driver/lib.rs
+++ b/src/librustc_driver/lib.rs
@@ -1134,6 +1134,7 @@ pub fn diagnostics_registry() -> errors::registry::Registry {
     all_errors.extend_from_slice(&rustc_privacy::DIAGNOSTICS);
     all_errors.extend_from_slice(&rustc_trans::DIAGNOSTICS);
     all_errors.extend_from_slice(&rustc_const_eval::DIAGNOSTICS);
+    all_errors.extend_from_slice(&rustc_metadata::DIAGNOSTICS);
 
     Registry::new(&all_errors)
 }
diff --git a/src/librustc_metadata/diagnostics.rs b/src/librustc_metadata/diagnostics.rs
index 321893074668..01c7d7fc79d5 100644
--- a/src/librustc_metadata/diagnostics.rs
+++ b/src/librustc_metadata/diagnostics.rs
@@ -21,7 +21,7 @@ A link name was given with an empty name. Erroneous code example:
 The rust compiler cannot link to an external library if you don't give it its
 name. Example:
 
-```
+```ignore
 #[link(name = "some_lib")] extern {} // ok!
 ```
 "##,
@@ -72,7 +72,7 @@ A link was used without a name parameter. Erroneous code example:
 Please add the name parameter to allow the rust compiler to find the library
 you want. Example:
 
-```
+```ignore
 #[link(kind = "dylib", name = "some_lib")] extern {} // ok!
 ```
 "##,
@@ -121,7 +121,7 @@ macro_rules! get_pimientos {
 
 // In your crate:
 #[macro_use(get_tacos, get_pimientos)] // It imports `get_tacos` and
-extern crate some_crate;               // `get_pimientos` macros from some_crate.
+extern crate some_crate;               // `get_pimientos` macros from some_crate
 ```
 
 If you would like to import all exported macros, write `macro_use` with no
diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs
index a96fa8a006d8..d27c0c031535 100644
--- a/src/librustc_metadata/lib.rs
+++ b/src/librustc_metadata/lib.rs
@@ -63,3 +63,5 @@ pub mod index;
 pub mod loader;
 pub mod macro_import;
 pub mod tls_context;
+
+__build_diagnostic_array! { librustc_metadata, DIAGNOSTICS }

From 1eda14e4c9f8a315086cfa5986156cf693a2e92f Mon Sep 17 00:00:00 2001
From: Guillaume Gomez 
Date: Thu, 25 Aug 2016 13:06:38 +0200
Subject: [PATCH 154/443] E0060 and E0061 improvement

---
 src/librustc_typeck/check/mod.rs              | 20 ++++++++++---------
 src/test/compile-fail/E0060.rs                |  3 +--
 src/test/compile-fail/E0061.rs                | 10 ++++++++--
 src/test/compile-fail/issue-18819.rs          |  4 ++--
 src/test/compile-fail/issue-3044.rs           |  2 +-
 src/test/compile-fail/issue-4935.rs           |  1 -
 src/test/compile-fail/method-call-err-msg.rs  |  3 +--
 src/test/compile-fail/not-enough-arguments.rs |  4 ++--
 src/test/compile-fail/overloaded-calls-bad.rs |  2 --
 src/test/compile-fail/variadic-ffi-3.rs       |  8 ++++----
 10 files changed, 30 insertions(+), 27 deletions(-)

diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 3d51da02b874..0d2129b2cb41 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -2481,16 +2481,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     if arg_count == 1 {" was"} else {"s were"}),
                 error_code);
 
-            err.span_label(sp, &format!("expected {}{} parameter{}",
-                                        if variadic {"at least "} else {""},
-                                        expected_count,
-                                        if expected_count == 1 {""} else {"s"}));
-
             let input_types = fn_inputs.iter().map(|i| format!("{:?}", i)).collect::>();
-            if input_types.len() > 0 {
-                err.note(&format!("the following parameter type{} expected: {}",
-                        if expected_count == 1 {" was"} else {"s were"},
-                        input_types.join(", ")));
+            if input_types.len() > 1 {
+                err.note("the following parameter types were expected:");
+                err.note(&input_types.join(", "));
+            } else if input_types.len() > 0 {
+                err.note(&format!("the following parameter type was expected: {}",
+                                  input_types[0]));
+            } else {
+                err.span_label(sp, &format!("expected {}{} parameter{}",
+                                            if variadic {"at least "} else {""},
+                                            expected_count,
+                                            if expected_count == 1 {""} else {"s"}));
             }
             err.emit();
         }
diff --git a/src/test/compile-fail/E0060.rs b/src/test/compile-fail/E0060.rs
index e1f2618c180f..5182a2bf5a0a 100644
--- a/src/test/compile-fail/E0060.rs
+++ b/src/test/compile-fail/E0060.rs
@@ -15,6 +15,5 @@ extern "C" {
 fn main() {
     unsafe { printf(); }
     //~^ ERROR E0060
-    //~| NOTE expected at least 1 parameter
-    //~| NOTE the following parameter type was expected
+    //~| NOTE the following parameter type was expected: *const u8
 }
diff --git a/src/test/compile-fail/E0061.rs b/src/test/compile-fail/E0061.rs
index ca04b059dc7f..4c7c0dfd44c5 100644
--- a/src/test/compile-fail/E0061.rs
+++ b/src/test/compile-fail/E0061.rs
@@ -10,9 +10,15 @@
 
 fn f(a: u16, b: &str) {}
 
+fn f2(a: u16) {}
+
 fn main() {
     f(0);
     //~^ ERROR E0061
-    //~| NOTE expected 2 parameters
-    //~| NOTE the following parameter types were expected
+    //~| NOTE the following parameter types were expected:
+    //~| NOTE u16, &str
+
+    f2();
+    //~^ ERROR E0061
+    //~| NOTE the following parameter type was expected: u16
 }
diff --git a/src/test/compile-fail/issue-18819.rs b/src/test/compile-fail/issue-18819.rs
index cf650460c3de..8035d798e32d 100644
--- a/src/test/compile-fail/issue-18819.rs
+++ b/src/test/compile-fail/issue-18819.rs
@@ -25,6 +25,6 @@ fn print_x(_: &Foo, extra: &str) {
 fn main() {
     print_x(X);
     //~^ ERROR this function takes 2 parameters but 1 parameter was supplied
-    //~| NOTE the following parameter types were expected: &Foo, &str
-    //~| NOTE expected 2 parameters
+    //~| NOTE the following parameter types were expected:
+    //~| NOTE &Foo, &str
 }
diff --git a/src/test/compile-fail/issue-3044.rs b/src/test/compile-fail/issue-3044.rs
index d19e3b2c7b0a..b934cbe4b5d8 100644
--- a/src/test/compile-fail/issue-3044.rs
+++ b/src/test/compile-fail/issue-3044.rs
@@ -15,6 +15,6 @@ fn main() {
     });
     //~^^ ERROR this function takes 2 parameters but 1 parameter was supplied
     //~| NOTE the following parameter types were expected
-    //~| NOTE expected 2 parameters
+    //~| NOTE _, _
     // the first error is, um, non-ideal.
 }
diff --git a/src/test/compile-fail/issue-4935.rs b/src/test/compile-fail/issue-4935.rs
index 58a84f3490b3..08707a187dfd 100644
--- a/src/test/compile-fail/issue-4935.rs
+++ b/src/test/compile-fail/issue-4935.rs
@@ -14,4 +14,3 @@ fn foo(a: usize) {}
 fn main() { foo(5, 6) }
 //~^ ERROR this function takes 1 parameter but 2 parameters were supplied
 //~| NOTE the following parameter type was expected
-//~| NOTE expected 1 parameter
diff --git a/src/test/compile-fail/method-call-err-msg.rs b/src/test/compile-fail/method-call-err-msg.rs
index bcf676dbede6..b7e0c5b81d91 100644
--- a/src/test/compile-fail/method-call-err-msg.rs
+++ b/src/test/compile-fail/method-call-err-msg.rs
@@ -23,10 +23,9 @@ fn main() {
      //~^ NOTE expected 0 parameters
      .one()     //~ ERROR this function takes 1 parameter but 0 parameters were supplied
      //~^ NOTE the following parameter type was expected
-     //~| NOTE expected 1 parameter
      .two(0);   //~ ERROR this function takes 2 parameters but 1 parameter was supplied
      //~^ NOTE the following parameter types were expected
-     //~| NOTE expected 2 parameters
+     //~| NOTE isize, isize
 
     let y = Foo;
     y.zero()
diff --git a/src/test/compile-fail/not-enough-arguments.rs b/src/test/compile-fail/not-enough-arguments.rs
index f2f61fcaeec1..660d48da4dbc 100644
--- a/src/test/compile-fail/not-enough-arguments.rs
+++ b/src/test/compile-fail/not-enough-arguments.rs
@@ -19,6 +19,6 @@ fn foo(a: isize, b: isize, c: isize, d:isize) {
 fn main() {
   foo(1, 2, 3);
   //~^ ERROR this function takes 4 parameters but 3
-  //~| NOTE the following parameter types were expected
-  //~| NOTE expected 4 parameters
+  //~| NOTE the following parameter types were expected:
+  //~| NOTE isize, isize, isize, isize
 }
diff --git a/src/test/compile-fail/overloaded-calls-bad.rs b/src/test/compile-fail/overloaded-calls-bad.rs
index 1825ec61f1ed..0aa9af3c8dad 100644
--- a/src/test/compile-fail/overloaded-calls-bad.rs
+++ b/src/test/compile-fail/overloaded-calls-bad.rs
@@ -42,9 +42,7 @@ fn main() {
     let ans = s();
     //~^ ERROR this function takes 1 parameter but 0 parameters were supplied
     //~| NOTE the following parameter type was expected
-    //~| NOTE expected 1 parameter
     let ans = s("burma", "shave");
     //~^ ERROR this function takes 1 parameter but 2 parameters were supplied
     //~| NOTE the following parameter type was expected
-    //~| NOTE expected 1 parameter
 }
diff --git a/src/test/compile-fail/variadic-ffi-3.rs b/src/test/compile-fail/variadic-ffi-3.rs
index cc9a7c84eded..334b8bb08aea 100644
--- a/src/test/compile-fail/variadic-ffi-3.rs
+++ b/src/test/compile-fail/variadic-ffi-3.rs
@@ -17,11 +17,11 @@ extern "C" fn bar(f: isize, x: u8) {}
 fn main() {
     unsafe {
         foo(); //~ ERROR: this function takes at least 2 parameters but 0 parameters were supplied
-        //~^ NOTE the following parameter types were expected
-        //~| NOTE expected at least 2 parameters
+               //~^ NOTE the following parameter types were expected:
+               //~| NOTE isize, u8
         foo(1); //~ ERROR: this function takes at least 2 parameters but 1 parameter was supplied
-        //~^ NOTE the following parameter types were expected
-        //~| NOTE expected at least 2 parameters
+        //~^ NOTE the following parameter types were expected:
+        //~| NOTE isize, u8
 
         let x: unsafe extern "C" fn(f: isize, x: u8) = foo;
         //~^ ERROR: mismatched types

From b66410043a8d2f352b8261f93c4227d48292df72 Mon Sep 17 00:00:00 2001
From: Jake Goldsborough 
Date: Sat, 3 Sep 2016 20:22:12 -0700
Subject: [PATCH 155/443] adding a check to bootstrap script and a check to the
 rust config script

---
 src/bootstrap/bootstrap.py | 9 +++++++++
 src/bootstrap/config.rs    | 3 +++
 2 files changed, 12 insertions(+)

diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py
index 17a7c9ca66a2..3f4a18ab1247 100644
--- a/src/bootstrap/bootstrap.py
+++ b/src/bootstrap/bootstrap.py
@@ -236,6 +236,15 @@ class RustBuild:
             return config + '/bin/rustc' + self.exe_suffix()
         return os.path.join(self.bin_root(), "bin/rustc" + self.exe_suffix())
 
+    def nodejs(self):
+        config = self.get_toml('nodejs')
+        if config:
+            return config
+        if os.path.exists(os.path.join(self.bin_root(), "bin/nodejs")):
+            return os.path.join(self.bin_root(), "bin/nodejs" + self.exe_suffix())
+        elif os.path.exists(os.path.join(self.bin_root(), "bin/node")):
+            return os.path.join(self.bin_root(), "bin/node" + self.exe_suffix())
+
     def get_string(self, line):
         start = line.find('"')
         end = start + 1 + line[start+1:].find('"')
diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs
index 682a6f74126a..5a7ae4f6973d 100644
--- a/src/bootstrap/config.rs
+++ b/src/bootstrap/config.rs
@@ -67,6 +67,7 @@ pub struct Config {
     pub target: Vec,
     pub rustc: Option,
     pub cargo: Option,
+    pub nodejs: Option,
     pub local_rebuild: bool,
 
     // libstd features
@@ -111,6 +112,7 @@ struct Build {
     host: Vec,
     target: Vec,
     cargo: Option,
+    nodejs: Option,
     rustc: Option,
     compiler_docs: Option,
     docs: Option,
@@ -215,6 +217,7 @@ impl Config {
         }
         config.rustc = build.rustc.map(PathBuf::from);
         config.cargo = build.cargo.map(PathBuf::from);
+        config.nodejs = build.nodejs.map(PathBuf::from);
         set(&mut config.compiler_docs, build.compiler_docs);
         set(&mut config.docs, build.docs);
 

From ca5dfd0c975c80697dcc2a3bcbfc9d3106609fb1 Mon Sep 17 00:00:00 2001
From: Keunhong Lee 
Date: Sun, 4 Sep 2016 03:22:56 +0000
Subject: [PATCH 156/443] Allow CompilerControllers to access
 rustc_plugin::registry::Registry structure.

---
 src/librustc_driver/driver.rs   | 13 +++++++++----
 src/librustc_driver/test.rs     |  2 +-
 src/librustc_plugin/registry.rs |  4 ++--
 src/librustdoc/core.rs          |  2 +-
 src/librustdoc/test.rs          |  2 +-
 5 files changed, 14 insertions(+), 9 deletions(-)

diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs
index 94092be4922b..35284a88bd32 100644
--- a/src/librustc_driver/driver.rs
+++ b/src/librustc_driver/driver.rs
@@ -97,7 +97,7 @@ pub fn compile_input(sess: &Session,
             }
         };
 
-        let krate = {
+        let (krate, registry) = {
             let mut compile_state = CompileState::state_after_parse(input,
                                                                     sess,
                                                                     outdir,
@@ -109,14 +109,14 @@ pub fn compile_input(sess: &Session,
                                     compile_state,
                                     Ok(()));
 
-            compile_state.krate.unwrap()
+            (compile_state.krate.unwrap(), compile_state.registry)
         };
 
         let outputs = build_output_filenames(input, outdir, output, &krate.attrs, sess);
         let crate_name = link::find_crate_name(Some(sess), &krate.attrs, input);
         let ExpansionResult { expanded_crate, defs, analysis, resolutions, mut hir_forest } = {
             phase_2_configure_and_expand(
-                sess, &cstore, krate, &crate_name, addl_plugins, control.make_glob_map,
+                sess, &cstore, krate, registry, &crate_name, addl_plugins, control.make_glob_map,
                 |expanded_crate| {
                     let mut state = CompileState::state_after_expand(
                         input, sess, outdir, output, &cstore, expanded_crate, &crate_name,
@@ -329,6 +329,7 @@ pub struct CompileState<'a, 'b, 'ast: 'a, 'tcx: 'b> where 'ast: 'tcx {
     pub input: &'a Input,
     pub session: &'ast Session,
     pub krate: Option,
+    pub registry: Option>,
     pub cstore: Option<&'a CStore>,
     pub crate_name: Option<&'a str>,
     pub output_filenames: Option<&'a OutputFilenames>,
@@ -357,6 +358,7 @@ impl<'a, 'b, 'ast, 'tcx> CompileState<'a, 'b, 'ast, 'tcx> {
             out_file: None,
             arenas: None,
             krate: None,
+            registry: None,
             cstore: None,
             crate_name: None,
             output_filenames: None,
@@ -379,6 +381,8 @@ impl<'a, 'b, 'ast, 'tcx> CompileState<'a, 'b, 'ast, 'tcx> {
                          cstore: &'a CStore)
                          -> CompileState<'a, 'b, 'ast, 'tcx> {
         CompileState {
+            // Initialize the registry before moving `krate`
+            registry: Some(Registry::new(&session, krate.span)),
             krate: Some(krate),
             cstore: Some(cstore),
             out_file: out_file.as_ref().map(|s| &**s),
@@ -545,6 +549,7 @@ pub struct ExpansionResult<'a> {
 pub fn phase_2_configure_and_expand<'a, F>(sess: &Session,
                                            cstore: &CStore,
                                            mut krate: ast::Crate,
+                                           registry: Option,
                                            crate_name: &'a str,
                                            addl_plugins: Option>,
                                            make_glob_map: MakeGlobMap,
@@ -592,7 +597,7 @@ pub fn phase_2_configure_and_expand<'a, F>(sess: &Session,
                                    addl_plugins.take().unwrap())
     });
 
-    let mut registry = Registry::new(sess, &krate);
+    let mut registry = registry.unwrap_or(Registry::new(sess, krate.span));
 
     time(time_passes, "plugin registration", || {
         if sess.features.borrow().rustc_diagnostic_macros {
diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs
index 460a6e68a5c5..2d04b8d1362f 100644
--- a/src/librustc_driver/test.rs
+++ b/src/librustc_driver/test.rs
@@ -115,7 +115,7 @@ fn test_env(source_string: &str,
     let krate = driver::phase_1_parse_input(&sess, krate_config, &input).unwrap();
     let driver::ExpansionResult { defs, resolutions, mut hir_forest, .. } = {
         driver::phase_2_configure_and_expand(
-            &sess, &cstore, krate, "test", None, MakeGlobMap::No, |_| Ok(()),
+            &sess, &cstore, krate, None, "test", None, MakeGlobMap::No, |_| Ok(()),
         ).expect("phase 2 aborted")
     };
     let _ignore = dep_graph.in_ignore();
diff --git a/src/librustc_plugin/registry.rs b/src/librustc_plugin/registry.rs
index 5ae6584aed42..6fa42e7bcd77 100644
--- a/src/librustc_plugin/registry.rs
+++ b/src/librustc_plugin/registry.rs
@@ -69,11 +69,11 @@ pub struct Registry<'a> {
 
 impl<'a> Registry<'a> {
     #[doc(hidden)]
-    pub fn new(sess: &'a Session, krate: &ast::Crate) -> Registry<'a> {
+    pub fn new(sess: &'a Session, krate_span: Span) -> Registry<'a> {
         Registry {
             sess: sess,
             args_hidden: None,
-            krate_span: krate.span,
+            krate_span: krate_span,
             syntax_exts: vec!(),
             early_lint_passes: vec!(),
             late_lint_passes: vec!(),
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index 26f792a1fdf9..0c236434cc70 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -146,7 +146,7 @@ pub fn run_core(search_paths: SearchPaths,
 
     let driver::ExpansionResult { defs, analysis, resolutions, mut hir_forest, .. } = {
         driver::phase_2_configure_and_expand(
-            &sess, &cstore, krate, &name, None, resolve::MakeGlobMap::No, |_| Ok(()),
+            &sess, &cstore, krate, None, &name, None, resolve::MakeGlobMap::No, |_| Ok(()),
         ).expect("phase_2_configure_and_expand aborted in rustdoc!")
     };
 
diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs
index beed1dc9f9e7..e4dd41d7e4c3 100644
--- a/src/librustdoc/test.rs
+++ b/src/librustdoc/test.rs
@@ -94,7 +94,7 @@ pub fn run(input: &str,
     let krate = panictry!(driver::phase_1_parse_input(&sess, cfg, &input));
     let driver::ExpansionResult { defs, mut hir_forest, .. } = {
         phase_2_configure_and_expand(
-            &sess, &cstore, krate, "rustdoc-test", None, MakeGlobMap::No, |_| Ok(())
+            &sess, &cstore, krate, None, "rustdoc-test", None, MakeGlobMap::No, |_| Ok(())
         ).expect("phase_2_configure_and_expand aborted in rustdoc!")
     };
 

From 6f7e51e49b7d74f8112cf048fcbd377d0db7c326 Mon Sep 17 00:00:00 2001
From: Vadim Petrochenkov 
Date: Fri, 26 Aug 2016 19:23:42 +0300
Subject: [PATCH 157/443] Replace `_, _, _` with `..`

---
 src/librustc/hir/def.rs                            |  2 +-
 src/librustc/hir/intravisit.rs                     |  6 +++---
 src/librustc/hir/pat_util.rs                       |  2 +-
 src/librustc/infer/error_reporting.rs              |  4 ++--
 src/librustc/infer/mod.rs                          |  2 +-
 src/librustc/lib.rs                                |  1 +
 src/librustc/middle/dead.rs                        |  4 ++--
 src/librustc/middle/effect.rs                      |  4 ++--
 src/librustc/middle/expr_use_visitor.rs            |  2 +-
 src/librustc/middle/reachable.rs                   | 14 +++++++-------
 src/librustc/middle/resolve_lifetime.rs            |  8 ++++----
 src/librustc/middle/stability.rs                   |  6 +++---
 src/librustc/ty/mod.rs                             | 10 +++++-----
 src/librustc_borrowck/borrowck/mir/mod.rs          |  4 ++--
 src/librustc_borrowck/borrowck/mod.rs              |  2 +-
 src/librustc_borrowck/lib.rs                       |  1 +
 src/librustc_const_eval/eval.rs                    |  2 +-
 src/librustc_const_eval/lib.rs                     |  2 +-
 src/librustc_lint/bad_style.rs                     |  4 ++--
 src/librustc_lint/builtin.rs                       | 12 ++++++------
 src/librustc_lint/lib.rs                           |  1 +
 src/librustc_metadata/encoder.rs                   |  8 ++++----
 src/librustc_metadata/lib.rs                       |  1 +
 src/librustc_mir/hair/cx/mod.rs                    |  2 +-
 src/librustc_mir/lib.rs                            |  1 +
 src/librustc_mir/transform/qualify_consts.rs       |  2 +-
 src/librustc_passes/ast_validation.rs              | 10 +++++-----
 src/librustc_passes/consts.rs                      |  2 +-
 src/librustc_passes/lib.rs                         |  1 +
 src/librustc_privacy/lib.rs                        | 13 +++++++------
 src/librustc_resolve/build_reduced_graph.rs        |  4 ++--
 src/librustc_resolve/lib.rs                        |  5 +++--
 src/librustc_save_analysis/dump_visitor.rs         |  2 +-
 src/librustc_save_analysis/lib.rs                  |  7 ++++---
 src/librustc_trans/collector.rs                    |  4 ++--
 src/librustc_trans/lib.rs                          |  1 +
 src/librustc_typeck/astconv.rs                     |  2 +-
 src/librustc_typeck/check/mod.rs                   |  8 ++++----
 src/librustc_typeck/check/wfcheck.rs               |  4 ++--
 src/librustc_typeck/coherence/mod.rs               | 10 +++++-----
 src/librustc_typeck/coherence/orphan.rs            |  4 ++--
 src/librustc_typeck/coherence/overlap.rs           |  2 +-
 src/librustc_typeck/coherence/unsafety.rs          |  2 +-
 src/librustc_typeck/collect.rs                     | 10 +++++-----
 src/librustc_typeck/lib.rs                         |  5 +++--
 src/libstd/lib.rs                                  |  1 +
 src/libstd/sys/windows/fs.rs                       |  2 +-
 src/libsyntax/ast.rs                               |  2 +-
 .../auxiliary/macro_crate_test.rs                  |  5 +++--
 .../auxiliary/macro_crate_test.rs                  |  7 ++++---
 50 files changed, 117 insertions(+), 103 deletions(-)

diff --git a/src/librustc/hir/def.rs b/src/librustc/hir/def.rs
index aa0eac37ecff..71bc2693abd2 100644
--- a/src/librustc/hir/def.rs
+++ b/src/librustc/hir/def.rs
@@ -124,7 +124,7 @@ impl Def {
             Def::Variant(_, id) | Def::Enum(id) | Def::TyAlias(id) | Def::AssociatedTy(_, id) |
             Def::TyParam(id) | Def::Struct(id) | Def::Union(id) | Def::Trait(id) |
             Def::Method(id) | Def::Const(id) | Def::AssociatedConst(id) |
-            Def::Local(id, _) | Def::Upvar(id, _, _, _) => {
+            Def::Local(id, _) | Def::Upvar(id, ..) => {
                 id
             }
 
diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs
index 62157b1ca368..81b1be53615d 100644
--- a/src/librustc/hir/intravisit.rs
+++ b/src/librustc/hir/intravisit.rs
@@ -49,8 +49,8 @@ pub enum FnKind<'a> {
 impl<'a> FnKind<'a> {
     pub fn attrs(&self) -> &'a [Attribute] {
         match *self {
-            FnKind::ItemFn(_, _, _, _, _, _, attrs) => attrs,
-            FnKind::Method(_, _, _, attrs) => attrs,
+            FnKind::ItemFn(.., attrs) => attrs,
+            FnKind::Method(.., attrs) => attrs,
             FnKind::Closure(attrs) => attrs,
         }
     }
@@ -622,7 +622,7 @@ pub fn walk_fn_decl_nopat<'v, V: Visitor<'v>>(visitor: &mut V, function_declarat
 
 pub fn walk_fn_kind<'v, V: Visitor<'v>>(visitor: &mut V, function_kind: FnKind<'v>) {
     match function_kind {
-        FnKind::ItemFn(_, generics, _, _, _, _, _) => {
+        FnKind::ItemFn(_, generics, ..) => {
             visitor.visit_generics(generics);
         }
         FnKind::Method(_, sig, _, _) => {
diff --git a/src/librustc/hir/pat_util.rs b/src/librustc/hir/pat_util.rs
index 593d10ef4f7c..abb608400244 100644
--- a/src/librustc/hir/pat_util.rs
+++ b/src/librustc/hir/pat_util.rs
@@ -62,7 +62,7 @@ pub fn pat_is_refutable(dm: &DefMap, pat: &hir::Pat) -> bool {
                 _ => false
             }
         }
-        PatKind::Vec(_, _, _) => true,
+        PatKind::Vec(..) => true,
         _ => false
     }
 }
diff --git a/src/librustc/infer/error_reporting.rs b/src/librustc/infer/error_reporting.rs
index efce0c8354ba..753dd01d87ee 100644
--- a/src/librustc/infer/error_reporting.rs
+++ b/src/librustc/infer/error_reporting.rs
@@ -1787,7 +1787,7 @@ fn lifetimes_in_scope<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
     let method_id_opt = match tcx.map.find(parent) {
         Some(node) => match node {
             ast_map::NodeItem(item) => match item.node {
-                hir::ItemFn(_, _, _, _, ref gen, _) => {
+                hir::ItemFn(.., ref gen, _) => {
                     taken.extend_from_slice(&gen.lifetimes);
                     None
                 },
@@ -1811,7 +1811,7 @@ fn lifetimes_in_scope<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
         if let Some(node) = tcx.map.find(parent) {
             match node {
                 ast_map::NodeItem(item) => match item.node {
-                    hir::ItemImpl(_, _, ref gen, _, _, _) => {
+                    hir::ItemImpl(_, _, ref gen, ..) => {
                         taken.extend_from_slice(&gen.lifetimes);
                     }
                     _ => ()
diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs
index b6114f293ad3..bc5ca76c3f85 100644
--- a/src/librustc/infer/mod.rs
+++ b/src/librustc/infer/mod.rs
@@ -248,7 +248,7 @@ impl TypeOrigin {
             &TypeOrigin::RelateOutputImplTypes(_) => {
                 "trait type parameters matches those specified on the impl"
             }
-            &TypeOrigin::MatchExpressionArm(_, _, _) => "match arms have compatible types",
+            &TypeOrigin::MatchExpressionArm(..) => "match arms have compatible types",
             &TypeOrigin::IfExpression(_) => "if and else have compatible types",
             &TypeOrigin::IfExpressionWithNoElse(_) => "if missing an else returns ()",
             &TypeOrigin::RangeExpression(_) => "start and end of range have compatible types",
diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs
index 1e4b2e9116fd..f70349d0ee08 100644
--- a/src/librustc/lib.rs
+++ b/src/librustc/lib.rs
@@ -30,6 +30,7 @@
 #![feature(conservative_impl_trait)]
 #![feature(const_fn)]
 #![feature(core_intrinsics)]
+#![feature(dotdot_in_tuple_patterns)]
 #![feature(enumset)]
 #![feature(libc)]
 #![feature(nonzero)]
diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs
index 0b1d9e8d8f69..8cb362c1625a 100644
--- a/src/librustc/middle/dead.rs
+++ b/src/librustc/middle/dead.rs
@@ -344,7 +344,7 @@ impl<'v> Visitor<'v> for LifeSeeder {
                 self.worklist.extend(enum_def.variants.iter()
                                                       .map(|variant| variant.node.data.id()));
             }
-            hir::ItemTrait(_, _, _, ref trait_items) => {
+            hir::ItemTrait(.., ref trait_items) => {
                 for trait_item in trait_items {
                     match trait_item.node {
                         hir::ConstTraitItem(_, Some(_)) |
@@ -357,7 +357,7 @@ impl<'v> Visitor<'v> for LifeSeeder {
                     }
                 }
             }
-            hir::ItemImpl(_, _, _, ref opt_trait, _, ref impl_items) => {
+            hir::ItemImpl(.., ref opt_trait, _, ref impl_items) => {
                 for impl_item in impl_items {
                     if opt_trait.is_some() ||
                             has_allow_dead_code_or_lang_attr(&impl_item.attrs) {
diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs
index e52eba68da19..66c55eb1f3e5 100644
--- a/src/librustc/middle/effect.rs
+++ b/src/librustc/middle/effect.rs
@@ -83,7 +83,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EffectCheckVisitor<'a, 'tcx> {
                 block: &'v hir::Block, span: Span, id: ast::NodeId) {
 
         let (is_item_fn, is_unsafe_fn) = match fn_kind {
-            FnKind::ItemFn(_, _, unsafety, _, _, _, _) =>
+            FnKind::ItemFn(_, _, unsafety, ..) =>
                 (true, unsafety == hir::Unsafety::Unsafe),
             FnKind::Method(_, sig, _, _) =>
                 (true, sig.unsafety == hir::Unsafety::Unsafe),
@@ -143,7 +143,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EffectCheckVisitor<'a, 'tcx> {
 
     fn visit_expr(&mut self, expr: &hir::Expr) {
         match expr.node {
-            hir::ExprMethodCall(_, _, _) => {
+            hir::ExprMethodCall(..) => {
                 let method_call = MethodCall::expr(expr.id);
                 let base_type = self.tcx.tables.borrow().method_map[&method_call].ty;
                 debug!("effect: method call case, base type is {:?}",
diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs
index 541aeeb7d8dd..66c8a8ac0d37 100644
--- a/src/librustc/middle/expr_use_visitor.rs
+++ b/src/librustc/middle/expr_use_visitor.rs
@@ -544,7 +544,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
                 self.consume_expr(&count);
             }
 
-            hir::ExprClosure(_, _, _, fn_decl_span) => {
+            hir::ExprClosure(.., fn_decl_span) => {
                 self.walk_captures(expr, fn_decl_span)
             }
 
diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs
index 0625504af88e..beffaff1e5b8 100644
--- a/src/librustc/middle/reachable.rs
+++ b/src/librustc/middle/reachable.rs
@@ -46,8 +46,8 @@ fn item_might_be_inlined(item: &hir::Item) -> bool {
     }
 
     match item.node {
-        hir::ItemImpl(_, _, ref generics, _, _, _) |
-        hir::ItemFn(_, _, _, _, ref generics, _) => {
+        hir::ItemImpl(_, _, ref generics, ..) |
+        hir::ItemFn(.., ref generics, _) => {
             generics_require_inlining(generics)
         }
         _ => false,
@@ -187,7 +187,7 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
                             // does too.
                             let impl_node_id = self.tcx.map.as_local_node_id(impl_did).unwrap();
                             match self.tcx.map.expect_item(impl_node_id).node {
-                                hir::ItemImpl(_, _, ref generics, _, _, _) => {
+                                hir::ItemImpl(_, _, ref generics, ..) => {
                                     generics_require_inlining(generics)
                                 }
                                 _ => false
@@ -226,7 +226,7 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
             // If we are building an executable, only explicitly extern
             // types need to be exported.
             if let ast_map::NodeItem(item) = *node {
-                let reachable = if let hir::ItemFn(_, _, _, abi, _, _) = item.node {
+                let reachable = if let hir::ItemFn(.., abi, _, _) = item.node {
                     abi != Abi::Rust
                 } else {
                     false
@@ -248,7 +248,7 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
         match *node {
             ast_map::NodeItem(item) => {
                 match item.node {
-                    hir::ItemFn(_, _, _, _, _, ref search_block) => {
+                    hir::ItemFn(.., ref search_block) => {
                         if item_might_be_inlined(&item) {
                             intravisit::walk_block(self, &search_block)
                         }
@@ -265,7 +265,7 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
                     // inherently and their children are already in the
                     // worklist, as determined by the privacy pass
                     hir::ItemExternCrate(_) | hir::ItemUse(_) |
-                    hir::ItemTy(..) | hir::ItemStatic(_, _, _) |
+                    hir::ItemTy(..) | hir::ItemStatic(..) |
                     hir::ItemMod(..) | hir::ItemForeignMod(..) |
                     hir::ItemImpl(..) | hir::ItemTrait(..) |
                     hir::ItemStruct(..) | hir::ItemEnum(..) |
@@ -329,7 +329,7 @@ struct CollectPrivateImplItemsVisitor<'a> {
 impl<'a, 'v> Visitor<'v> for CollectPrivateImplItemsVisitor<'a> {
     fn visit_item(&mut self, item: &hir::Item) {
         // We need only trait impls here, not inherent impls, and only non-exported ones
-        if let hir::ItemImpl(_, _, _, Some(_), _, ref impl_items) = item.node {
+        if let hir::ItemImpl(.., Some(_), _, ref impl_items) = item.node {
             if !self.access_levels.is_reachable(item.id) {
                 for impl_item in impl_items {
                     self.worklist.push(impl_item.id);
diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs
index 4d1eed612cfd..b6faf834b26f 100644
--- a/src/librustc/middle/resolve_lifetime.rs
+++ b/src/librustc/middle/resolve_lifetime.rs
@@ -158,7 +158,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for LifetimeContext<'a, 'tcx> {
                 hir::ItemStruct(_, ref generics) |
                 hir::ItemUnion(_, ref generics) |
                 hir::ItemTrait(_, ref generics, _, _) |
-                hir::ItemImpl(_, _, ref generics, _, _, _) => {
+                hir::ItemImpl(_, _, ref generics, ..) => {
                     // These kinds of items have only early bound lifetime parameters.
                     let lifetimes = &generics.lifetimes;
                     let start = if let hir::ItemTrait(..) = item.node {
@@ -204,7 +204,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for LifetimeContext<'a, 'tcx> {
     fn visit_fn(&mut self, fk: FnKind<'v>, decl: &'v hir::FnDecl,
                 b: &'v hir::Block, s: Span, fn_id: ast::NodeId) {
         match fk {
-            FnKind::ItemFn(_, generics, _, _, _, _, _) => {
+            FnKind::ItemFn(_, generics, ..) => {
                 self.visit_early_late(fn_id,decl, generics, |this| {
                     this.add_scope_and_walk_fn(fk, decl, b, s, fn_id)
                 })
@@ -499,7 +499,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
                                  fn_id: ast::NodeId) {
 
         match fk {
-            FnKind::ItemFn(_, generics, _, _, _, _, _) => {
+            FnKind::ItemFn(_, generics, ..) => {
                 intravisit::walk_fn_decl(self, fd);
                 self.visit_generics(generics);
             }
@@ -584,7 +584,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
             }
             match parent.node {
                 hir::ItemTrait(_, ref generics, _, _) |
-                hir::ItemImpl(_, _, ref generics, _, _, _) => {
+                hir::ItemImpl(_, _, ref generics, ..) => {
                     start += generics.lifetimes.len() + generics.ty_params.len();
                 }
                 _ => {}
diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs
index aea1ee8d8240..9fc83557fa44 100644
--- a/src/librustc/middle/stability.rs
+++ b/src/librustc/middle/stability.rs
@@ -252,11 +252,11 @@ impl<'a, 'tcx, 'v> Visitor<'v> for Annotator<'a, 'tcx> {
             // they don't have their own stability. They still can be annotated as unstable
             // and propagate this unstability to children, but this annotation is completely
             // optional. They inherit stability from their parents when unannotated.
-            hir::ItemImpl(_, _, _, None, _, _) | hir::ItemForeignMod(..) => {
+            hir::ItemImpl(.., None, _, _) | hir::ItemForeignMod(..) => {
                 self.in_trait_impl = false;
                 kind = AnnotationKind::Container;
             }
-            hir::ItemImpl(_, _, _, Some(_), _, _) => {
+            hir::ItemImpl(.., Some(_), _, _) => {
                 self.in_trait_impl = true;
             }
             hir::ItemStruct(ref sd, _) => {
@@ -528,7 +528,7 @@ pub fn check_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         // For implementations of traits, check the stability of each item
         // individually as it's possible to have a stable trait with unstable
         // items.
-        hir::ItemImpl(_, _, _, Some(ref t), _, ref impl_items) => {
+        hir::ItemImpl(.., Some(ref t), _, ref impl_items) => {
             let trait_did = tcx.expect_def(t.ref_id).def_id();
             let trait_items = tcx.trait_items(trait_did);
 
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 3c450e14dea8..a9b3833b4017 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -1336,7 +1336,7 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> {
             }
             Some(ast_map::NodeItem(item)) => {
                 match item.node {
-                    hir::ItemFn(_, _, _, _, _, ref body) => {
+                    hir::ItemFn(.., ref body) => {
                         // We assume this is a function.
                         let fn_def_id = tcx.map.local_def_id(id);
 
@@ -2262,7 +2262,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
 
     pub fn provided_trait_methods(self, id: DefId) -> Vec>> {
         if let Some(id) = self.map.as_local_node_id(id) {
-            if let ItemTrait(_, _, _, ref ms) = self.map.expect_item(id).node {
+            if let ItemTrait(.., ref ms) = self.map.expect_item(id).node {
                 ms.iter().filter_map(|ti| {
                     if let hir::MethodTraitItem(_, Some(_)) = ti.node {
                         match self.impl_or_trait_item(self.map.local_def_id(ti.id)) {
@@ -2288,7 +2288,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     pub fn associated_consts(self, id: DefId) -> Vec>> {
         if let Some(id) = self.map.as_local_node_id(id) {
             match self.map.expect_item(id).node {
-                ItemTrait(_, _, _, ref tis) => {
+                ItemTrait(.., ref tis) => {
                     tis.iter().filter_map(|ti| {
                         if let hir::ConstTraitItem(_, _) = ti.node {
                             match self.impl_or_trait_item(self.map.local_def_id(ti.id)) {
@@ -2304,7 +2304,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
                         }
                     }).collect()
                 }
-                ItemImpl(_, _, _, _, _, ref iis) => {
+                ItemImpl(.., ref iis) => {
                     iis.iter().filter_map(|ii| {
                         if let hir::ImplItemKind::Const(_, _) = ii.node {
                             match self.impl_or_trait_item(self.map.local_def_id(ii.id)) {
@@ -2334,7 +2334,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
             match self.map.find(id) {
                 Some(ast_map::NodeItem(item)) => {
                     match item.node {
-                        hir::ItemImpl(_, polarity, _, _, _, _) => Some(polarity),
+                        hir::ItemImpl(_, polarity, ..) => Some(polarity),
                         _ => None
                     }
                 }
diff --git a/src/librustc_borrowck/borrowck/mir/mod.rs b/src/librustc_borrowck/borrowck/mir/mod.rs
index be408e2db5c3..9c462feeaadd 100644
--- a/src/librustc_borrowck/borrowck/mir/mod.rs
+++ b/src/librustc_borrowck/borrowck/mir/mod.rs
@@ -67,8 +67,8 @@ pub fn borrowck_mir<'a, 'tcx: 'a>(
     id: ast::NodeId,
     attributes: &[ast::Attribute]) {
     match fk {
-        FnKind::ItemFn(name, _, _, _, _, _, _) |
-        FnKind::Method(name, _, _, _) => {
+        FnKind::ItemFn(name, ..) |
+        FnKind::Method(name, ..) => {
             debug!("borrowck_mir({}) UNIMPLEMENTED", name);
         }
         FnKind::Closure(_) => {
diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs
index f5e20285e0c1..e25adadbb244 100644
--- a/src/librustc_borrowck/borrowck/mod.rs
+++ b/src/librustc_borrowck/borrowck/mod.rs
@@ -711,7 +711,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
 
             move_data::Captured =>
                 (match self.tcx.map.expect_expr(the_move.id).node {
-                    hir::ExprClosure(_, _, _, fn_decl_span) => fn_decl_span,
+                    hir::ExprClosure(.., fn_decl_span) => fn_decl_span,
                     ref r => bug!("Captured({}) maps to non-closure: {:?}",
                                   the_move.id, r),
                 }, " (into closure)"),
diff --git a/src/librustc_borrowck/lib.rs b/src/librustc_borrowck/lib.rs
index 16fefee34726..22b590592fe1 100644
--- a/src/librustc_borrowck/lib.rs
+++ b/src/librustc_borrowck/lib.rs
@@ -19,6 +19,7 @@
 
 #![allow(non_camel_case_types)]
 
+#![feature(dotdot_in_tuple_patterns)]
 #![feature(quote)]
 #![feature(rustc_diagnostic_macros)]
 #![feature(rustc_private)]
diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs
index 114b5e1331de..a74b8848c4d6 100644
--- a/src/librustc_const_eval/eval.rs
+++ b/src/librustc_const_eval/eval.rs
@@ -228,7 +228,7 @@ pub fn lookup_const_fn_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefI
     };
 
     match fn_like.kind() {
-        FnKind::ItemFn(_, _, _, hir::Constness::Const, _, _, _) => {
+        FnKind::ItemFn(_, _, _, hir::Constness::Const, ..) => {
             Some(fn_like)
         }
         FnKind::Method(_, m, _, _) => {
diff --git a/src/librustc_const_eval/lib.rs b/src/librustc_const_eval/lib.rs
index a6714c178e7c..f926fef065ea 100644
--- a/src/librustc_const_eval/lib.rs
+++ b/src/librustc_const_eval/lib.rs
@@ -22,7 +22,7 @@
       html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
       html_root_url = "https://doc.rust-lang.org/nightly/")]
 
-
+#![feature(dotdot_in_tuple_patterns)]
 #![feature(rustc_private)]
 #![feature(staged_api)]
 #![feature(rustc_diagnostic_macros)]
diff --git a/src/librustc_lint/bad_style.rs b/src/librustc_lint/bad_style.rs
index 1094d0ee12bb..84d65308f952 100644
--- a/src/librustc_lint/bad_style.rs
+++ b/src/librustc_lint/bad_style.rs
@@ -239,7 +239,7 @@ impl LateLintPass for NonSnakeCase {
                 fk: FnKind, _: &hir::FnDecl,
                 _: &hir::Block, span: Span, id: ast::NodeId) {
         match fk {
-            FnKind::Method(name, _, _, _) => match method_context(cx, id, span) {
+            FnKind::Method(name, ..) => match method_context(cx, id, span) {
                 MethodLateContext::PlainImpl => {
                     self.check_snake_case(cx, "method", &name.as_str(), Some(span))
                 },
@@ -248,7 +248,7 @@ impl LateLintPass for NonSnakeCase {
                 },
                 _ => (),
             },
-            FnKind::ItemFn(name, _, _, _, _, _, _) => {
+            FnKind::ItemFn(name, ..) => {
                 self.check_snake_case(cx, "function", &name.as_str(), Some(span))
             },
             FnKind::Closure(_) => (),
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index 1702c1c0edc9..eb2ded45c04c 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -203,10 +203,10 @@ impl LateLintPass for UnsafeCode {
 
     fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
         match it.node {
-            hir::ItemTrait(hir::Unsafety::Unsafe, _, _, _) =>
+            hir::ItemTrait(hir::Unsafety::Unsafe, ..) =>
                 cx.span_lint(UNSAFE_CODE, it.span, "declaration of an `unsafe` trait"),
 
-            hir::ItemImpl(hir::Unsafety::Unsafe, _, _, _, _, _) =>
+            hir::ItemImpl(hir::Unsafety::Unsafe, ..) =>
                 cx.span_lint(UNSAFE_CODE, it.span, "implementation of an `unsafe` trait"),
 
             _ => return,
@@ -216,7 +216,7 @@ impl LateLintPass for UnsafeCode {
     fn check_fn(&mut self, cx: &LateContext, fk: FnKind, _: &hir::FnDecl,
                 _: &hir::Block, span: Span, _: ast::NodeId) {
         match fk {
-            FnKind::ItemFn(_, _, hir::Unsafety::Unsafe, _, _, _, _) =>
+            FnKind::ItemFn(_, _, hir::Unsafety::Unsafe, ..) =>
                 cx.span_lint(UNSAFE_CODE, span, "declaration of an `unsafe` function"),
 
             FnKind::Method(_, sig, _, _) => {
@@ -351,7 +351,7 @@ impl LateLintPass for MissingDoc {
             hir::ItemEnum(..) => "an enum",
             hir::ItemStruct(..) => "a struct",
             hir::ItemUnion(..) => "a union",
-            hir::ItemTrait(_, _, _, ref items) => {
+            hir::ItemTrait(.., ref items) => {
                 // Issue #11592, traits are always considered exported, even when private.
                 if it.vis == hir::Visibility::Inherited {
                     self.private_traits.insert(it.id);
@@ -363,7 +363,7 @@ impl LateLintPass for MissingDoc {
                 "a trait"
             },
             hir::ItemTy(..) => "a type alias",
-            hir::ItemImpl(_, _, _, Some(ref trait_ref), _, ref impl_items) => {
+            hir::ItemImpl(.., Some(ref trait_ref), _, ref impl_items) => {
                 // If the trait is private, add the impl items to private_traits so they don't get
                 // reported for missing docs.
                 let real_trait = cx.tcx.expect_def(trait_ref.ref_id).def_id();
@@ -1037,7 +1037,7 @@ impl LintPass for InvalidNoMangleItems {
 impl LateLintPass for InvalidNoMangleItems {
     fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
         match it.node {
-            hir::ItemFn(_, _, _, _, ref generics, _) => {
+            hir::ItemFn(.., ref generics, _) => {
                 if attr::contains_name(&it.attrs, "no_mangle") {
                     if !cx.access_levels.is_reachable(it.id) {
                         let msg = format!("function {} is marked #[no_mangle], but not exported",
diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs
index c3b752d605f9..b9817cc6ff45 100644
--- a/src/librustc_lint/lib.rs
+++ b/src/librustc_lint/lib.rs
@@ -31,6 +31,7 @@
 #![cfg_attr(test, feature(test))]
 #![feature(box_patterns)]
 #![feature(box_syntax)]
+#![feature(dotdot_in_tuple_patterns)]
 #![feature(quote)]
 #![feature(rustc_diagnostic_macros)]
 #![feature(rustc_private)]
diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs
index 35f5eba4160d..583631d2e0ab 100644
--- a/src/librustc_metadata/encoder.rs
+++ b/src/librustc_metadata/encoder.rs
@@ -1065,7 +1065,7 @@ impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> {
                 let trait_ref = tcx.impl_trait_ref(ecx.tcx.map.local_def_id(item.id)).unwrap();
                 encode_trait_ref(self.rbml_w, ecx, trait_ref, tag_item_trait_ref);
             }
-            hir::ItemImpl(unsafety, polarity, _, _, _, _) => {
+            hir::ItemImpl(unsafety, polarity, ..) => {
                 // We need to encode information about the default methods we
                 // have inherited, so we drive self based on the impl structure.
                 let impl_items = tcx.impl_items.borrow();
@@ -1129,7 +1129,7 @@ impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> {
                 encode_stability(self.rbml_w, stab);
                 encode_deprecation(self.rbml_w, depr);
             }
-            hir::ItemTrait(_, _, _, _) => {
+            hir::ItemTrait(..) => {
                 encode_def_id_and_key(ecx, self.rbml_w, def_id);
                 encode_family(self.rbml_w, 'I');
                 encode_item_variances(self.rbml_w, ecx, item.id);
@@ -1209,10 +1209,10 @@ impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> {
             hir::ItemUnion(..) => {
                 self.encode_addl_union_info(def_id);
             }
-            hir::ItemImpl(_, _, _, _, _, ref ast_items) => {
+            hir::ItemImpl(.., ref ast_items) => {
                 self.encode_addl_impl_info(def_id, item.id, ast_items);
             }
-            hir::ItemTrait(_, _, _, ref trait_items) => {
+            hir::ItemTrait(.., ref trait_items) => {
                 self.encode_addl_trait_info(def_id, trait_items);
             }
         }
diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs
index a3afb9d84bd3..84323d464660 100644
--- a/src/librustc_metadata/lib.rs
+++ b/src/librustc_metadata/lib.rs
@@ -18,6 +18,7 @@
 #![cfg_attr(not(stage0), deny(warnings))]
 
 #![feature(box_patterns)]
+#![feature(dotdot_in_tuple_patterns)]
 #![feature(enumset)]
 #![feature(question_mark)]
 #![feature(quote)]
diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs
index 1767630b81b1..919b23ffda54 100644
--- a/src/librustc_mir/hair/cx/mod.rs
+++ b/src/librustc_mir/hair/cx/mod.rs
@@ -53,7 +53,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
             MirSource::Fn(id) => {
                 let fn_like = FnLikeNode::from_node(infcx.tcx.map.get(id));
                 match fn_like.map(|f| f.kind()) {
-                    Some(FnKind::ItemFn(_, _, _, c, _, _, _)) => c,
+                    Some(FnKind::ItemFn(_, _, _, c, ..)) => c,
                     Some(FnKind::Method(_, m, _, _)) => m.constness,
                     _ => hir::Constness::NotConst
                 }
diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs
index 3d01d49c5347..f580ceeee5d7 100644
--- a/src/librustc_mir/lib.rs
+++ b/src/librustc_mir/lib.rs
@@ -22,6 +22,7 @@ Rust MIR: a lowered representation of Rust. Also: an experiment!
 
 #![feature(associated_consts)]
 #![feature(box_patterns)]
+#![feature(dotdot_in_tuple_patterns)]
 #![feature(rustc_diagnostic_macros)]
 #![feature(rustc_private)]
 #![feature(staged_api)]
diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs
index 6c6a5f7fc74b..751f25b27940 100644
--- a/src/librustc_mir/transform/qualify_consts.rs
+++ b/src/librustc_mir/transform/qualify_consts.rs
@@ -119,7 +119,7 @@ fn is_const_fn(tcx: TyCtxt, def_id: DefId) -> bool {
     if let Some(node_id) = tcx.map.as_local_node_id(def_id) {
         let fn_like = FnLikeNode::from_node(tcx.map.get(node_id));
         match fn_like.map(|f| f.kind()) {
-            Some(FnKind::ItemFn(_, _, _, c, _, _, _)) => {
+            Some(FnKind::ItemFn(_, _, _, c, ..)) => {
                 c == hir::Constness::Const
             }
             Some(FnKind::Method(_, m, _, _)) => {
diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs
index b8284f5dcf10..6a24742426ab 100644
--- a/src/librustc_passes/ast_validation.rs
+++ b/src/librustc_passes/ast_validation.rs
@@ -100,8 +100,8 @@ impl<'a> Visitor for AstValidator<'a> {
         match expr.node {
             ExprKind::While(_, _, Some(ident)) |
             ExprKind::Loop(_, Some(ident)) |
-            ExprKind::WhileLet(_, _, _, Some(ident)) |
-            ExprKind::ForLoop(_, _, _, Some(ident)) |
+            ExprKind::WhileLet(.., Some(ident)) |
+            ExprKind::ForLoop(.., Some(ident)) |
             ExprKind::Break(Some(ident)) |
             ExprKind::Continue(Some(ident)) => {
                 self.check_label(ident.node, ident.span, expr.id);
@@ -155,7 +155,7 @@ impl<'a> Visitor for AstValidator<'a> {
                         .span_err(path.span, "type or lifetime parameters in import path");
                 }
             }
-            ItemKind::Impl(_, _, _, Some(..), _, ref impl_items) => {
+            ItemKind::Impl(.., Some(..), _, ref impl_items) => {
                 self.invalid_visibility(&item.vis, item.span, None);
                 for impl_item in impl_items {
                     self.invalid_visibility(&impl_item.vis, impl_item.span, None);
@@ -164,7 +164,7 @@ impl<'a> Visitor for AstValidator<'a> {
                     }
                 }
             }
-            ItemKind::Impl(_, _, _, None, _, _) => {
+            ItemKind::Impl(.., None, _, _) => {
                 self.invalid_visibility(&item.vis,
                                         item.span,
                                         Some("place qualifiers on individual impl items instead"));
@@ -185,7 +185,7 @@ impl<'a> Visitor for AstValidator<'a> {
                     }
                 }
             }
-            ItemKind::Trait(_, _, _, ref trait_items) => {
+            ItemKind::Trait(.., ref trait_items) => {
                 for trait_item in trait_items {
                     if let TraitItemKind::Method(ref sig, _) = trait_item.node {
                         self.check_trait_fn_not_const(sig.constness);
diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs
index c3749bf4546f..3094ff49f1f5 100644
--- a/src/librustc_passes/consts.rs
+++ b/src/librustc_passes/consts.rs
@@ -147,7 +147,7 @@ impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> {
         }
 
         let mode = match fk {
-            FnKind::ItemFn(_, _, _, hir::Constness::Const, _, _, _)
+            FnKind::ItemFn(_, _, _, hir::Constness::Const, ..)
                 => Mode::ConstFn,
             FnKind::Method(_, m, _, _) => {
                 if m.constness == hir::Constness::Const {
diff --git a/src/librustc_passes/lib.rs b/src/librustc_passes/lib.rs
index e59c4a6fc418..a4657251c9ce 100644
--- a/src/librustc_passes/lib.rs
+++ b/src/librustc_passes/lib.rs
@@ -23,6 +23,7 @@
        html_root_url = "https://doc.rust-lang.org/nightly/")]
 #![cfg_attr(not(stage0), deny(warnings))]
 
+#![feature(dotdot_in_tuple_patterns)]
 #![feature(rustc_diagnostic_macros)]
 #![feature(staged_api)]
 #![feature(rustc_private)]
diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs
index 179863c16fff..5e374ce7c580 100644
--- a/src/librustc_privacy/lib.rs
+++ b/src/librustc_privacy/lib.rs
@@ -17,6 +17,7 @@
       html_root_url = "https://doc.rust-lang.org/nightly/")]
 #![cfg_attr(not(stage0), deny(warnings))]
 
+#![feature(dotdot_in_tuple_patterns)]
 #![feature(rustc_diagnostic_macros)]
 #![feature(rustc_private)]
 #![feature(staged_api)]
@@ -125,10 +126,10 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> {
     fn visit_item(&mut self, item: &hir::Item) {
         let inherited_item_level = match item.node {
             // Impls inherit level from their types and traits
-            hir::ItemImpl(_, _, _, None, ref ty, _) => {
+            hir::ItemImpl(.., None, ref ty, _) => {
                 self.ty_level(&ty)
             }
-            hir::ItemImpl(_, _, _, Some(ref trait_ref), ref ty, _) => {
+            hir::ItemImpl(.., Some(ref trait_ref), ref ty, _) => {
                 cmp::min(self.ty_level(&ty), self.trait_level(trait_ref))
             }
             hir::ItemDefaultImpl(_, ref trait_ref) => {
@@ -157,19 +158,19 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> {
                     }
                 }
             }
-            hir::ItemImpl(_, _, _, None, _, ref impl_items) => {
+            hir::ItemImpl(.., None, _, ref impl_items) => {
                 for impl_item in impl_items {
                     if impl_item.vis == hir::Public {
                         self.update(impl_item.id, item_level);
                     }
                 }
             }
-            hir::ItemImpl(_, _, _, Some(_), _, ref impl_items) => {
+            hir::ItemImpl(.., Some(_), _, ref impl_items) => {
                 for impl_item in impl_items {
                     self.update(impl_item.id, item_level);
                 }
             }
-            hir::ItemTrait(_, _, _, ref trait_items) => {
+            hir::ItemTrait(.., ref trait_items) => {
                 for trait_item in trait_items {
                     self.update(trait_item.id, item_level);
                 }
@@ -204,7 +205,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> {
             hir::ItemUse(..) => {}
             // Visit everything
             hir::ItemConst(..) | hir::ItemStatic(..) | hir::ItemFn(..) |
-            hir::ItemTrait(..) | hir::ItemTy(..) | hir::ItemImpl(_, _, _, Some(..), _, _) => {
+            hir::ItemTrait(..) | hir::ItemTy(..) | hir::ItemImpl(.., Some(..), _, _) => {
                 if item_level.is_some() {
                     self.reach().visit_item(item);
                 }
diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs
index 8e97870c21a5..98ddff70462c 100644
--- a/src/librustc_resolve/build_reduced_graph.rs
+++ b/src/librustc_resolve/build_reduced_graph.rs
@@ -232,7 +232,7 @@ impl<'b> Resolver<'b> {
                 let def = Def::Const(self.definitions.local_def_id(item.id));
                 self.define(parent, name, ValueNS, (def, sp, vis));
             }
-            ItemKind::Fn(_, _, _, _, _, _) => {
+            ItemKind::Fn(..) => {
                 let def = Def::Fn(self.definitions.local_def_id(item.id));
                 self.define(parent, name, ValueNS, (def, sp, vis));
             }
@@ -294,7 +294,7 @@ impl<'b> Resolver<'b> {
 
             ItemKind::DefaultImpl(_, _) | ItemKind::Impl(..) => {}
 
-            ItemKind::Trait(_, _, _, ref items) => {
+            ItemKind::Trait(.., ref items) => {
                 let def_id = self.definitions.local_def_id(item.id);
 
                 // Add all the items within to a new module.
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index db0704db33fd..0a86eeef7c45 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -19,6 +19,7 @@
 
 #![feature(associated_consts)]
 #![feature(borrow_state)]
+#![feature(dotdot_in_tuple_patterns)]
 #![feature(rustc_diagnostic_macros)]
 #![feature(rustc_private)]
 #![feature(staged_api)]
@@ -599,7 +600,7 @@ impl<'a> Visitor for Resolver<'a> {
                 _: Span,
                 node_id: NodeId) {
         let rib_kind = match function_kind {
-            FnKind::ItemFn(_, generics, _, _, _, _) => {
+            FnKind::ItemFn(_, generics, ..) => {
                 self.visit_generics(generics);
                 ItemRibKind
             }
@@ -1634,7 +1635,7 @@ impl<'a> Resolver<'a> {
             ItemKind::Ty(_, ref generics) |
             ItemKind::Struct(_, ref generics) |
             ItemKind::Union(_, ref generics) |
-            ItemKind::Fn(_, _, _, _, ref generics, _) => {
+            ItemKind::Fn(.., ref generics, _) => {
                 self.with_type_parameter_rib(HasTypeParameters(generics, ItemRibKind),
                                              |this| visit::walk_item(this, item));
             }
diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs
index f9a20cec42d1..329527b304e3 100644
--- a/src/librustc_save_analysis/dump_visitor.rs
+++ b/src/librustc_save_analysis/dump_visitor.rs
@@ -1137,7 +1137,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D>
                     }.lower(self.tcx));
                 }
             }
-            Fn(ref decl, _, _, _, ref ty_params, ref body) =>
+            Fn(ref decl, .., ref ty_params, ref body) =>
                 self.process_fn(item, &decl, ty_params, &body),
             Static(ref typ, _, ref expr) =>
                 self.process_static_or_const_item(item, typ, expr),
diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs
index 47f3a06de1bd..559893b26fac 100644
--- a/src/librustc_save_analysis/lib.rs
+++ b/src/librustc_save_analysis/lib.rs
@@ -18,6 +18,7 @@
 #![cfg_attr(not(stage0), deny(warnings))]
 
 #![feature(custom_attribute)]
+#![feature(dotdot_in_tuple_patterns)]
 #![allow(unused_attributes)]
 #![feature(rustc_private)]
 #![feature(staged_api)]
@@ -124,7 +125,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
 
     pub fn get_item_data(&self, item: &ast::Item) -> Option {
         match item.node {
-            ast::ItemKind::Fn(ref decl, _, _, _, ref generics, _) => {
+            ast::ItemKind::Fn(ref decl, .., ref generics, _) => {
                 let qualname = format!("::{}", self.tcx.node_path_str(item.id));
                 let sub_span = self.span_utils.sub_span_after_keyword(item.span, keywords::Fn);
                 filter!(self.span_utils, sub_span, item.span, None);
@@ -217,7 +218,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                     variants: def.variants.iter().map(|v| v.node.data.id()).collect(),
                 }))
             }
-            ast::ItemKind::Impl(_, _, _, ref trait_ref, ref typ, _) => {
+            ast::ItemKind::Impl(.., ref trait_ref, ref typ, _) => {
                 let mut type_data = None;
                 let sub_span;
 
@@ -295,7 +296,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
             Some(impl_id) => match self.tcx.map.get_if_local(impl_id) {
                 Some(NodeItem(item)) => {
                     match item.node {
-                        hir::ItemImpl(_, _, _, _, ref ty, _) => {
+                        hir::ItemImpl(.., ref ty, _) => {
                             let mut result = String::from("<");
                             result.push_str(&rustc::hir::print::ty_to_string(&ty));
 
diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs
index 4bea5d7e87fc..b5c922d7fda4 100644
--- a/src/librustc_trans/collector.rs
+++ b/src/librustc_trans/collector.rs
@@ -1152,7 +1152,7 @@ impl<'b, 'a, 'v> hir_visit::Visitor<'v> for RootCollector<'b, 'a, 'v> {
                 // const items only generate translation items if they are
                 // actually used somewhere. Just declaring them is insufficient.
             }
-            hir::ItemFn(_, _, _, _, ref generics, _) => {
+            hir::ItemFn(.., ref generics, _) => {
                 if !generics.is_type_parameterized() {
                     let def_id = self.scx.tcx().map.local_def_id(item.id);
 
@@ -1179,7 +1179,7 @@ impl<'b, 'a, 'v> hir_visit::Visitor<'v> for RootCollector<'b, 'a, 'v> {
                 let parent_node_id = hir_map.get_parent_node(ii.id);
                 let is_impl_generic = match hir_map.expect_item(parent_node_id) {
                     &hir::Item {
-                        node: hir::ItemImpl(_, _, ref generics, _, _, _),
+                        node: hir::ItemImpl(_, _, ref generics, ..),
                         ..
                     } => {
                         generics.is_type_parameterized()
diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs
index 6ede55d5ff49..6f5bac840a1d 100644
--- a/src/librustc_trans/lib.rs
+++ b/src/librustc_trans/lib.rs
@@ -27,6 +27,7 @@
 #![feature(box_syntax)]
 #![feature(const_fn)]
 #![feature(custom_attribute)]
+#![feature(dotdot_in_tuple_patterns)]
 #![allow(unused_attributes)]
 #![feature(libc)]
 #![feature(quote)]
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index c445455ef2bc..5925d222b446 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -1358,7 +1358,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
             // `ty::trait_items` used below requires information generated
             // by type collection, which may be in progress at this point.
             match tcx.map.expect_item(trait_id).node {
-                hir::ItemTrait(_, _, _, ref trait_items) => {
+                hir::ItemTrait(.., ref trait_items) => {
                     let item = trait_items.iter()
                                           .find(|i| i.name == assoc_name)
                                           .expect("missing associated type");
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index f4fea5542b3d..36c2494a0065 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -741,7 +741,7 @@ pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) {
                             it.id);
       }
       hir::ItemFn(..) => {} // entirely within check_item_body
-      hir::ItemImpl(_, _, _, _, _, ref impl_items) => {
+      hir::ItemImpl(.., ref impl_items) => {
           debug!("ItemImpl {} with id {}", it.name, it.id);
           let impl_def_id = ccx.tcx.map.local_def_id(it.id);
           match ccx.tcx.impl_trait_ref(impl_def_id) {
@@ -808,10 +808,10 @@ pub fn check_item_body<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) {
            ccx.tcx.item_path_str(ccx.tcx.map.local_def_id(it.id)));
     let _indenter = indenter();
     match it.node {
-      hir::ItemFn(ref decl, _, _, _, _, ref body) => {
+      hir::ItemFn(ref decl, .., ref body) => {
         check_bare_fn(ccx, &decl, &body, it.id);
       }
-      hir::ItemImpl(_, _, _, _, _, ref impl_items) => {
+      hir::ItemImpl(.., ref impl_items) => {
         debug!("ItemImpl {} with id {}", it.name, it.id);
 
         for impl_item in impl_items {
@@ -828,7 +828,7 @@ pub fn check_item_body<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) {
             }
         }
       }
-      hir::ItemTrait(_, _, _, ref trait_items) => {
+      hir::ItemTrait(.., ref trait_items) => {
         for trait_item in trait_items {
             match trait_item.node {
                 hir::ConstTraitItem(_, Some(ref expr)) => {
diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs
index 7dff30d03c33..8eb7d3456876 100644
--- a/src/librustc_typeck/check/wfcheck.rs
+++ b/src/librustc_typeck/check/wfcheck.rs
@@ -126,7 +126,7 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
                     }
                 }
             }
-            hir::ItemFn(_, _, _, _, _, ref body) => {
+            hir::ItemFn(.., ref body) => {
                 self.check_item_fn(item, body);
             }
             hir::ItemStatic(..) => {
@@ -156,7 +156,7 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
 
                 self.check_variances_for_type_defn(item, ast_generics);
             }
-            hir::ItemTrait(_, _, _, ref items) => {
+            hir::ItemTrait(.., ref items) => {
                 self.check_trait(item, items);
             }
             _ => {}
diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs
index fba145efa950..70682bb8c8f3 100644
--- a/src/librustc_typeck/coherence/mod.rs
+++ b/src/librustc_typeck/coherence/mod.rs
@@ -195,7 +195,7 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> {
     // Converts an implementation in the AST to a vector of items.
     fn create_impl_from_item(&self, item: &Item) -> Vec {
         match item.node {
-            ItemImpl(_, _, _, _, _, ref impl_items) => {
+            ItemImpl(.., ref impl_items) => {
                 impl_items.iter().map(|impl_item| {
                     let impl_def_id = self.crate_context.tcx.map.local_def_id(impl_item.id);
                     match impl_item.node {
@@ -252,7 +252,7 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> {
                         match tcx.map.find(impl_node_id) {
                             Some(hir_map::NodeItem(item)) => {
                                 let span = match item.node {
-                                    ItemImpl(_, _, _, _, ref ty, _) => {
+                                    ItemImpl(.., ref ty, _) => {
                                         ty.span
                                     },
                                     _ => item.span
@@ -324,7 +324,7 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> {
                 }
                 Err(CopyImplementationError::InfrigingVariant(name)) => {
                     let item = tcx.map.expect_item(impl_node_id);
-                    let span = if let ItemImpl(_, _, _, Some(ref tr), _, _) = item.node {
+                    let span = if let ItemImpl(.., Some(ref tr), _, _) = item.node {
                         tr.path.span
                     } else {
                         span
@@ -338,7 +338,7 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> {
                 }
                 Err(CopyImplementationError::NotAnAdt) => {
                     let item = tcx.map.expect_item(impl_node_id);
-                    let span = if let ItemImpl(_, _, _, _, ref ty, _) = item.node {
+                    let span = if let ItemImpl(.., ref ty, _) = item.node {
                         ty.span
                     } else {
                         span
@@ -463,7 +463,7 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> {
                             return;
                         } else if diff_fields.len() > 1 {
                             let item = tcx.map.expect_item(impl_node_id);
-                            let span = if let ItemImpl(_, _, _, Some(ref t), _, _) = item.node {
+                            let span = if let ItemImpl(.., Some(ref t), _, _) = item.node {
                                 t.path.span
                             } else {
                                 tcx.map.span(impl_node_id)
diff --git a/src/librustc_typeck/coherence/orphan.rs b/src/librustc_typeck/coherence/orphan.rs
index 4c38475335ce..cb424eb48e93 100644
--- a/src/librustc_typeck/coherence/orphan.rs
+++ b/src/librustc_typeck/coherence/orphan.rs
@@ -68,7 +68,7 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> {
     fn check_item(&self, item: &hir::Item) {
         let def_id = self.tcx.map.local_def_id(item.id);
         match item.node {
-            hir::ItemImpl(_, _, _, None, ref ty, _) => {
+            hir::ItemImpl(.., None, ref ty, _) => {
                 // For inherent impls, self type must be a nominal type
                 // defined in this crate.
                 debug!("coherence2::orphan check: inherent impl {}",
@@ -222,7 +222,7 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> {
                     }
                 }
             }
-            hir::ItemImpl(_, _, _, Some(_), _, _) => {
+            hir::ItemImpl(.., Some(_), _, _) => {
                 // "Trait" impl
                 debug!("coherence2::orphan check: trait impl {}",
                        self.tcx.map.node_to_string(item.id));
diff --git a/src/librustc_typeck/coherence/overlap.rs b/src/librustc_typeck/coherence/overlap.rs
index c4d925372f18..890b6c72e6fe 100644
--- a/src/librustc_typeck/coherence/overlap.rs
+++ b/src/librustc_typeck/coherence/overlap.rs
@@ -122,7 +122,7 @@ impl<'cx, 'tcx,'v> intravisit::Visitor<'v> for OverlapChecker<'cx, 'tcx> {
                     err.emit();
                 }
             }
-            hir::ItemImpl(_, _, _, Some(_), _, _) => {
+            hir::ItemImpl(.., Some(_), _, _) => {
                 let impl_def_id = self.tcx.map.local_def_id(item.id);
                 let trait_ref = self.tcx.impl_trait_ref(impl_def_id).unwrap();
                 let trait_def_id = trait_ref.def_id;
diff --git a/src/librustc_typeck/coherence/unsafety.rs b/src/librustc_typeck/coherence/unsafety.rs
index 53ec72abac05..cdf5478e692b 100644
--- a/src/librustc_typeck/coherence/unsafety.rs
+++ b/src/librustc_typeck/coherence/unsafety.rs
@@ -81,7 +81,7 @@ impl<'cx, 'tcx,'v> intravisit::Visitor<'v> for UnsafetyChecker<'cx, 'tcx> {
             hir::ItemDefaultImpl(unsafety, _) => {
                 self.check_unsafety_coherence(item, unsafety, hir::ImplPolarity::Positive);
             }
-            hir::ItemImpl(unsafety, polarity, _, _, _, _) => {
+            hir::ItemImpl(unsafety, polarity, ..) => {
                 self.check_unsafety_coherence(item, unsafety, polarity);
             }
             _ => { }
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 55db44a2c310..a012fd418cac 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -850,7 +850,7 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
 
             enforce_impl_lifetimes_are_constrained(ccx, generics, def_id, impl_items);
         },
-        hir::ItemTrait(_, _, _, ref trait_items) => {
+        hir::ItemTrait(.., ref trait_items) => {
             let trait_def = trait_def_of_item(ccx, it);
             let def_id = trait_def.trait_ref.def_id;
             let _: Result<(), ErrorReported> = // any error is already reported, can ignore
@@ -1311,7 +1311,7 @@ fn trait_defines_associated_type_named(ccx: &CrateCtxt,
     };
 
     let trait_items = match item.node {
-        hir::ItemTrait(_, _, _, ref trait_items) => trait_items,
+        hir::ItemTrait(.., ref trait_items) => trait_items,
         _ => bug!("trait_node_id {} is not a trait", trait_node_id)
     };
 
@@ -1445,8 +1445,8 @@ fn generics_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
 
             NodeItem(item) => {
                 match item.node {
-                    ItemFn(_, _, _, _, ref generics, _) |
-                    ItemImpl(_, _, ref generics, _, _, _) => generics,
+                    ItemFn(.., ref generics, _) |
+                    ItemImpl(_, _, ref generics, ..) => generics,
 
                     ItemTy(_, ref generics) |
                     ItemEnum(_, ref generics) |
@@ -1651,7 +1651,7 @@ fn predicates_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
 
     let no_generics = hir::Generics::empty();
     let generics = match it.node {
-        hir::ItemFn(_, _, _, _, ref generics, _) |
+        hir::ItemFn(.., ref generics, _) |
         hir::ItemTy(_, ref generics) |
         hir::ItemEnum(_, ref generics) |
         hir::ItemStruct(_, ref generics) |
diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs
index a5445b18e77f..d2e2d578fced 100644
--- a/src/librustc_typeck/lib.rs
+++ b/src/librustc_typeck/lib.rs
@@ -76,6 +76,7 @@ This API is completely unstable and subject to change.
 
 #![feature(box_patterns)]
 #![feature(box_syntax)]
+#![feature(dotdot_in_tuple_patterns)]
 #![feature(quote)]
 #![feature(rustc_diagnostic_macros)]
 #![feature(rustc_private)]
@@ -215,7 +216,7 @@ fn check_main_fn_ty(ccx: &CrateCtxt,
             match tcx.map.find(main_id) {
                 Some(hir_map::NodeItem(it)) => {
                     match it.node {
-                        hir::ItemFn(_, _, _, _, ref generics, _) => {
+                        hir::ItemFn(.., ref generics, _) => {
                             if generics.is_parameterized() {
                                 struct_span_err!(ccx.tcx.sess, generics.span, E0131,
                                          "main function is not allowed to have type parameters")
@@ -267,7 +268,7 @@ fn check_start_fn_ty(ccx: &CrateCtxt,
             match tcx.map.find(start_id) {
                 Some(hir_map::NodeItem(it)) => {
                     match it.node {
-                        hir::ItemFn(_,_,_,_,ref ps,_)
+                        hir::ItemFn(..,ref ps,_)
                         if ps.is_parameterized() => {
                             struct_span_err!(tcx.sess, ps.span, E0132,
                                 "start function is not allowed to have type parameters")
diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs
index 44d1fbfdb70b..4a637b5cfcff 100644
--- a/src/libstd/lib.rs
+++ b/src/libstd/lib.rs
@@ -227,6 +227,7 @@
 #![feature(const_fn)]
 #![feature(core_float)]
 #![feature(core_intrinsics)]
+#![feature(dotdot_in_tuple_patterns)]
 #![feature(dropck_parametricity)]
 #![feature(float_extras)]
 #![feature(float_from_str_radix)]
diff --git a/src/libstd/sys/windows/fs.rs b/src/libstd/sys/windows/fs.rs
index fe448cdd78fe..90a16853d56d 100644
--- a/src/libstd/sys/windows/fs.rs
+++ b/src/libstd/sys/windows/fs.rs
@@ -200,7 +200,7 @@ impl OpenOptions {
         const ERROR_INVALID_PARAMETER: i32 = 87;
 
         match (self.read, self.write, self.append, self.access_mode) {
-            (_, _, _, Some(mode)) => Ok(mode),
+            (.., Some(mode)) => Ok(mode),
             (true,  false, false, None) => Ok(c::GENERIC_READ),
             (false, true,  false, None) => Ok(c::GENERIC_WRITE),
             (true,  true,  false, None) => Ok(c::GENERIC_READ | c::GENERIC_WRITE),
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 4394fb0e1431..bbd334514458 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -562,7 +562,7 @@ impl Pat {
             PatKind::Wild |
             PatKind::Lit(_) |
             PatKind::Range(_, _) |
-            PatKind::Ident(_, _, _) |
+            PatKind::Ident(..) |
             PatKind::Path(..) |
             PatKind::Mac(_) => {
                 true
diff --git a/src/test/compile-fail-fulldeps/auxiliary/macro_crate_test.rs b/src/test/compile-fail-fulldeps/auxiliary/macro_crate_test.rs
index 5a3412b7ed9f..5b1ecfed2427 100644
--- a/src/test/compile-fail-fulldeps/auxiliary/macro_crate_test.rs
+++ b/src/test/compile-fail-fulldeps/auxiliary/macro_crate_test.rs
@@ -10,6 +10,7 @@
 
 // force-host
 
+#![feature(dotdot_in_tuple_patterns)]
 #![feature(plugin_registrar, quote, rustc_private)]
 
 extern crate syntax;
@@ -75,7 +76,7 @@ fn expand_into_foo_multi(cx: &mut ExtCtxt,
         Annotatable::ImplItem(_) => {
             quote_item!(cx, impl X { fn foo(&self) -> i32 { 42 } }).unwrap().and_then(|i| {
                 match i.node {
-                    ItemKind::Impl(_, _, _, _, _, mut items) => {
+                    ItemKind::Impl(.., mut items) => {
                         Annotatable::ImplItem(P(items.pop().expect("impl method not found")))
                     }
                     _ => unreachable!("impl parsed to something other than impl")
@@ -85,7 +86,7 @@ fn expand_into_foo_multi(cx: &mut ExtCtxt,
         Annotatable::TraitItem(_) => {
             quote_item!(cx, trait X { fn foo(&self) -> i32 { 0 } }).unwrap().and_then(|i| {
                 match i.node {
-                    ItemKind::Trait(_, _, _, mut items) => {
+                    ItemKind::Trait(.., mut items) => {
                         Annotatable::TraitItem(P(items.pop().expect("trait method not found")))
                     }
                     _ => unreachable!("trait parsed to something other than trait")
diff --git a/src/test/run-pass-fulldeps/auxiliary/macro_crate_test.rs b/src/test/run-pass-fulldeps/auxiliary/macro_crate_test.rs
index 46fdf9112584..4885863122c3 100644
--- a/src/test/run-pass-fulldeps/auxiliary/macro_crate_test.rs
+++ b/src/test/run-pass-fulldeps/auxiliary/macro_crate_test.rs
@@ -10,6 +10,7 @@
 
 // force-host
 
+#![feature(dotdot_in_tuple_patterns)]
 #![feature(plugin_registrar, quote, rustc_private)]
 
 extern crate syntax;
@@ -81,7 +82,7 @@ fn expand_into_foo_multi(cx: &mut ExtCtxt,
         Annotatable::ImplItem(_it) => vec![
             quote_item!(cx, impl X { fn foo(&self) -> i32 { 42 } }).unwrap().and_then(|i| {
                 match i.node {
-                    ItemKind::Impl(_, _, _, _, _, mut items) => {
+                    ItemKind::Impl(.., mut items) => {
                         Annotatable::ImplItem(P(items.pop().expect("impl method not found")))
                     }
                     _ => unreachable!("impl parsed to something other than impl")
@@ -91,7 +92,7 @@ fn expand_into_foo_multi(cx: &mut ExtCtxt,
         Annotatable::TraitItem(_it) => vec![
             quote_item!(cx, trait X { fn foo(&self) -> i32 { 0 } }).unwrap().and_then(|i| {
                 match i.node {
-                    ItemKind::Trait(_, _, _, mut items) => {
+                    ItemKind::Trait(.., mut items) => {
                         Annotatable::TraitItem(P(items.pop().expect("trait method not found")))
                     }
                     _ => unreachable!("trait parsed to something other than trait")
@@ -165,7 +166,7 @@ fn expand_caller(cx: &mut ExtCtxt,
                  push: &mut FnMut(Annotatable)) {
     let (orig_fn_name, ret_type) = match *it {
         Annotatable::Item(ref item) => match item.node {
-            ItemKind::Fn(ref decl, _, _, _, _, _) => {
+            ItemKind::Fn(ref decl, ..) => {
                 (item.ident, &decl.output)
             }
             _ => cx.span_fatal(item.span, "Only functions with return types can be annotated.")

From e05e74ac831bc8438f5daeb98432a29285ed9514 Mon Sep 17 00:00:00 2001
From: Vadim Petrochenkov 
Date: Fri, 26 Aug 2016 19:23:42 +0300
Subject: [PATCH 158/443] Replace `_, _` with `..`

---
 src/libgetopts/lib.rs                         |  2 +-
 src/librustc/cfg/construct.rs                 |  6 ++---
 src/librustc/hir/def.rs                       |  2 +-
 src/librustc/hir/intravisit.rs                |  4 +--
 src/librustc/hir/map/collector.rs             |  2 +-
 src/librustc/hir/mod.rs                       |  4 +--
 src/librustc/hir/pat_util.rs                  |  2 +-
 src/librustc/infer/error_reporting.rs         |  6 ++---
 src/librustc/infer/higher_ranked/mod.rs       |  2 +-
 src/librustc/infer/mod.rs                     |  6 ++---
 src/librustc/infer/region_inference/mod.rs    |  6 ++---
 src/librustc/infer/type_variable.rs           |  2 +-
 src/librustc/middle/effect.rs                 |  4 +--
 src/librustc/middle/expr_use_visitor.rs       |  8 +++---
 src/librustc/middle/intrinsicck.rs            |  4 +--
 src/librustc/middle/liveness.rs               |  6 ++---
 src/librustc/middle/mem_categorization.rs     | 26 +++++++++----------
 src/librustc/middle/region.rs                 |  2 +-
 src/librustc/middle/resolve_lifetime.rs       | 10 +++----
 src/librustc/middle/stability.rs              |  2 +-
 src/librustc/mir/tcx.rs                       |  2 +-
 src/librustc/session/config.rs                |  4 +--
 src/librustc/traits/select.rs                 |  4 +--
 src/librustc/ty/adjustment.rs                 |  2 +-
 src/librustc/ty/contents.rs                   |  2 +-
 src/librustc/ty/fast_reject.rs                |  2 +-
 src/librustc/ty/item_path.rs                  |  2 +-
 src/librustc/ty/mod.rs                        |  6 ++---
 src/librustc/ty/sty.rs                        |  6 ++---
 src/librustc/ty/util.rs                       |  2 +-
 src/librustc_borrowck/borrowck/check_loans.rs |  8 +++---
 src/librustc_borrowck/borrowck/fragments.rs   |  8 +++---
 .../borrowck/gather_loans/gather_moves.rs     |  6 ++---
 .../borrowck/gather_loans/lifetime.rs         | 12 ++++-----
 .../borrowck/gather_loans/mod.rs              |  2 +-
 .../borrowck/gather_loans/move_error.rs       |  6 ++---
 src/librustc_borrowck/borrowck/mod.rs         | 10 +++----
 src/librustc_borrowck/borrowck/move_data.rs   |  8 +++---
 src/librustc_const_eval/check_match.rs        | 12 ++++-----
 src/librustc_const_eval/eval.rs               |  6 ++---
 src/librustc_driver/lib.rs                    |  5 ++--
 src/librustc_incremental/assert_dep_graph.rs  |  2 +-
 .../calculate_svh/svh_visitor.rs              |  6 ++---
 src/librustc_incremental/lib.rs               |  1 +
 src/librustc_incremental/persist/fs.rs        |  4 +--
 src/librustc_lint/builtin.rs                  |  8 +++---
 src/librustc_lint/unused.rs                   | 14 +++++-----
 src/librustc_metadata/astencode.rs            |  2 +-
 src/librustc_metadata/creader.rs              | 16 ++++++------
 src/librustc_metadata/decoder.rs              |  4 +--
 src/librustc_metadata/encoder.rs              |  2 +-
 src/librustc_mir/hair/cx/expr.rs              |  6 ++---
 src/librustc_mir/hair/cx/mod.rs               |  2 +-
 src/librustc_mir/transform/qualify_consts.rs  | 10 +++----
 src/librustc_mir/transform/type_check.rs      |  2 +-
 src/librustc_passes/ast_validation.rs         |  2 +-
 src/librustc_passes/consts.rs                 | 12 ++++-----
 src/librustc_passes/loops.rs                  |  2 +-
 src/librustc_privacy/lib.rs                   | 12 ++++-----
 src/librustc_resolve/build_reduced_graph.rs   |  4 +--
 src/librustc_resolve/check_unused.rs          |  2 +-
 src/librustc_resolve/lib.rs                   | 16 ++++++------
 src/librustc_save_analysis/dump_visitor.rs    | 12 ++++-----
 src/librustc_save_analysis/lib.rs             |  6 ++---
 src/librustc_trans/adt.rs                     |  6 ++---
 src/librustc_trans/back/write.rs              | 12 ++++-----
 src/librustc_trans/base.rs                    |  2 +-
 src/librustc_trans/cabi_x86_64.rs             |  2 +-
 src/librustc_trans/callee.rs                  |  6 ++---
 src/librustc_trans/collector.rs               |  5 ++--
 src/librustc_trans/debuginfo/metadata.rs      |  8 +++---
 src/librustc_trans/debuginfo/type_names.rs    |  2 +-
 src/librustc_trans/intrinsic.rs               |  2 +-
 src/librustc_trans/mir/block.rs               |  4 +--
 src/librustc_trans/trans_item.rs              |  2 +-
 src/librustc_typeck/check/callee.rs           |  2 +-
 src/librustc_typeck/check/cast.rs             |  2 +-
 src/librustc_typeck/check/coercion.rs         |  2 +-
 src/librustc_typeck/check/intrinsic.rs        |  2 +-
 src/librustc_typeck/check/method/confirm.rs   |  2 +-
 src/librustc_typeck/check/method/probe.rs     |  8 +++---
 src/librustc_typeck/check/mod.rs              | 12 ++++-----
 src/librustc_typeck/check/regionck.rs         | 10 +++----
 src/librustc_typeck/check/upvar.rs            |  8 +++---
 src/librustc_typeck/check/wfcheck.rs          |  4 +--
 src/librustc_typeck/check/writeback.rs        |  4 +--
 src/librustc_typeck/coherence/mod.rs          |  2 +-
 src/librustc_typeck/collect.rs                |  6 ++---
 src/librustc_typeck/variance/constraints.rs   |  2 +-
 src/librustc_typeck/variance/terms.rs         |  2 +-
 src/librustdoc/clean/inline.rs                |  2 +-
 src/librustdoc/clean/mod.rs                   |  8 +++---
 src/librustdoc/html/render.rs                 |  2 +-
 src/librustdoc/lib.rs                         |  3 ++-
 src/libserialize/hex.rs                       |  2 +-
 src/libstd/path.rs                            |  2 +-
 src/libsyntax/ast.rs                          |  2 +-
 src/libsyntax/ext/tt/macro_parser.rs          |  4 +--
 src/libsyntax/parse/token.rs                  |  6 ++---
 src/libsyntax_ext/asm.rs                      |  2 +-
 src/libsyntax_ext/deriving/debug.rs           |  2 +-
 src/libsyntax_ext/deriving/generic/mod.rs     |  8 +++---
 src/libsyntax_ext/deriving/hash.rs            |  2 +-
 src/libsyntax_ext/lib.rs                      |  1 +
 src/libterm/terminfo/parm.rs                  |  2 +-
 src/test/run-make/save-analysis/foo.rs        |  8 +++---
 .../auxiliary/custom_derive_plugin_attr.rs    |  3 ++-
 107 files changed, 275 insertions(+), 271 deletions(-)

diff --git a/src/libgetopts/lib.rs b/src/libgetopts/lib.rs
index eda20699755a..42200795bb3a 100644
--- a/src/libgetopts/lib.rs
+++ b/src/libgetopts/lib.rs
@@ -279,7 +279,7 @@ impl OptGroup {
                                   }],
                 }
             }
-            (_, _) => panic!("something is wrong with the long-form opt"),
+            _ => panic!("something is wrong with the long-form opt"),
         }
     }
 }
diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs
index 232db76a6d17..25a73226473b 100644
--- a/src/librustc/cfg/construct.rs
+++ b/src/librustc/cfg/construct.rs
@@ -99,7 +99,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
 
     fn pat(&mut self, pat: &hir::Pat, pred: CFGIndex) -> CFGIndex {
         match pat.node {
-            PatKind::Binding(_, _, None) |
+            PatKind::Binding(.., None) |
             PatKind::Path(..) |
             PatKind::Lit(..) |
             PatKind::Range(..) |
@@ -109,7 +109,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
 
             PatKind::Box(ref subpat) |
             PatKind::Ref(ref subpat, _) |
-            PatKind::Binding(_, _, Some(ref subpat)) => {
+            PatKind::Binding(.., Some(ref subpat)) => {
                 let subpat_exit = self.pat(&subpat, pred);
                 self.add_ast_node(pat.id, &[subpat_exit])
             }
@@ -306,7 +306,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
                 self.call(expr, pred, &func, args.iter().map(|e| &**e))
             }
 
-            hir::ExprMethodCall(_, _, ref args) => {
+            hir::ExprMethodCall(.., ref args) => {
                 self.call(expr, pred, &args[0], args[1..].iter().map(|e| &**e))
             }
 
diff --git a/src/librustc/hir/def.rs b/src/librustc/hir/def.rs
index 71bc2693abd2..a270be4f1dfd 100644
--- a/src/librustc/hir/def.rs
+++ b/src/librustc/hir/def.rs
@@ -104,7 +104,7 @@ impl Def {
     pub fn var_id(&self) -> ast::NodeId {
         match *self {
             Def::Local(_, id) |
-            Def::Upvar(_, id, _, _) => {
+            Def::Upvar(_, id, ..) => {
                 id
             }
 
diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs
index 81b1be53615d..f0caa971d969 100644
--- a/src/librustc/hir/intravisit.rs
+++ b/src/librustc/hir/intravisit.rs
@@ -341,7 +341,7 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) {
             visitor.visit_id(item.id);
             visitor.visit_trait_ref(trait_ref)
         }
-        ItemImpl(_, _, ref type_parameters, ref opt_trait_reference, ref typ, ref impl_items) => {
+        ItemImpl(.., ref type_parameters, ref opt_trait_reference, ref typ, ref impl_items) => {
             visitor.visit_id(item.id);
             visitor.visit_generics(type_parameters);
             walk_list!(visitor, visit_trait_ref, opt_trait_reference);
@@ -625,7 +625,7 @@ pub fn walk_fn_kind<'v, V: Visitor<'v>>(visitor: &mut V, function_kind: FnKind<'
         FnKind::ItemFn(_, generics, ..) => {
             visitor.visit_generics(generics);
         }
-        FnKind::Method(_, sig, _, _) => {
+        FnKind::Method(_, sig, ..) => {
             visitor.visit_generics(&sig.generics);
         }
         FnKind::Closure(_) => {}
diff --git a/src/librustc/hir/map/collector.rs b/src/librustc/hir/map/collector.rs
index 280c0f304856..d4e1eb70ae8f 100644
--- a/src/librustc/hir/map/collector.rs
+++ b/src/librustc/hir/map/collector.rs
@@ -109,7 +109,7 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> {
                         this.insert(struct_def.id(), NodeStructCtor(struct_def));
                     }
                 }
-                ItemTrait(_, _, ref bounds, _) => {
+                ItemTrait(.., ref bounds, _) => {
                     for b in bounds.iter() {
                         if let TraitTyParamBound(ref t, TraitBoundModifier::None) = *b {
                             this.insert(t.trait_ref.ref_id, NodeItem(i));
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index e16005558f82..e22c9869ab17 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -469,7 +469,7 @@ impl Pat {
         }
 
         match self.node {
-            PatKind::Binding(_, _, Some(ref p)) => p.walk_(it),
+            PatKind::Binding(.., Some(ref p)) => p.walk_(it),
             PatKind::Struct(_, ref fields, _) => {
                 fields.iter().all(|field| field.node.pat.walk_(it))
             }
@@ -486,7 +486,7 @@ impl Pat {
             }
             PatKind::Wild |
             PatKind::Lit(_) |
-            PatKind::Range(_, _) |
+            PatKind::Range(..) |
             PatKind::Binding(..) |
             PatKind::Path(..) => {
                 true
diff --git a/src/librustc/hir/pat_util.rs b/src/librustc/hir/pat_util.rs
index abb608400244..a63bf14cb023 100644
--- a/src/librustc/hir/pat_util.rs
+++ b/src/librustc/hir/pat_util.rs
@@ -53,7 +53,7 @@ impl EnumerateAndAdjustIterator for T {
 
 pub fn pat_is_refutable(dm: &DefMap, pat: &hir::Pat) -> bool {
     match pat.node {
-        PatKind::Lit(_) | PatKind::Range(_, _) | PatKind::Path(Some(..), _) => true,
+        PatKind::Lit(_) | PatKind::Range(..) | PatKind::Path(Some(..), _) => true,
         PatKind::TupleStruct(..) |
         PatKind::Path(..) |
         PatKind::Struct(..) => {
diff --git a/src/librustc/infer/error_reporting.rs b/src/librustc/infer/error_reporting.rs
index 753dd01d87ee..38f3f055cbb2 100644
--- a/src/librustc/infer/error_reporting.rs
+++ b/src/librustc/infer/error_reporting.rs
@@ -140,9 +140,9 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
                     Some(ast_map::NodeExpr(expr)) => match expr.node {
                         hir::ExprCall(..) => "call",
                         hir::ExprMethodCall(..) => "method call",
-                        hir::ExprMatch(_, _, hir::MatchSource::IfLetDesugar { .. }) => "if let",
-                        hir::ExprMatch(_, _, hir::MatchSource::WhileLetDesugar) =>  "while let",
-                        hir::ExprMatch(_, _, hir::MatchSource::ForLoopDesugar) =>  "for",
+                        hir::ExprMatch(.., hir::MatchSource::IfLetDesugar { .. }) => "if let",
+                        hir::ExprMatch(.., hir::MatchSource::WhileLetDesugar) =>  "while let",
+                        hir::ExprMatch(.., hir::MatchSource::ForLoopDesugar) =>  "for",
                         hir::ExprMatch(..) => "match",
                         _ => "expression",
                     },
diff --git a/src/librustc/infer/higher_ranked/mod.rs b/src/librustc/infer/higher_ranked/mod.rs
index 90be5e935baf..322752ccea3e 100644
--- a/src/librustc/infer/higher_ranked/mod.rs
+++ b/src/librustc/infer/higher_ranked/mod.rs
@@ -684,7 +684,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                             warnings.extend(
                                 match self.region_vars.var_origin(vid) {
                                     LateBoundRegion(_,
-                                                    ty::BrNamed(_, _, wc),
+                                                    ty::BrNamed(.., wc),
                                                     _) => Some(wc),
                                     _ => None,
                                 });
diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs
index bc5ca76c3f85..59431f3f02dc 100644
--- a/src/librustc/infer/mod.rs
+++ b/src/librustc/infer/mod.rs
@@ -225,7 +225,7 @@ impl TypeOrigin {
             &TypeOrigin::RelateOutputImplTypes(_) |
             &TypeOrigin::ExprAssignable(_) => "mismatched types",
             &TypeOrigin::MethodCompatCheck(_) => "method not compatible with trait",
-            &TypeOrigin::MatchExpressionArm(_, _, source) => match source {
+            &TypeOrigin::MatchExpressionArm(.., source) => match source {
                 hir::MatchSource::IfLetDesugar{..} => "`if let` arms have incompatible types",
                 _ => "match arms have incompatible types",
             },
@@ -1712,7 +1712,7 @@ impl TypeOrigin {
             TypeOrigin::ExprAssignable(span) => span,
             TypeOrigin::Misc(span) => span,
             TypeOrigin::RelateOutputImplTypes(span) => span,
-            TypeOrigin::MatchExpressionArm(match_span, _, _) => match_span,
+            TypeOrigin::MatchExpressionArm(match_span, ..) => match_span,
             TypeOrigin::IfExpression(span) => span,
             TypeOrigin::IfExpressionWithNoElse(span) => span,
             TypeOrigin::RangeExpression(span) => span,
@@ -1765,7 +1765,7 @@ impl RegionVariableOrigin {
             Autoref(a) => a,
             Coercion(a) => a,
             EarlyBoundRegion(a, _) => a,
-            LateBoundRegion(a, _, _) => a,
+            LateBoundRegion(a, ..) => a,
             BoundRegionInCoherence(_) => syntax_pos::DUMMY_SP,
             UpvarRegion(_, a) => a
         }
diff --git a/src/librustc/infer/region_inference/mod.rs b/src/librustc/infer/region_inference/mod.rs
index b3693ae1e21a..ef36ffa83192 100644
--- a/src/librustc/infer/region_inference/mod.rs
+++ b/src/librustc/infer/region_inference/mod.rs
@@ -605,7 +605,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> {
                                  undo_entry: &UndoLogEntry<'tcx>)
                                  -> bool {
             match undo_entry {
-                &AddConstraint(ConstrainVarSubVar(_, _)) =>
+                &AddConstraint(ConstrainVarSubVar(..)) =>
                     false,
                 &AddConstraint(ConstrainRegSubVar(a, _)) =>
                     skols.contains(&a),
@@ -613,7 +613,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> {
                     skols.contains(&b),
                 &AddConstraint(ConstrainRegSubReg(a, b)) =>
                     skols.contains(&a) || skols.contains(&b),
-                &AddGiven(_, _) =>
+                &AddGiven(..) =>
                     false,
                 &AddVerify(_) =>
                     false,
@@ -1372,7 +1372,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> {
                 (&ReFree(..), &ReFree(..)) => Equal,
                 (&ReFree(..), _) => Less,
                 (_, &ReFree(..)) => Greater,
-                (_, _) => Equal,
+                (..) => Equal,
             }
         }
         lower_bounds.sort_by(|a, b| free_regions_first(a, b));
diff --git a/src/librustc/infer/type_variable.rs b/src/librustc/infer/type_variable.rs
index 09ae16540c4f..da9fd1cff2b4 100644
--- a/src/librustc/infer/type_variable.rs
+++ b/src/librustc/infer/type_variable.rs
@@ -267,7 +267,7 @@ impl<'tcx> TypeVariableTable<'tcx> {
                     debug!("NewElem({}) new_elem_threshold={}", index, new_elem_threshold);
                 }
 
-                sv::UndoLog::Other(SpecifyVar(vid, _, _)) => {
+                sv::UndoLog::Other(SpecifyVar(vid, ..)) => {
                     if vid.index < new_elem_threshold {
                         // quick check to see if this variable was
                         // created since the snapshot started or not.
diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs
index 66c55eb1f3e5..a7af0b50b849 100644
--- a/src/librustc/middle/effect.rs
+++ b/src/librustc/middle/effect.rs
@@ -43,7 +43,7 @@ enum RootUnsafeContext {
 
 fn type_is_unsafe_function(ty: Ty) -> bool {
     match ty.sty {
-        ty::TyFnDef(_, _, ref f) |
+        ty::TyFnDef(.., ref f) |
         ty::TyFnPtr(ref f) => f.unsafety == hir::Unsafety::Unsafe,
         _ => false,
     }
@@ -85,7 +85,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EffectCheckVisitor<'a, 'tcx> {
         let (is_item_fn, is_unsafe_fn) = match fn_kind {
             FnKind::ItemFn(_, _, unsafety, ..) =>
                 (true, unsafety == hir::Unsafety::Unsafe),
-            FnKind::Method(_, sig, _, _) =>
+            FnKind::Method(_, sig, ..) =>
                 (true, sig.unsafety == hir::Unsafety::Unsafe),
             _ => (false, false),
         };
diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs
index 66c8a8ac0d37..d32954d3800a 100644
--- a/src/librustc/middle/expr_use_visitor.rs
+++ b/src/librustc/middle/expr_use_visitor.rs
@@ -409,7 +409,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
                 self.consume_exprs(args);
             }
 
-            hir::ExprMethodCall(_, _, ref args) => { // callee.m(args)
+            hir::ExprMethodCall(.., ref args) => { // callee.m(args)
                 self.consume_exprs(args);
             }
 
@@ -940,9 +940,9 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
                pat);
         return_if_err!(self.mc.cat_pattern(cmt_discr, pat, |_mc, cmt_pat, pat| {
             match pat.node {
-                PatKind::Binding(hir::BindByRef(..), _, _) =>
+                PatKind::Binding(hir::BindByRef(..), ..) =>
                     mode.lub(BorrowingMatch),
-                PatKind::Binding(hir::BindByValue(..), _, _) => {
+                PatKind::Binding(hir::BindByValue(..), ..) => {
                     match copy_or_move(self.mc.infcx, &cmt_pat, PatBindingMove) {
                         Copy => mode.lub(CopyingMatch),
                         Move(..) => mode.lub(MovingMatch),
@@ -964,7 +964,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
         let infcx = self.mc.infcx;
         let delegate = &mut self.delegate;
         return_if_err!(mc.cat_pattern(cmt_discr.clone(), pat, |mc, cmt_pat, pat| {
-            if let PatKind::Binding(bmode, _, _) = pat.node {
+            if let PatKind::Binding(bmode, ..) = pat.node {
                 debug!("binding cmt_pat={:?} pat={:?} match_mode={:?}", cmt_pat, pat, match_mode);
 
                 // pat_ty: the type of the binding being produced.
diff --git a/src/librustc/middle/intrinsicck.rs b/src/librustc/middle/intrinsicck.rs
index a1a4f15b9f78..61bcc05bbb4f 100644
--- a/src/librustc/middle/intrinsicck.rs
+++ b/src/librustc/middle/intrinsicck.rs
@@ -52,7 +52,7 @@ struct ExprVisitor<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
 impl<'a, 'gcx, 'tcx> ExprVisitor<'a, 'gcx, 'tcx> {
     fn def_id_is_transmute(&self, def_id: DefId) -> bool {
         let intrinsic = match self.infcx.tcx.lookup_item_type(def_id).ty.sty {
-            ty::TyFnDef(_, _, ref bfty) => bfty.abi == RustIntrinsic,
+            ty::TyFnDef(.., ref bfty) => bfty.abi == RustIntrinsic,
             _ => return false
         };
         intrinsic && self.infcx.tcx.item_name(def_id).as_str() == "transmute"
@@ -160,7 +160,7 @@ impl<'a, 'gcx, 'tcx, 'v> Visitor<'v> for ExprVisitor<'a, 'gcx, 'tcx> {
                 Def::Fn(did) if self.def_id_is_transmute(did) => {
                     let typ = self.infcx.tcx.node_id_to_type(expr.id);
                     match typ.sty {
-                        ty::TyFnDef(_, _, ref bare_fn_ty) if bare_fn_ty.abi == RustIntrinsic => {
+                        ty::TyFnDef(.., ref bare_fn_ty) if bare_fn_ty.abi == RustIntrinsic => {
                             let from = bare_fn_ty.sig.0.inputs[0];
                             let to = bare_fn_ty.sig.0.output;
                             self.check_transmute(expr.span, from, to, expr.id);
diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs
index b83826de26dd..b579c69cd05c 100644
--- a/src/librustc/middle/liveness.rs
+++ b/src/librustc/middle/liveness.rs
@@ -482,7 +482,7 @@ fn visit_expr(ir: &mut IrMaps, expr: &Expr) {
         ir.add_live_node_for_node(expr.id, ExprNode(expr.span));
         intravisit::walk_expr(ir, expr);
       }
-      hir::ExprBinary(op, _, _) if op.node.is_lazy() => {
+      hir::ExprBinary(op, ..) if op.node.is_lazy() => {
         ir.add_live_node_for_node(expr.id, ExprNode(expr.span));
         intravisit::walk_expr(ir, expr);
       }
@@ -943,7 +943,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
               self.propagate_through_expr(&e, succ)
           }
 
-          hir::ExprClosure(_, _, ref blk, _) => {
+          hir::ExprClosure(.., ref blk, _) => {
               debug!("{} is an ExprClosure",
                      expr_to_string(expr));
 
@@ -1123,7 +1123,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
             self.propagate_through_expr(&f, succ)
           }
 
-          hir::ExprMethodCall(_, _, ref args) => {
+          hir::ExprMethodCall(.., ref args) => {
             let method_call = ty::MethodCall::expr(expr.id);
             let method_ty = self.ir.tcx.tables.borrow().method_map[&method_call].ty;
             // FIXME(canndrew): This is_never should really be an is_uninhabited
diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs
index b17411ced57f..f8eb0d4a0ece 100644
--- a/src/librustc/middle/mem_categorization.rs
+++ b/src/librustc/middle/mem_categorization.rs
@@ -228,7 +228,7 @@ fn deref_kind(t: Ty, context: DerefKindContext) -> McResult {
             Ok(deref_interior(InteriorField(PositionalField(0))))
         }
 
-        ty::TyArray(_, _) | ty::TySlice(_) => {
+        ty::TyArray(..) | ty::TySlice(_) => {
             // no deref of indexed content without supplying InteriorOffsetKind
             if let Some(context) = context {
                 Ok(deref_interior(InteriorElement(context, ElementKind::VecElement)))
@@ -318,7 +318,7 @@ impl MutabilityCategory {
     fn from_local(tcx: TyCtxt, id: ast::NodeId) -> MutabilityCategory {
         let ret = match tcx.map.get(id) {
             ast_map::NodeLocal(p) => match p.node {
-                PatKind::Binding(bind_mode, _, _) => {
+                PatKind::Binding(bind_mode, ..) => {
                     if bind_mode == hir::BindByValue(hir::MutMutable) {
                         McDeclared
                     } else {
@@ -419,7 +419,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
         // *being borrowed* is.  But ideally we would put in a more
         // fundamental fix to this conflated use of the node id.
         let ret_ty = match pat.node {
-            PatKind::Binding(hir::BindByRef(_), _, _) => {
+            PatKind::Binding(hir::BindByRef(_), ..) => {
                 // a bind-by-ref means that the base_ty will be the type of the ident itself,
                 // but what we want here is the type of the underlying value being borrowed.
                 // So peel off one-level, turning the &T into T.
@@ -761,7 +761,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
             };
 
             match fn_expr.node {
-                hir::ExprClosure(_, _, ref body, _) => body.id,
+                hir::ExprClosure(.., ref body, _) => body.id,
                 _ => bug!()
             }
         };
@@ -1185,7 +1185,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
             }
           }
 
-          PatKind::Binding(_, _, Some(ref subpat)) => {
+          PatKind::Binding(.., Some(ref subpat)) => {
               self.cat_pattern_(cmt, &subpat, op)?;
           }
 
@@ -1225,7 +1225,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
             }
           }
 
-          PatKind::Path(..) | PatKind::Binding(_, _, None) |
+          PatKind::Path(..) | PatKind::Binding(.., None) |
           PatKind::Lit(..) | PatKind::Range(..) | PatKind::Wild => {
             // always ok
           }
@@ -1275,9 +1275,9 @@ impl<'tcx> cmt_<'tcx> {
             Categorization::Rvalue(..) |
             Categorization::StaticItem |
             Categorization::Local(..) |
-            Categorization::Deref(_, _, UnsafePtr(..)) |
-            Categorization::Deref(_, _, BorrowedPtr(..)) |
-            Categorization::Deref(_, _, Implicit(..)) |
+            Categorization::Deref(.., UnsafePtr(..)) |
+            Categorization::Deref(.., BorrowedPtr(..)) |
+            Categorization::Deref(.., Implicit(..)) |
             Categorization::Upvar(..) => {
                 Rc::new((*self).clone())
             }
@@ -1320,7 +1320,7 @@ impl<'tcx> cmt_<'tcx> {
             Categorization::Rvalue(..) |
             Categorization::Local(..) |
             Categorization::Upvar(..) |
-            Categorization::Deref(_, _, UnsafePtr(..)) => { // yes, it's aliasable, but...
+            Categorization::Deref(.., UnsafePtr(..)) => { // yes, it's aliasable, but...
                 NonAliasable
             }
 
@@ -1349,9 +1349,9 @@ impl<'tcx> cmt_<'tcx> {
         match self.note {
             NoteClosureEnv(..) | NoteUpvarRef(..) => {
                 Some(match self.cat {
-                    Categorization::Deref(ref inner, _, _) => {
+                    Categorization::Deref(ref inner, ..) => {
                         match inner.cat {
-                            Categorization::Deref(ref inner, _, _) => inner.clone(),
+                            Categorization::Deref(ref inner, ..) => inner.clone(),
                             Categorization::Upvar(..) => inner.clone(),
                             _ => bug!()
                         }
@@ -1379,7 +1379,7 @@ impl<'tcx> cmt_<'tcx> {
                     "local variable".to_string()
                 }
             }
-            Categorization::Deref(_, _, pk) => {
+            Categorization::Deref(.., pk) => {
                 let upvar = self.upvar();
                 match upvar.as_ref().map(|i| &i.cat) {
                     Some(&Categorization::Upvar(ref var)) => {
diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs
index ef905b51edfb..fb99820f7c85 100644
--- a/src/librustc/middle/region.rs
+++ b/src/librustc/middle/region.rs
@@ -956,7 +956,7 @@ fn resolve_local(visitor: &mut RegionResolutionVisitor, local: &hir::Local) {
     ///        | box P&
     fn is_binding_pat(pat: &hir::Pat) -> bool {
         match pat.node {
-            PatKind::Binding(hir::BindByRef(_), _, _) => true,
+            PatKind::Binding(hir::BindByRef(_), ..) => true,
 
             PatKind::Struct(_, ref field_pats, _) => {
                 field_pats.iter().any(|fp| is_binding_pat(&fp.node.pat))
diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs
index b6faf834b26f..e897b16efab5 100644
--- a/src/librustc/middle/resolve_lifetime.rs
+++ b/src/librustc/middle/resolve_lifetime.rs
@@ -157,7 +157,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for LifetimeContext<'a, 'tcx> {
                 hir::ItemEnum(_, ref generics) |
                 hir::ItemStruct(_, ref generics) |
                 hir::ItemUnion(_, ref generics) |
-                hir::ItemTrait(_, ref generics, _, _) |
+                hir::ItemTrait(_, ref generics, ..) |
                 hir::ItemImpl(_, _, ref generics, ..) => {
                     // These kinds of items have only early bound lifetime parameters.
                     let lifetimes = &generics.lifetimes;
@@ -209,7 +209,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for LifetimeContext<'a, 'tcx> {
                     this.add_scope_and_walk_fn(fk, decl, b, s, fn_id)
                 })
             }
-            FnKind::Method(_, sig, _, _) => {
+            FnKind::Method(_, sig, ..) => {
                 self.visit_early_late(
                     fn_id,
                     decl,
@@ -455,7 +455,7 @@ fn extract_labels(ctxt: &mut LifetimeContext, b: &hir::Block) {
 
     fn expression_label(ex: &hir::Expr) -> Option<(ast::Name, Span)> {
         match ex.node {
-            hir::ExprWhile(_, _, Some(label)) |
+            hir::ExprWhile(.., Some(label)) |
             hir::ExprLoop(_, Some(label)) => Some((label.node, label.span)),
             _ => None,
         }
@@ -503,7 +503,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
                 intravisit::walk_fn_decl(self, fd);
                 self.visit_generics(generics);
             }
-            FnKind::Method(_, sig, _, _) => {
+            FnKind::Method(_, sig, ..) => {
                 intravisit::walk_fn_decl(self, fd);
                 self.visit_generics(&sig.generics);
             }
@@ -583,7 +583,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
                 start += 1; // Self comes first.
             }
             match parent.node {
-                hir::ItemTrait(_, ref generics, _, _) |
+                hir::ItemTrait(_, ref generics, ..) |
                 hir::ItemImpl(_, _, ref generics, ..) => {
                     start += generics.lifetimes.len() + generics.ty_params.len();
                 }
diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs
index 9fc83557fa44..c62c99c3b706 100644
--- a/src/librustc/middle/stability.rs
+++ b/src/librustc/middle/stability.rs
@@ -553,7 +553,7 @@ pub fn check_expr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, e: &hir::Expr,
                                            &Option)) {
     let span;
     let id = match e.node {
-        hir::ExprMethodCall(i, _, _) => {
+        hir::ExprMethodCall(i, ..) => {
             span = i.span;
             let method_call = ty::MethodCall::expr(e.id);
             tcx.tables.borrow().method_map[&method_call].def_id
diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs
index a0ccc72aa1fc..c82e723525b4 100644
--- a/src/librustc/mir/tcx.rs
+++ b/src/librustc/mir/tcx.rs
@@ -153,7 +153,7 @@ impl<'tcx> Rvalue<'tcx> {
                 ))
             }
             &Rvalue::Len(..) => Some(tcx.types.usize),
-            &Rvalue::Cast(_, _, ty) => Some(ty),
+            &Rvalue::Cast(.., ty) => Some(ty),
             &Rvalue::BinaryOp(op, ref lhs, ref rhs) => {
                 let lhs_ty = lhs.ty(mir, tcx);
                 let rhs_ty = rhs.ty(mir, tcx);
diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs
index a2f926aa92c5..5917c8f90e03 100644
--- a/src/librustc/session/config.rs
+++ b/src/librustc/session/config.rs
@@ -1535,8 +1535,8 @@ pub fn get_unstable_features_setting() -> UnstableFeatures {
     let bootstrap_provided_key = env::var("RUSTC_BOOTSTRAP_KEY").ok();
     match (disable_unstable_features, bootstrap_secret_key, bootstrap_provided_key) {
         (_, Some(ref s), Some(ref p)) if s == p => UnstableFeatures::Cheat,
-        (true, _, _) => UnstableFeatures::Disallow,
-        (false, _, _) => UnstableFeatures::Allow
+        (true, ..) => UnstableFeatures::Disallow,
+        (false, ..) => UnstableFeatures::Allow
     }
 }
 
diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs
index f8f10d9c2654..3f2bc8cbd13c 100644
--- a/src/librustc/traits/select.rs
+++ b/src/librustc/traits/select.rs
@@ -1379,7 +1379,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
             }
 
             // provide an impl, but only for suitable `fn` pointers
-            ty::TyFnDef(_, _, &ty::BareFnTy {
+            ty::TyFnDef(.., &ty::BareFnTy {
                 unsafety: hir::Unsafety::Normal,
                 abi: Abi::Rust,
                 sig: ty::Binder(ty::FnSig {
@@ -1635,7 +1635,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
             }
 
             // [T; n] -> [T].
-            (&ty::TyArray(_, _), &ty::TySlice(_)) => true,
+            (&ty::TyArray(..), &ty::TySlice(_)) => true,
 
             // Struct -> Struct.
             (&ty::TyStruct(def_id_a, _), &ty::TyStruct(def_id_b, _)) => {
diff --git a/src/librustc/ty/adjustment.rs b/src/librustc/ty/adjustment.rs
index ae9fd5ab5bc8..3386d894196f 100644
--- a/src/librustc/ty/adjustment.rs
+++ b/src/librustc/ty/adjustment.rs
@@ -160,7 +160,7 @@ impl<'a, 'gcx, 'tcx> ty::TyS<'tcx> {
 
                     AdjustReifyFnPointer => {
                         match self.sty {
-                            ty::TyFnDef(_, _, f) => tcx.mk_fn_ptr(f),
+                            ty::TyFnDef(.., f) => tcx.mk_fn_ptr(f),
                             _ => {
                                 bug!("AdjustReifyFnPointer adjustment on non-fn-item: {:?}",
                                      self);
diff --git a/src/librustc/ty/contents.rs b/src/librustc/ty/contents.rs
index d7d4693c1165..e0e8a329e6e1 100644
--- a/src/librustc/ty/contents.rs
+++ b/src/librustc/ty/contents.rs
@@ -202,7 +202,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> {
                     TC::None
                 }
 
-                ty::TyRef(_, _) => {
+                ty::TyRef(..) => {
                     TC::None
                 }
 
diff --git a/src/librustc/ty/fast_reject.rs b/src/librustc/ty/fast_reject.rs
index f9ca2484d7ef..84f34a640dd8 100644
--- a/src/librustc/ty/fast_reject.rs
+++ b/src/librustc/ty/fast_reject.rs
@@ -90,7 +90,7 @@ pub fn simplify_type<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
         ty::TyTuple(ref tys) => {
             Some(TupleSimplifiedType(tys.len()))
         }
-        ty::TyFnDef(_, _, ref f) | ty::TyFnPtr(ref f) => {
+        ty::TyFnDef(.., ref f) | ty::TyFnPtr(ref f) => {
             Some(FunctionSimplifiedType(f.sig.0.inputs.len()))
         }
         ty::TyProjection(_) | ty::TyParam(_) => {
diff --git a/src/librustc/ty/item_path.rs b/src/librustc/ty/item_path.rs
index ba8d33285092..ddb0a6970cba 100644
--- a/src/librustc/ty/item_path.rs
+++ b/src/librustc/ty/item_path.rs
@@ -337,7 +337,7 @@ pub fn characteristic_def_id_of_type(ty: Ty) -> Option {
                                    .filter_map(|ty| characteristic_def_id_of_type(ty))
                                    .next(),
 
-        ty::TyFnDef(def_id, _, _) |
+        ty::TyFnDef(def_id, ..) |
         ty::TyClosure(def_id, _) => Some(def_id),
 
         ty::TyBool |
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index a9b3833b4017..dfe24d5627bf 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -1269,7 +1269,7 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> {
         match tcx.map.find(id) {
             Some(ast_map::NodeImplItem(ref impl_item)) => {
                 match impl_item.node {
-                    hir::ImplItemKind::Type(_) | hir::ImplItemKind::Const(_, _) => {
+                    hir::ImplItemKind::Type(_) | hir::ImplItemKind::Const(..) => {
                         // associated types don't have their own entry (for some reason),
                         // so for now just grab environment for the impl
                         let impl_id = tcx.map.get_parent(id);
@@ -2290,7 +2290,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
             match self.map.expect_item(id).node {
                 ItemTrait(.., ref tis) => {
                     tis.iter().filter_map(|ti| {
-                        if let hir::ConstTraitItem(_, _) = ti.node {
+                        if let hir::ConstTraitItem(..) = ti.node {
                             match self.impl_or_trait_item(self.map.local_def_id(ti.id)) {
                                 ConstTraitItem(ac) => Some(ac),
                                 _ => {
@@ -2306,7 +2306,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
                 }
                 ItemImpl(.., ref iis) => {
                     iis.iter().filter_map(|ii| {
-                        if let hir::ImplItemKind::Const(_, _) = ii.node {
+                        if let hir::ImplItemKind::Const(..) = ii.node {
                             match self.impl_or_trait_item(self.map.local_def_id(ii.id)) {
                                 ConstTraitItem(ac) => Some(ac),
                                 _ => {
diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs
index d45fde925c51..7ded2b05f3b5 100644
--- a/src/librustc/ty/sty.rs
+++ b/src/librustc/ty/sty.rs
@@ -1171,7 +1171,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
 
     pub fn fn_sig(&self) -> &'tcx PolyFnSig<'tcx> {
         match self.sty {
-            TyFnDef(_, _, ref f) | TyFnPtr(ref f) => &f.sig,
+            TyFnDef(.., ref f) | TyFnPtr(ref f) => &f.sig,
             _ => bug!("Ty::fn_sig() called on non-fn type: {:?}", self)
         }
     }
@@ -1179,7 +1179,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
     /// Returns the ABI of the given function.
     pub fn fn_abi(&self) -> abi::Abi {
         match self.sty {
-            TyFnDef(_, _, ref f) | TyFnPtr(ref f) => f.abi,
+            TyFnDef(.., ref f) | TyFnPtr(ref f) => f.abi,
             _ => bug!("Ty::fn_abi() called on non-fn type"),
         }
     }
@@ -1252,7 +1252,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
             TyFloat(_) |
             TyBox(_) |
             TyStr |
-            TyArray(_, _) |
+            TyArray(..) |
             TySlice(_) |
             TyRawPtr(_) |
             TyNever |
diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs
index ad209094600a..51ca6bfeb5af 100644
--- a/src/librustc/ty/util.rs
+++ b/src/librustc/ty/util.rs
@@ -439,7 +439,7 @@ impl<'a, 'gcx, 'tcx> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tcx> {
             TyRef(_, m) => self.hash(m.mutbl),
             TyClosure(def_id, _) |
             TyAnon(def_id, _) |
-            TyFnDef(def_id, _, _) => self.def_id(def_id),
+            TyFnDef(def_id, ..) => self.def_id(def_id),
             TyFnPtr(f) => {
                 self.hash(f.unsafety);
                 self.hash(f.abi);
diff --git a/src/librustc_borrowck/borrowck/check_loans.rs b/src/librustc_borrowck/borrowck/check_loans.rs
index b4c6689c24b9..6f4c48d632a7 100644
--- a/src/librustc_borrowck/borrowck/check_loans.rs
+++ b/src/librustc_borrowck/borrowck/check_loans.rs
@@ -56,7 +56,7 @@ fn owned_ptr_base_path<'a, 'tcx>(loan_path: &'a LoanPath<'tcx>) -> &'a LoanPath<
                 }
             }
             LpDowncast(ref lp_base, _) |
-            LpExtend(ref lp_base, _, _) => helper(&lp_base)
+            LpExtend(ref lp_base, ..) => helper(&lp_base)
         }
     }
 }
@@ -80,7 +80,7 @@ fn owned_ptr_base_path_rc<'tcx>(loan_path: &Rc>) -> Rc helper(lp_base)
+            LpExtend(ref lp_base, ..) => helper(lp_base)
         }
     }
 }
@@ -312,7 +312,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
                     break;
                 }
                 LpDowncast(ref lp_base, _) |
-                LpExtend(ref lp_base, _, _) => {
+                LpExtend(ref lp_base, ..) => {
                     loan_path = &lp_base;
                 }
             }
@@ -542,7 +542,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
                     err
                 }
 
-                (_, _) => {
+                (..) => {
                     let mut err = struct_span_err!(self.bccx, new_loan.span, E0502,
                                                    "cannot borrow `{}`{} as {} because \
                                                    {} is also borrowed as {}{}",
diff --git a/src/librustc_borrowck/borrowck/fragments.rs b/src/librustc_borrowck/borrowck/fragments.rs
index 86f396d8982b..45f5c3288a6d 100644
--- a/src/librustc_borrowck/borrowck/fragments.rs
+++ b/src/librustc_borrowck/borrowck/fragments.rs
@@ -365,9 +365,9 @@ fn add_fragment_siblings<'a, 'tcx>(this: &MoveData<'tcx>,
         }
 
         // *LV for unsafe and borrowed pointers do not consume their loan path, so stop here.
-        LpExtend(_, _, LpDeref(mc::UnsafePtr(..)))   |
-        LpExtend(_, _, LpDeref(mc::Implicit(..)))    |
-        LpExtend(_, _, LpDeref(mc::BorrowedPtr(..))) => {}
+        LpExtend(.., LpDeref(mc::UnsafePtr(..)))   |
+        LpExtend(.., LpDeref(mc::Implicit(..)))    |
+        LpExtend(.., LpDeref(mc::BorrowedPtr(..))) => {}
 
         // FIXME (pnkfelix): LV[j] should be tracked, at least in the
         // sense of we will track the remaining drop obligation of the
@@ -378,7 +378,7 @@ fn add_fragment_siblings<'a, 'tcx>(this: &MoveData<'tcx>,
         // bind.
         //
         // Anyway, for now: LV[j] is not tracked precisely
-        LpExtend(_, _, LpInterior(_, InteriorElement(..))) => {
+        LpExtend(.., LpInterior(_, InteriorElement(..))) => {
             let mp = this.move_path(tcx, lp.clone());
             gathered_fragments.push(AllButOneFrom(mp));
         }
diff --git a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs
index 3cf02fc85a46..5f2d6c406c4b 100644
--- a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs
+++ b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs
@@ -161,9 +161,9 @@ fn check_and_get_illegal_move_origin<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
                                                cmt: &mc::cmt<'tcx>)
                                                -> Option> {
     match cmt.cat {
-        Categorization::Deref(_, _, mc::BorrowedPtr(..)) |
-        Categorization::Deref(_, _, mc::Implicit(..)) |
-        Categorization::Deref(_, _, mc::UnsafePtr(..)) |
+        Categorization::Deref(.., mc::BorrowedPtr(..)) |
+        Categorization::Deref(.., mc::Implicit(..)) |
+        Categorization::Deref(.., mc::UnsafePtr(..)) |
         Categorization::StaticItem => {
             Some(cmt.clone())
         }
diff --git a/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs b/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs
index 9f95175d59d4..5970d6e4f2f6 100644
--- a/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs
+++ b/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs
@@ -74,9 +74,9 @@ impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> {
             Categorization::Rvalue(..) |
             Categorization::Local(..) |                         // L-Local
             Categorization::Upvar(..) |
-            Categorization::Deref(_, _, mc::BorrowedPtr(..)) |  // L-Deref-Borrowed
-            Categorization::Deref(_, _, mc::Implicit(..)) |
-            Categorization::Deref(_, _, mc::UnsafePtr(..)) => {
+            Categorization::Deref(.., mc::BorrowedPtr(..)) |  // L-Deref-Borrowed
+            Categorization::Deref(.., mc::Implicit(..)) |
+            Categorization::Deref(.., mc::UnsafePtr(..)) => {
                 self.check_scope(self.scope(cmt))
             }
 
@@ -119,11 +119,11 @@ impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> {
                     self.bccx.tcx.region_maps.var_scope(local_id)))
             }
             Categorization::StaticItem |
-            Categorization::Deref(_, _, mc::UnsafePtr(..)) => {
+            Categorization::Deref(.., mc::UnsafePtr(..)) => {
                 self.bccx.tcx.mk_region(ty::ReStatic)
             }
-            Categorization::Deref(_, _, mc::BorrowedPtr(_, r)) |
-            Categorization::Deref(_, _, mc::Implicit(_, r)) => {
+            Categorization::Deref(.., mc::BorrowedPtr(_, r)) |
+            Categorization::Deref(.., mc::Implicit(_, r)) => {
                 r
             }
             Categorization::Downcast(ref cmt, _) |
diff --git a/src/librustc_borrowck/borrowck/gather_loans/mod.rs b/src/librustc_borrowck/borrowck/gather_loans/mod.rs
index a255564f01e2..763c012a8f8a 100644
--- a/src/librustc_borrowck/borrowck/gather_loans/mod.rs
+++ b/src/librustc_borrowck/borrowck/gather_loans/mod.rs
@@ -205,7 +205,7 @@ fn check_aliasability<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
                         alias_cause);
             Err(())
         }
-        (_, _) => {
+        (..) => {
             Ok(())
         }
     }
diff --git a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs
index 61c85e393d2d..bda68a1cd1ce 100644
--- a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs
+++ b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs
@@ -117,9 +117,9 @@ fn report_cannot_move_out_of<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
                                        move_from: mc::cmt<'tcx>)
                                        -> DiagnosticBuilder<'a> {
     match move_from.cat {
-        Categorization::Deref(_, _, mc::BorrowedPtr(..)) |
-        Categorization::Deref(_, _, mc::Implicit(..)) |
-        Categorization::Deref(_, _, mc::UnsafePtr(..)) |
+        Categorization::Deref(.., mc::BorrowedPtr(..)) |
+        Categorization::Deref(.., mc::Implicit(..)) |
+        Categorization::Deref(.., mc::UnsafePtr(..)) |
         Categorization::StaticItem => {
             let mut err = struct_span_err!(bccx, move_from.span, E0507,
                              "cannot move out of {}",
diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs
index e25adadbb244..5d62629b6481 100644
--- a/src/librustc_borrowck/borrowck/mod.rs
+++ b/src/librustc_borrowck/borrowck/mod.rs
@@ -142,7 +142,7 @@ fn borrowck_item(this: &mut BorrowckCtxt, item: &hir::Item) {
     // loan step is intended for things that have a data
     // flow dependent conditions.
     match item.node {
-        hir::ItemStatic(_, _, ref ex) |
+        hir::ItemStatic(.., ref ex) |
         hir::ItemConst(_, ref ex) => {
             gather_loans::gather_loans_in_static_initializer(this, item.id, &ex);
         }
@@ -422,7 +422,7 @@ pub fn closure_to_block(closure_id: ast::NodeId,
                         tcx: TyCtxt) -> ast::NodeId {
     match tcx.map.get(closure_id) {
         hir_map::NodeExpr(expr) => match expr.node {
-            hir::ExprClosure(_, _, ref block, _) => {
+            hir::ExprClosure(.., ref block, _) => {
                 block.id
             }
             _ => {
@@ -442,7 +442,7 @@ impl<'a, 'tcx> LoanPath<'tcx> {
                 tcx.region_maps.node_extent(block_id)
             }
             LpDowncast(ref base, _) |
-            LpExtend(ref base, _, _) => base.kill_scope(tcx),
+            LpExtend(ref base, ..) => base.kill_scope(tcx),
         }
     }
 
@@ -464,7 +464,7 @@ impl<'a, 'tcx> LoanPath<'tcx> {
     fn depth(&self) -> usize {
         match self.kind {
             LpExtend(ref base, _, LpDeref(_)) => base.depth(),
-            LpExtend(ref base, _, LpInterior(_, _)) => base.depth() + 1,
+            LpExtend(ref base, _, LpInterior(..)) => base.depth() + 1,
             _ => 0,
         }
     }
@@ -1177,7 +1177,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
                 out.push(')');
             }
 
-            LpVar(..) | LpUpvar(..) | LpExtend(_, _, LpInterior(..)) => {
+            LpVar(..) | LpUpvar(..) | LpExtend(.., LpInterior(..)) => {
                 self.append_loan_path_to_string(loan_path, out)
             }
         }
diff --git a/src/librustc_borrowck/borrowck/move_data.rs b/src/librustc_borrowck/borrowck/move_data.rs
index 236a1a2835c2..0c9261df5487 100644
--- a/src/librustc_borrowck/borrowck/move_data.rs
+++ b/src/librustc_borrowck/borrowck/move_data.rs
@@ -197,7 +197,7 @@ fn loan_path_is_precise(loan_path: &LoanPath) -> bool {
         LpVar(_) | LpUpvar(_) => {
             true
         }
-        LpExtend(_, _, LpInterior(_, InteriorKind::InteriorElement(..))) => {
+        LpExtend(.., LpInterior(_, InteriorKind::InteriorElement(..))) => {
             // Paths involving element accesses a[i] do not refer to a unique
             // location, as there is no accurate tracking of the indices.
             //
@@ -207,7 +207,7 @@ fn loan_path_is_precise(loan_path: &LoanPath) -> bool {
             false
         }
         LpDowncast(ref lp_base, _) |
-        LpExtend(ref lp_base, _, _) => {
+        LpExtend(ref lp_base, ..) => {
             loan_path_is_precise(&lp_base)
         }
     }
@@ -295,7 +295,7 @@ impl<'a, 'tcx> MoveData<'tcx> {
             }
 
             LpDowncast(ref base, _) |
-            LpExtend(ref base, _, _) => {
+            LpExtend(ref base, ..) => {
                 let parent_index = self.move_path(tcx, base.clone());
 
                 let index = MovePathIndex(self.paths.borrow().len());
@@ -351,7 +351,7 @@ impl<'a, 'tcx> MoveData<'tcx> {
                 match lp.kind {
                     LpVar(..) | LpUpvar(..) => { }
                     LpDowncast(ref b, _) |
-                    LpExtend(ref b, _, _) => {
+                    LpExtend(ref b, ..) => {
                         self.add_existing_base_paths(b, result);
                     }
                 }
diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs
index de28cbb7c9c9..e49011d88737 100644
--- a/src/librustc_const_eval/check_match.rs
+++ b/src/librustc_const_eval/check_match.rs
@@ -372,8 +372,8 @@ fn check_arms(cx: &MatchCheckCtxt,
 /// Checks for common cases of "catchall" patterns that may not be intended as such.
 fn pat_is_catchall(dm: &DefMap, p: &Pat) -> bool {
     match p.node {
-        PatKind::Binding(_, _, None) => true,
-        PatKind::Binding(_, _, Some(ref s)) => pat_is_catchall(dm, &s),
+        PatKind::Binding(.., None) => true,
+        PatKind::Binding(.., Some(ref s)) => pat_is_catchall(dm, &s),
         PatKind::Ref(ref s, _) => pat_is_catchall(dm, &s),
         PatKind::Tuple(ref v, _) => v.iter().all(|p| pat_is_catchall(dm, &p)),
         _ => false
@@ -382,7 +382,7 @@ fn pat_is_catchall(dm: &DefMap, p: &Pat) -> bool {
 
 fn raw_pat(p: &Pat) -> &Pat {
     match p.node {
-        PatKind::Binding(_, _, Some(ref s)) => raw_pat(&s),
+        PatKind::Binding(.., Some(ref s)) => raw_pat(&s),
         _ => p
     }
 }
@@ -804,7 +804,7 @@ fn pat_constructors(cx: &MatchCheckCtxt, p: &Pat,
             vec![ConstantRange(eval_const_expr(cx.tcx, &lo), eval_const_expr(cx.tcx, &hi))],
         PatKind::Vec(ref before, ref slice, ref after) =>
             match left_ty.sty {
-                ty::TyArray(_, _) => vec![Single],
+                ty::TyArray(..) => vec![Single],
                 ty::TySlice(_) if slice.is_some() => {
                     (before.len() + after.len()..max_slice_length+1)
                         .map(|length| Slice(length))
@@ -866,7 +866,7 @@ fn wrap_pat<'a, 'b, 'tcx>(cx: &MatchCheckCtxt<'b, 'tcx>,
 {
     let pat_ty = cx.tcx.pat_ty(pat);
     (pat, Some(match pat.node {
-        PatKind::Binding(hir::BindByRef(..), _, _) => {
+        PatKind::Binding(hir::BindByRef(..), ..) => {
             pat_ty.builtin_deref(false, NoPreference).unwrap().ty
         }
         _ => pat_ty
@@ -1217,7 +1217,7 @@ struct AtBindingPatternVisitor<'a, 'b:'a, 'tcx:'b> {
 impl<'a, 'b, 'tcx, 'v> Visitor<'v> for AtBindingPatternVisitor<'a, 'b, 'tcx> {
     fn visit_pat(&mut self, pat: &Pat) {
         match pat.node {
-            PatKind::Binding(_, _, ref subpat) => {
+            PatKind::Binding(.., ref subpat) => {
                 if !self.bindings_allowed {
                     span_err!(self.cx.tcx.sess, pat.span, E0303,
                               "pattern bindings are not allowed after an `@`");
diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs
index a74b8848c4d6..30e5a0cacf55 100644
--- a/src/librustc_const_eval/eval.rs
+++ b/src/librustc_const_eval/eval.rs
@@ -106,7 +106,7 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                 _ => None
             },
             Some(ast_map::NodeTraitItem(ti)) => match ti.node {
-                hir::ConstTraitItem(_, _) => {
+                hir::ConstTraitItem(..) => {
                     if let Some(substs) = substs {
                         // If we have a trait item and the substitutions for it,
                         // `resolve_trait_associated_const` will select an impl
@@ -151,7 +151,7 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                 _ => None
             },
             Some((&InlinedItem::TraitItem(trait_id, ref ti), _)) => match ti.node {
-                hir::ConstTraitItem(_, _) => {
+                hir::ConstTraitItem(..) => {
                     used_substs = true;
                     if let Some(substs) = substs {
                         // As mentioned in the comments above for in-crate
@@ -231,7 +231,7 @@ pub fn lookup_const_fn_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefI
         FnKind::ItemFn(_, _, _, hir::Constness::Const, ..) => {
             Some(fn_like)
         }
-        FnKind::Method(_, m, _, _) => {
+        FnKind::Method(_, m, ..) => {
             if m.constness == hir::Constness::Const {
                 Some(fn_like)
             } else {
diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs
index 6616e9579e81..3fc24bf6c54e 100644
--- a/src/librustc_driver/lib.rs
+++ b/src/librustc_driver/lib.rs
@@ -24,6 +24,7 @@
 #![cfg_attr(not(stage0), deny(warnings))]
 
 #![feature(box_syntax)]
+#![feature(dotdot_in_tuple_patterns)]
 #![feature(libc)]
 #![feature(quote)]
 #![feature(rustc_diagnostic_macros)]
@@ -802,7 +803,7 @@ Available lint options:
     let (plugin_groups, builtin_groups): (Vec<_>, _) = lint_store.get_lint_groups()
                                                                  .iter()
                                                                  .cloned()
-                                                                 .partition(|&(_, _, p)| p);
+                                                                 .partition(|&(.., p)| p);
     let plugin_groups = sort_lint_groups(plugin_groups);
     let builtin_groups = sort_lint_groups(builtin_groups);
 
@@ -877,7 +878,7 @@ Available lint options:
             println!("Compiler plugins can provide additional lints and lint groups. To see a \
                       listing of these, re-run `rustc -W help` with a crate filename.");
         }
-        (false, _, _) => panic!("didn't load lint plugins but got them anyway!"),
+        (false, ..) => panic!("didn't load lint plugins but got them anyway!"),
         (true, 0, 0) => println!("This crate does not load any lint plugins or lint groups."),
         (true, l, g) => {
             if l > 0 {
diff --git a/src/librustc_incremental/assert_dep_graph.rs b/src/librustc_incremental/assert_dep_graph.rs
index 8df8f5003711..bd96ae69ffbc 100644
--- a/src/librustc_incremental/assert_dep_graph.rs
+++ b/src/librustc_incremental/assert_dep_graph.rs
@@ -196,7 +196,7 @@ fn check_paths<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         let targets = match then_this_would_need.get(id) {
             Some(targets) => targets,
             None => {
-                for &(source_span, _, _) in sources.iter().take(1) {
+                for &(source_span, ..) in sources.iter().take(1) {
                     tcx.sess.span_err(
                         source_span,
                         &format!("no targets for id `{}`", id));
diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs
index d4a3ab59f9cb..3b7a97dd763d 100644
--- a/src/librustc_incremental/calculate_svh/svh_visitor.rs
+++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs
@@ -158,7 +158,7 @@ fn saw_expr<'a>(node: &'a Expr_) -> SawExprComponent<'a> {
         ExprCall(..)             => SawExprCall,
         ExprMethodCall(..)       => SawExprMethodCall,
         ExprTup(..)              => SawExprTup,
-        ExprBinary(op, _, _)     => SawExprBinary(op.node),
+        ExprBinary(op, ..)       => SawExprBinary(op.node),
         ExprUnary(op, _)         => SawExprUnary(op),
         ExprLit(ref lit)         => SawExprLit(lit.node.clone()),
         ExprCast(..)             => SawExprCast,
@@ -170,7 +170,7 @@ fn saw_expr<'a>(node: &'a Expr_) -> SawExprComponent<'a> {
         ExprClosure(..)          => SawExprClosure,
         ExprBlock(..)            => SawExprBlock,
         ExprAssign(..)           => SawExprAssign,
-        ExprAssignOp(op, _, _)   => SawExprAssignOp(op.node),
+        ExprAssignOp(op, ..)     => SawExprAssignOp(op.node),
         ExprField(_, name)       => SawExprField(name.node.as_str()),
         ExprTupField(_, id)      => SawExprTupField(id.node),
         ExprIndex(..)            => SawExprIndex,
@@ -179,7 +179,7 @@ fn saw_expr<'a>(node: &'a Expr_) -> SawExprComponent<'a> {
         ExprBreak(id)            => SawExprBreak(id.map(|id| id.node.as_str())),
         ExprAgain(id)            => SawExprAgain(id.map(|id| id.node.as_str())),
         ExprRet(..)              => SawExprRet,
-        ExprInlineAsm(ref a,_,_) => SawExprInlineAsm(a),
+        ExprInlineAsm(ref a,..)  => SawExprInlineAsm(a),
         ExprStruct(..)           => SawExprStruct,
         ExprRepeat(..)           => SawExprRepeat,
     }
diff --git a/src/librustc_incremental/lib.rs b/src/librustc_incremental/lib.rs
index 511ba8ec19cc..c866014c7672 100644
--- a/src/librustc_incremental/lib.rs
+++ b/src/librustc_incremental/lib.rs
@@ -19,6 +19,7 @@
       html_root_url = "https://doc.rust-lang.org/nightly/")]
 #![cfg_attr(not(stage0), deny(warnings))]
 
+#![feature(dotdot_in_tuple_patterns)]
 #![feature(question_mark)]
 #![feature(rustc_private)]
 #![feature(staged_api)]
diff --git a/src/librustc_incremental/persist/fs.rs b/src/librustc_incremental/persist/fs.rs
index 4ad4b115759c..8166045be5f6 100644
--- a/src/librustc_incremental/persist/fs.rs
+++ b/src/librustc_incremental/persist/fs.rs
@@ -880,12 +880,12 @@ pub fn garbage_collect_session_directories(sess: &Session) -> io::Result<()> {
 fn all_except_most_recent(deletion_candidates: Vec<(SystemTime, PathBuf, Option)>)
                           -> FnvHashMap> {
     let most_recent = deletion_candidates.iter()
-                                         .map(|&(timestamp, _, _)| timestamp)
+                                         .map(|&(timestamp, ..)| timestamp)
                                          .max();
 
     if let Some(most_recent) = most_recent {
         deletion_candidates.into_iter()
-                           .filter(|&(timestamp, _, _)| timestamp != most_recent)
+                           .filter(|&(timestamp, ..)| timestamp != most_recent)
                            .map(|(_, path, lock)| (path, lock))
                            .collect()
     } else {
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index eb2ded45c04c..a73930fa5251 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -72,7 +72,7 @@ impl LintPass for WhileTrue {
 
 impl LateLintPass for WhileTrue {
     fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) {
-        if let hir::ExprWhile(ref cond, _, _) = e.node {
+        if let hir::ExprWhile(ref cond, ..) = e.node {
             if let hir::ExprLit(ref lit) = cond.node {
                 if let ast::LitKind::Bool(true) = lit.node {
                     cx.span_lint(WHILE_TRUE, e.span,
@@ -219,7 +219,7 @@ impl LateLintPass for UnsafeCode {
             FnKind::ItemFn(_, _, hir::Unsafety::Unsafe, ..) =>
                 cx.span_lint(UNSAFE_CODE, span, "declaration of an `unsafe` function"),
 
-            FnKind::Method(_, sig, _, _) => {
+            FnKind::Method(_, sig, ..) => {
                 if sig.unsafety == hir::Unsafety::Unsafe {
                     cx.span_lint(UNSAFE_CODE, span, "implementation of an `unsafe` method")
                 }
@@ -1116,7 +1116,7 @@ impl LateLintPass for MutableTransmutes {
                 }
                 let typ = cx.tcx.node_id_to_type(expr.id);
                 match typ.sty {
-                    ty::TyFnDef(_, _, ref bare_fn) if bare_fn.abi == RustIntrinsic => {
+                    ty::TyFnDef(.., ref bare_fn) if bare_fn.abi == RustIntrinsic => {
                         let from = bare_fn.sig.0.inputs[0];
                         let to = bare_fn.sig.0.output;
                         return Some((&from.sty, &to.sty));
@@ -1129,7 +1129,7 @@ impl LateLintPass for MutableTransmutes {
 
         fn def_id_is_transmute(cx: &LateContext, def_id: DefId) -> bool {
             match cx.tcx.lookup_item_type(def_id).ty.sty {
-                ty::TyFnDef(_, _, ref bfty) if bfty.abi == RustIntrinsic => (),
+                ty::TyFnDef(.., ref bfty) if bfty.abi == RustIntrinsic => (),
                 _ => return false
             }
             cx.tcx.item_name(def_id).as_str() == "transmute"
diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs
index 44f1cf7b5335..f07720f5202b 100644
--- a/src/librustc_lint/unused.rs
+++ b/src/librustc_lint/unused.rs
@@ -334,7 +334,7 @@ impl UnusedParens {
                     contains_exterior_struct_lit(&x)
                 }
 
-                ast::ExprKind::MethodCall(_, _, ref exprs) => {
+                ast::ExprKind::MethodCall(.., ref exprs) => {
                     // X { y: 1 }.bar(...)
                     contains_exterior_struct_lit(&exprs[0])
                 }
@@ -355,15 +355,15 @@ impl EarlyLintPass for UnusedParens {
     fn check_expr(&mut self, cx: &EarlyContext, e: &ast::Expr) {
         use syntax::ast::ExprKind::*;
         let (value, msg, struct_lit_needs_parens) = match e.node {
-            If(ref cond, _, _) => (cond, "`if` condition", true),
-            While(ref cond, _, _) => (cond, "`while` condition", true),
-            IfLet(_, ref cond, _, _) => (cond, "`if let` head expression", true),
-            WhileLet(_, ref cond, _, _) => (cond, "`while let` head expression", true),
-            ForLoop(_, ref cond, _, _) => (cond, "`for` head expression", true),
+            If(ref cond, ..) => (cond, "`if` condition", true),
+            While(ref cond, ..) => (cond, "`while` condition", true),
+            IfLet(_, ref cond, ..) => (cond, "`if let` head expression", true),
+            WhileLet(_, ref cond, ..) => (cond, "`while let` head expression", true),
+            ForLoop(_, ref cond, ..) => (cond, "`for` head expression", true),
             Match(ref head, _) => (head, "`match` head expression", true),
             Ret(Some(ref value)) => (value, "`return` value", false),
             Assign(_, ref value) => (value, "assigned value", false),
-            AssignOp(_, _, ref value) => (value, "assigned value", false),
+            AssignOp(.., ref value) => (value, "assigned value", false),
             InPlace(_, ref value) => (value, "emplacement value", false),
             _ => return
         };
diff --git a/src/librustc_metadata/astencode.rs b/src/librustc_metadata/astencode.rs
index 9d9c6f033a96..fb7e1c0f7895 100644
--- a/src/librustc_metadata/astencode.rs
+++ b/src/librustc_metadata/astencode.rs
@@ -303,7 +303,7 @@ impl Folder for NestedItemsDropper {
         blk.and_then(|hir::Block {id, stmts, expr, rules, span, ..}| {
             let stmts_sans_items = stmts.into_iter().filter_map(|stmt| {
                 let use_stmt = match stmt.node {
-                    hir::StmtExpr(_, _) | hir::StmtSemi(_, _) => true,
+                    hir::StmtExpr(..) | hir::StmtSemi(..) => true,
                     hir::StmtDecl(ref decl, _) => {
                         match decl.node {
                             hir::DeclLocal(_) => true,
diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs
index 2524348dc1a9..7eb452ddbab1 100644
--- a/src/librustc_metadata/creader.rs
+++ b/src/librustc_metadata/creader.rs
@@ -490,7 +490,7 @@ impl<'a> CrateReader<'a> {
         // numbers
         let map: FnvHashMap<_, _> = decoder::get_crate_deps(cdata).iter().map(|dep| {
             debug!("resolving dep crate {} hash: `{}`", dep.name, dep.hash);
-            let (local_cnum, _, _) = self.resolve_crate(root,
+            let (local_cnum, ..) = self.resolve_crate(root,
                                                         &dep.name,
                                                         &dep.name,
                                                         Some(&dep.hash),
@@ -1003,13 +1003,13 @@ impl<'a> LocalCrateReader<'a> {
                     if !info.should_link {
                         return;
                     }
-                    let (cnum, _, _) = self.creader.resolve_crate(&None,
-                                                                  &info.ident,
-                                                                  &info.name,
-                                                                  None,
-                                                                  i.span,
-                                                                  PathKind::Crate,
-                                                                  true);
+                    let (cnum, ..) = self.creader.resolve_crate(&None,
+                                                                &info.ident,
+                                                                &info.name,
+                                                                None,
+                                                                i.span,
+                                                                PathKind::Crate,
+                                                                true);
 
                     let def_id = self.definitions.opt_local_def_id(i.id).unwrap();
                     let len = self.definitions.def_path(def_id.index).data.len();
diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs
index aeb95e5670d6..6b48b4dfabcf 100644
--- a/src/librustc_metadata/decoder.rs
+++ b/src/librustc_metadata/decoder.rs
@@ -492,7 +492,7 @@ pub fn get_adt_def<'a, 'tcx>(cdata: Cmd,
                    variant.name,
                    ctor_ty);
             let field_tys = match ctor_ty.sty {
-                ty::TyFnDef(_, _, &ty::BareFnTy { sig: ty::Binder(ty::FnSig {
+                ty::TyFnDef(.., &ty::BareFnTy { sig: ty::Binder(ty::FnSig {
                     ref inputs, ..
                 }), ..}) => {
                     // tuple-struct constructors don't have escaping regions
@@ -952,7 +952,7 @@ pub fn get_impl_or_trait_item<'a, 'tcx>(cdata: Cmd, id: DefIndex, tcx: TyCtxt<'a
             let predicates = doc_predicates(item_doc, tcx, cdata, tag_item_predicates);
             let ity = tcx.lookup_item_type(def_id).ty;
             let fty = match ity.sty {
-                ty::TyFnDef(_, _, fty) => fty,
+                ty::TyFnDef(.., fty) => fty,
                 _ => bug!(
                     "the type {:?} of the method {:?} is not a function?",
                     ity, name)
diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs
index 583631d2e0ab..23398a0400c5 100644
--- a/src/librustc_metadata/encoder.rs
+++ b/src/librustc_metadata/encoder.rs
@@ -915,7 +915,7 @@ impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> {
                 encode_deprecation(self.rbml_w, depr);
                 encode_attributes(self.rbml_w, &item.attrs);
             }
-            hir::ItemConst(_, _) => {
+            hir::ItemConst(..) => {
                 encode_def_id_and_key(ecx, self.rbml_w, def_id);
                 encode_family(self.rbml_w, 'C');
                 self.encode_bounds_and_type_for_item(item.id);
diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs
index c8f660a2d9c7..8812287c3429 100644
--- a/src/librustc_mir/hair/cx/expr.rs
+++ b/src/librustc_mir/hair/cx/expr.rs
@@ -217,7 +217,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
 
     let kind = match expr.node {
         // Here comes the interesting stuff:
-        hir::ExprMethodCall(_, _, ref args) => {
+        hir::ExprMethodCall(.., ref args) => {
             // Rewrite a.b(c) into UFCS form like Trait::b(a, c)
             let expr = method_callee(cx, expr, ty::MethodCall::expr(expr.id));
             let args = args.iter()
@@ -242,7 +242,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                 let method = method_callee(cx, expr, ty::MethodCall::expr(expr.id));
 
                 let sig = match method.ty.sty {
-                    ty::TyFnDef(_, _, fn_ty) => &fn_ty.sig,
+                    ty::TyFnDef(.., fn_ty) => &fn_ty.sig,
                     _ => span_bug!(expr.span, "type of method is not an fn")
                 };
 
@@ -743,7 +743,7 @@ fn convert_var<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
             let body_id = match cx.tcx.map.find(closure_expr_id) {
                 Some(map::NodeExpr(expr)) => {
                     match expr.node {
-                        hir::ExprClosure(_, _, ref body, _) => body.id,
+                        hir::ExprClosure(.., ref body, _) => body.id,
                         _ => {
                             span_bug!(expr.span, "closure expr is not a closure expr");
                         }
diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs
index 919b23ffda54..8dd33ad2f9c7 100644
--- a/src/librustc_mir/hair/cx/mod.rs
+++ b/src/librustc_mir/hair/cx/mod.rs
@@ -54,7 +54,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
                 let fn_like = FnLikeNode::from_node(infcx.tcx.map.get(id));
                 match fn_like.map(|f| f.kind()) {
                     Some(FnKind::ItemFn(_, _, _, c, ..)) => c,
-                    Some(FnKind::Method(_, m, _, _)) => m.constness,
+                    Some(FnKind::Method(_, m, ..)) => m.constness,
                     _ => hir::Constness::NotConst
                 }
             }
diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs
index 751f25b27940..0bcd3e6d4ebb 100644
--- a/src/librustc_mir/transform/qualify_consts.rs
+++ b/src/librustc_mir/transform/qualify_consts.rs
@@ -122,7 +122,7 @@ fn is_const_fn(tcx: TyCtxt, def_id: DefId) -> bool {
             Some(FnKind::ItemFn(_, _, _, c, ..)) => {
                 c == hir::Constness::Const
             }
-            Some(FnKind::Method(_, m, _, _)) => {
+            Some(FnKind::Method(_, m, ..)) => {
                 m.constness == hir::Constness::Const
             }
             _ => false
@@ -576,9 +576,9 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
             Rvalue::Repeat(..) |
             Rvalue::UnaryOp(..) |
             Rvalue::CheckedBinaryOp(..) |
-            Rvalue::Cast(CastKind::ReifyFnPointer, _, _) |
-            Rvalue::Cast(CastKind::UnsafeFnPointer, _, _) |
-            Rvalue::Cast(CastKind::Unsize, _, _) => {}
+            Rvalue::Cast(CastKind::ReifyFnPointer, ..) |
+            Rvalue::Cast(CastKind::UnsafeFnPointer, ..) |
+            Rvalue::Cast(CastKind::Unsize, ..) => {}
 
             Rvalue::Len(_) => {
                 // Static lvalues in consts would have errored already,
@@ -705,7 +705,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
             }
 
             Rvalue::Aggregate(ref kind, _) => {
-                if let AggregateKind::Adt(def, _, _, _) = *kind {
+                if let AggregateKind::Adt(def, ..) = *kind {
                     if def.has_dtor() {
                         self.add(Qualif::NEEDS_DROP);
                         self.deny_drop();
diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs
index 55bd51cd75ba..e260b1d262ae 100644
--- a/src/librustc_mir/transform/type_check.rs
+++ b/src/librustc_mir/transform/type_check.rs
@@ -457,7 +457,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
                 let func_ty = func.ty(mir, tcx);
                 debug!("check_terminator: call, func_ty={:?}", func_ty);
                 let func_ty = match func_ty.sty {
-                    ty::TyFnDef(_, _, func_ty) | ty::TyFnPtr(func_ty) => func_ty,
+                    ty::TyFnDef(.., func_ty) | ty::TyFnPtr(func_ty) => func_ty,
                     _ => {
                         span_mirbug!(self, term, "call to non-function {:?}", func_ty);
                         return;
diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs
index 6a24742426ab..6275639a9adf 100644
--- a/src/librustc_passes/ast_validation.rs
+++ b/src/librustc_passes/ast_validation.rs
@@ -98,7 +98,7 @@ impl<'a> Visitor for AstValidator<'a> {
 
     fn visit_expr(&mut self, expr: &Expr) {
         match expr.node {
-            ExprKind::While(_, _, Some(ident)) |
+            ExprKind::While(.., Some(ident)) |
             ExprKind::Loop(_, Some(ident)) |
             ExprKind::WhileLet(.., Some(ident)) |
             ExprKind::ForLoop(.., Some(ident)) |
diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs
index 3094ff49f1f5..d4e8eb51cde2 100644
--- a/src/librustc_passes/consts.rs
+++ b/src/librustc_passes/consts.rs
@@ -149,7 +149,7 @@ impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> {
         let mode = match fk {
             FnKind::ItemFn(_, _, _, hir::Constness::Const, ..)
                 => Mode::ConstFn,
-            FnKind::Method(_, m, _, _) => {
+            FnKind::Method(_, m, ..) => {
                 if m.constness == hir::Constness::Const {
                     Mode::ConstFn
                 } else {
@@ -307,8 +307,8 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> {
                         hir::DeclItem(_) => continue,
                     }
                 }
-                hir::StmtExpr(_, _) => {}
-                hir::StmtSemi(_, _) => {}
+                hir::StmtExpr(..) => {}
+                hir::StmtSemi(..) => {}
             }
             self.add_qualif(ConstQualif::NOT_CONST);
         }
@@ -671,7 +671,7 @@ impl<'a, 'gcx, 'tcx> euv::Delegate<'tcx> for CheckCrateVisitor<'a, 'gcx> {
                 Categorization::StaticItem => {
                     break;
                 }
-                Categorization::Deref(ref cmt, _, _) |
+                Categorization::Deref(ref cmt, ..) |
                 Categorization::Downcast(ref cmt, _) |
                 Categorization::Interior(ref cmt, _) => cur = cmt,
 
@@ -716,7 +716,7 @@ impl<'a, 'gcx, 'tcx> euv::Delegate<'tcx> for CheckCrateVisitor<'a, 'gcx> {
                         // type of the expression.  `&mut [1]` has exactly the
                         // same representation as &mut 1.
                         match cmt.ty.sty {
-                            ty::TyArray(_, _) |
+                            ty::TyArray(..) |
                             ty::TySlice(_) => break,
                             _ => {}
                         }
@@ -727,7 +727,7 @@ impl<'a, 'gcx, 'tcx> euv::Delegate<'tcx> for CheckCrateVisitor<'a, 'gcx> {
                 Categorization::StaticItem => {
                     break;
                 }
-                Categorization::Deref(ref cmt, _, _) |
+                Categorization::Deref(ref cmt, ..) |
                 Categorization::Downcast(ref cmt, _) |
                 Categorization::Interior(ref cmt, _) => {
                     cur = cmt;
diff --git a/src/librustc_passes/loops.rs b/src/librustc_passes/loops.rs
index eab16bd5bd1b..e942707acd56 100644
--- a/src/librustc_passes/loops.rs
+++ b/src/librustc_passes/loops.rs
@@ -53,7 +53,7 @@ impl<'a, 'v> Visitor<'v> for CheckLoopVisitor<'a> {
             hir::ExprLoop(ref b, _) => {
                 self.with_context(Loop, |v| v.visit_block(&b));
             }
-            hir::ExprClosure(_, _, ref b, _) => {
+            hir::ExprClosure(.., ref b, _) => {
                 self.with_context(Closure, |v| v.visit_block(&b));
             }
             hir::ExprBreak(_) => self.require_loop("break", e.span),
diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs
index 5e374ce7c580..8c72933c4ce4 100644
--- a/src/librustc_privacy/lib.rs
+++ b/src/librustc_privacy/lib.rs
@@ -249,7 +249,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> {
             // The interface is empty
             hir::ItemDefaultImpl(..) => {}
             // Visit everything except for private impl items
-            hir::ItemImpl(_, _, ref generics, None, _, ref impl_items) => {
+            hir::ItemImpl(.., ref generics, None, _, ref impl_items) => {
                 if item_level.is_some() {
                     self.reach().visit_generics(generics);
                     for impl_item in impl_items {
@@ -454,7 +454,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> {
                 if let Def::Struct(..) = self.tcx.expect_def(expr.id) {
                     let expr_ty = self.tcx.expr_ty(expr);
                     let def = match expr_ty.sty {
-                        ty::TyFnDef(_, _, &ty::BareFnTy { sig: ty::Binder(ty::FnSig {
+                        ty::TyFnDef(.., &ty::BareFnTy { sig: ty::Binder(ty::FnSig {
                             output: ty, ..
                         }), ..}) => ty,
                         _ => expr_ty
@@ -644,7 +644,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx>
             // namespace (the contents have their own privacies).
             hir::ItemForeignMod(_) => {}
 
-            hir::ItemTrait(_, _, ref bounds, _) => {
+            hir::ItemTrait(.., ref bounds, _) => {
                 if !self.trait_is_public(item.id) {
                     return
                 }
@@ -659,7 +659,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx>
             // (i.e. we could just return here to not check them at
             // all, or some worse estimation of whether an impl is
             // publicly visible).
-            hir::ItemImpl(_, _, ref g, ref trait_ref, ref self_, ref impl_items) => {
+            hir::ItemImpl(.., ref g, ref trait_ref, ref self_, ref impl_items) => {
                 // `impl [... for] Private` is never visible.
                 let self_contains_private;
                 // impl [... for] Public<...>, but not `impl [... for]
@@ -1091,7 +1091,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivateItemsInPublicInterfacesVisitor<'a, 'tc
             hir::ItemDefaultImpl(..) => {}
             // An inherent impl is public when its type is public
             // Subitems of inherent impls have their own publicity
-            hir::ItemImpl(_, _, ref generics, None, ref ty, ref impl_items) => {
+            hir::ItemImpl(.., ref generics, None, ref ty, ref impl_items) => {
                 let ty_vis = self.ty_visibility(ty);
                 check.required_visibility = ty_vis;
                 check.visit_generics(generics);
@@ -1105,7 +1105,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivateItemsInPublicInterfacesVisitor<'a, 'tc
             }
             // A trait impl is public when both its type and its trait are public
             // Subitems of trait impls have inherited publicity
-            hir::ItemImpl(_, _, ref generics, Some(ref trait_ref), ref ty, ref impl_items) => {
+            hir::ItemImpl(.., ref generics, Some(ref trait_ref), ref ty, ref impl_items) => {
                 let vis = min(self.ty_visibility(ty), self.trait_ref_visibility(trait_ref));
                 check.required_visibility = vis;
                 check.visit_generics(generics);
diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs
index 98ddff70462c..ad750ccc0129 100644
--- a/src/librustc_resolve/build_reduced_graph.rs
+++ b/src/librustc_resolve/build_reduced_graph.rs
@@ -228,7 +228,7 @@ impl<'b> Resolver<'b> {
                 let def = Def::Static(self.definitions.local_def_id(item.id), mutbl);
                 self.define(parent, name, ValueNS, (def, sp, vis));
             }
-            ItemKind::Const(_, _) => {
+            ItemKind::Const(..) => {
                 let def = Def::Const(self.definitions.local_def_id(item.id));
                 self.define(parent, name, ValueNS, (def, sp, vis));
             }
@@ -292,7 +292,7 @@ impl<'b> Resolver<'b> {
                 self.structs.insert(item_def_id, field_names);
             }
 
-            ItemKind::DefaultImpl(_, _) | ItemKind::Impl(..) => {}
+            ItemKind::DefaultImpl(..) | ItemKind::Impl(..) => {}
 
             ItemKind::Trait(.., ref items) => {
                 let def_id = self.definitions.local_def_id(item.id);
diff --git a/src/librustc_resolve/check_unused.rs b/src/librustc_resolve/check_unused.rs
index bc923ba29ca4..93abe07128fa 100644
--- a/src/librustc_resolve/check_unused.rs
+++ b/src/librustc_resolve/check_unused.rs
@@ -95,7 +95,7 @@ impl<'a, 'b> Visitor for UnusedImportCheckVisitor<'a, 'b> {
             }
             ast::ItemKind::Use(ref p) => {
                 match p.node {
-                    ViewPathSimple(_, _) => {
+                    ViewPathSimple(..) => {
                         self.check_import(item.id, p.span)
                     }
 
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index 0a86eeef7c45..0420fa802688 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -381,7 +381,7 @@ fn resolve_struct_error<'b, 'a: 'b, 'c>(resolver: &'b Resolver<'a>,
                                     module = path,
                                     ident = ident.node)
                         }
-                        Some(&ExprKind::MethodCall(ident, _, _)) => {
+                        Some(&ExprKind::MethodCall(ident, ..)) => {
                             format!("to call a function from the `{module}` module, \
                                      use `{module}::{ident}(..)`",
                                     module = path,
@@ -1643,7 +1643,7 @@ impl<'a> Resolver<'a> {
             ItemKind::DefaultImpl(_, ref trait_ref) => {
                 self.with_optional_trait_ref(Some(trait_ref), |_, _| {});
             }
-            ItemKind::Impl(_, _, ref generics, ref opt_trait_ref, ref self_type, ref impl_items) =>
+            ItemKind::Impl(.., ref generics, ref opt_trait_ref, ref self_type, ref impl_items) =>
                 self.resolve_implementation(generics,
                                             opt_trait_ref,
                                             &self_type,
@@ -2369,7 +2369,7 @@ impl<'a> Resolver<'a> {
                     self.record_def(pat.id, resolution);
                 }
 
-                PatKind::TupleStruct(ref path, _, _) => {
+                PatKind::TupleStruct(ref path, ..) => {
                     self.resolve_pattern_path(pat.id, None, path, ValueNS, |def| {
                         match def {
                             Def::Struct(..) | Def::Variant(..) => true,
@@ -2388,7 +2388,7 @@ impl<'a> Resolver<'a> {
                     }, "variant, struct or constant");
                 }
 
-                PatKind::Struct(ref path, _, _) => {
+                PatKind::Struct(ref path, ..) => {
                     self.resolve_pattern_path(pat.id, None, path, TypeNS, |def| {
                         match def {
                             Def::Struct(..) | Def::Union(..) | Def::Variant(..) |
@@ -2963,7 +2963,7 @@ impl<'a> Resolver<'a> {
                 visit::walk_expr(self, expr);
             }
 
-            ExprKind::Struct(ref path, _, _) => {
+            ExprKind::Struct(ref path, ..) => {
                 // Resolve the path to the structure it goes to. We don't
                 // check to ensure that the path is actually a structure; that
                 // is checked later during typeck.
@@ -2985,7 +2985,7 @@ impl<'a> Resolver<'a> {
                 visit::walk_expr(self, expr);
             }
 
-            ExprKind::Loop(_, Some(label)) | ExprKind::While(_, _, Some(label)) => {
+            ExprKind::Loop(_, Some(label)) | ExprKind::While(.., Some(label)) => {
                 self.with_label_rib(|this| {
                     let def = Def::Label(expr.id);
 
@@ -3077,7 +3077,7 @@ impl<'a> Resolver<'a> {
                 let traits = self.get_traits_containing_item(name.node.name);
                 self.trait_map.insert(expr.id, traits);
             }
-            ExprKind::MethodCall(name, _, _) => {
+            ExprKind::MethodCall(name, ..) => {
                 debug!("(recording candidate traits for expr) recording traits for {}",
                        expr.id);
                 let traits = self.get_traits_containing_item(name.node.name);
@@ -3241,7 +3241,7 @@ impl<'a> Resolver<'a> {
                     if !in_module_is_extern || name_binding.vis == ty::Visibility::Public {
                         // add the module to the lookup
                         let is_extern = in_module_is_extern || name_binding.is_extern_crate();
-                        if !worklist.iter().any(|&(m, _, _)| m.def == module.def) {
+                        if !worklist.iter().any(|&(m, ..)| m.def == module.def) {
                             worklist.push((module, path_segments, is_extern));
                         }
                     }
diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs
index 329527b304e3..eaf2a8f5e781 100644
--- a/src/librustc_save_analysis/dump_visitor.rs
+++ b/src/librustc_save_analysis/dump_visitor.rs
@@ -312,7 +312,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
                     qualname: String::new()
                 }.lower(self.tcx));
             }
-            Def::Static(_, _) |
+            Def::Static(..) |
             Def::Const(_) |
             Def::AssociatedConst(..) |
             Def::Local(..) |
@@ -351,7 +351,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
             let mut collector = PathCollector::new();
             collector.visit_pat(&arg.pat);
             let span_utils = self.span.clone();
-            for &(id, ref p, _, _) in &collector.collected_paths {
+            for &(id, ref p, ..) in &collector.collected_paths {
                 let typ = self.tcx.node_types().get(&id).unwrap().to_string();
                 // get the span only for the name of the variable (I hope the path is only ever a
                 // variable name, but who knows?)
@@ -879,7 +879,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
                 }
             }
             Def::Local(..) |
-            Def::Static(_,_) |
+            Def::Static(..) |
             Def::Const(..) |
             Def::AssociatedConst(..) |
             Def::Struct(..) |
@@ -1145,7 +1145,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D>
                 self.process_static_or_const_item(item, &typ, &expr),
             Struct(ref def, ref ty_params) => self.process_struct(item, def, ty_params),
             Enum(ref def, ref ty_params) => self.process_enum(item, def, ty_params),
-            Impl(_, _,
+            Impl(..,
                           ref ty_params,
                           ref trait_ref,
                           ref typ,
@@ -1280,7 +1280,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D>
                 let def = self.tcx.expect_def(hir_expr.id);
                 self.process_struct_lit(ex, path, fields, adt.variant_of_def(def), base)
             }
-            ast::ExprKind::MethodCall(_, _, ref args) => self.process_method_call(ex, args),
+            ast::ExprKind::MethodCall(.., ref args) => self.process_method_call(ex, args),
             ast::ExprKind::Field(ref sub_ex, _) => {
                 self.visit_expr(&sub_ex);
 
@@ -1409,7 +1409,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D>
                     paths_to_process.push((id, p.clone(), Some(ref_kind)))
                 }
                 // FIXME(nrc) what are these doing here?
-                Def::Static(_, _) |
+                Def::Static(..) |
                 Def::Const(..) |
                 Def::AssociatedConst(..) => {}
                 def => error!("unexpected definition kind when processing collected paths: {:?}",
diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs
index 559893b26fac..f69edea047e3 100644
--- a/src/librustc_save_analysis/lib.rs
+++ b/src/librustc_save_analysis/lib.rs
@@ -422,7 +422,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
                     }
                 }
             }
-            ast::ExprKind::Struct(ref path, _, _) => {
+            ast::ExprKind::Struct(ref path, ..) => {
                 match self.tcx.expr_ty_adjusted(&hir_node).sty {
                     ty::TyStruct(def, _) | ty::TyUnion(def, _) => {
                         let sub_span = self.span_utils.span_for_last_ident(path.span);
@@ -694,11 +694,11 @@ impl PathCollector {
 impl Visitor for PathCollector {
     fn visit_pat(&mut self, p: &ast::Pat) {
         match p.node {
-            PatKind::Struct(ref path, _, _) => {
+            PatKind::Struct(ref path, ..) => {
                 self.collected_paths.push((p.id, path.clone(),
                                            ast::Mutability::Mutable, recorder::TypeRef));
             }
-            PatKind::TupleStruct(ref path, _, _) |
+            PatKind::TupleStruct(ref path, ..) |
             PatKind::Path(_, ref path) => {
                 self.collected_paths.push((p.id, path.clone(),
                                            ast::Mutability::Mutable, recorder::VarRef));
diff --git a/src/librustc_trans/adt.rs b/src/librustc_trans/adt.rs
index 15a9d58c9b57..9eeefa079fb6 100644
--- a/src/librustc_trans/adt.rs
+++ b/src/librustc_trans/adt.rs
@@ -701,7 +701,7 @@ fn generic_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
     debug!("adt::generic_type_of r: {:?} name: {:?} sizing: {} dst: {}",
            r, name, sizing, dst);
     match *r {
-        CEnum(ity, _, _) => ll_inttype(cx, ity),
+        CEnum(ity, ..) => ll_inttype(cx, ity),
         RawNullablePointer { nnty, .. } =>
             type_of::sizing_type_of(cx, nnty),
         StructWrappedNullablePointer { nonnull: ref st, .. } => {
@@ -839,7 +839,7 @@ pub fn trans_switch<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
 
 pub fn is_discr_signed<'tcx>(r: &Repr<'tcx>) -> bool {
     match *r {
-        CEnum(ity, _, _) => ity.is_signed(),
+        CEnum(ity, ..) => ity.is_signed(),
         General(ity, _) => ity.is_signed(),
         Univariant(..) | UntaggedUnion(..) => false,
         RawNullablePointer { .. } => false,
@@ -918,7 +918,7 @@ fn load_discr(bcx: Block, ity: IntType, ptr: ValueRef, min: Disr, max: Disr,
 pub fn trans_case<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr, discr: Disr)
                               -> ValueRef {
     match *r {
-        CEnum(ity, _, _) => {
+        CEnum(ity, ..) => {
             C_integral(ll_inttype(bcx.ccx(), ity), discr.0, true)
         }
         General(ity, _) => {
diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs
index 081b4431bd7b..04b814e2b977 100644
--- a/src/librustc_trans/back/write.rs
+++ b/src/librustc_trans/back/write.rs
@@ -1130,10 +1130,10 @@ pub unsafe fn with_llvm_pmb(llmod: ModuleRef,
     // inline with lifetime intrinsics, and O2+ we add an inliner with a
     // thresholds copied from clang.
     match (opt_level, opt_size, inline_threshold) {
-        (_, _, Some(t)) => {
+        (.., Some(t)) => {
             llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, t as u32);
         }
-        (llvm::CodeGenOptLevel::Aggressive, _, _) => {
+        (llvm::CodeGenOptLevel::Aggressive, ..) => {
             llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 275);
         }
         (_, llvm::CodeGenOptSizeDefault, _) => {
@@ -1142,16 +1142,16 @@ pub unsafe fn with_llvm_pmb(llmod: ModuleRef,
         (_, llvm::CodeGenOptSizeAggressive, _) => {
             llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 25);
         }
-        (llvm::CodeGenOptLevel::None, _, _) => {
+        (llvm::CodeGenOptLevel::None, ..) => {
             llvm::LLVMRustAddAlwaysInlinePass(builder, false);
         }
-        (llvm::CodeGenOptLevel::Less, _, _) => {
+        (llvm::CodeGenOptLevel::Less, ..) => {
             llvm::LLVMRustAddAlwaysInlinePass(builder, true);
         }
-        (llvm::CodeGenOptLevel::Default, _, _) => {
+        (llvm::CodeGenOptLevel::Default, ..) => {
             llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 225);
         }
-        (llvm::CodeGenOptLevel::Other, _, _) => {
+        (llvm::CodeGenOptLevel::Other, ..) => {
             bug!("CodeGenOptLevel::Other selected")
         }
     }
diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs
index 99126095ede3..c94de0811808 100644
--- a/src/librustc_trans/base.rs
+++ b/src/librustc_trans/base.rs
@@ -924,7 +924,7 @@ impl<'blk, 'tcx> FunctionContext<'blk, 'tcx> {
                block_arena: &'blk TypedArena>)
                -> FunctionContext<'blk, 'tcx> {
         let (param_substs, def_id) = match definition {
-            Some((instance, _, _)) => {
+            Some((instance, ..)) => {
                 common::validate_substs(instance.substs);
                 (instance.substs, Some(instance.def))
             }
diff --git a/src/librustc_trans/cabi_x86_64.rs b/src/librustc_trans/cabi_x86_64.rs
index 805c7d345a0e..eb67f4ca6185 100644
--- a/src/librustc_trans/cabi_x86_64.rs
+++ b/src/librustc_trans/cabi_x86_64.rs
@@ -182,7 +182,7 @@ fn classify_ty(ty: Type) -> Vec {
             (SSEDs,       SSEUp) |
             (SSEInt(_),   SSEUp) => return,
 
-            (_,           _) => newv
+            (..) => newv
         };
         cls[i] = to_write;
     }
diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs
index 33cacbe194bb..a6b92b949e0f 100644
--- a/src/librustc_trans/callee.rs
+++ b/src/librustc_trans/callee.rs
@@ -98,7 +98,7 @@ impl<'tcx> Callee<'tcx> {
         }
 
         let fn_ty = def_ty(ccx.shared(), def_id, substs);
-        if let ty::TyFnDef(_, _, f) = fn_ty.sty {
+        if let ty::TyFnDef(.., f) = fn_ty.sty {
             if f.abi == Abi::RustIntrinsic || f.abi == Abi::PlatformIntrinsic {
                 return Callee {
                     data: Intrinsic,
@@ -314,7 +314,7 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>(
     // Construct the "tuply" version of `bare_fn_ty`. It takes two arguments: `self`,
     // which is the fn pointer, and `args`, which is the arguments tuple.
     let sig = match bare_fn_ty.sty {
-        ty::TyFnDef(_, _,
+        ty::TyFnDef(..,
                     &ty::BareFnTy { unsafety: hir::Unsafety::Normal,
                                     abi: Abi::Rust,
                                     ref sig }) |
@@ -442,7 +442,7 @@ fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     // other weird situations. Annoying.
 
     let fn_ptr_ty = match fn_ty.sty {
-        ty::TyFnDef(_, _, fty) => {
+        ty::TyFnDef(.., fty) => {
             // Create a fn pointer with the substituted signature.
             tcx.mk_fn_ptr(fty)
         }
diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs
index b5c922d7fda4..704fac5ce7e5 100644
--- a/src/librustc_trans/collector.rs
+++ b/src/librustc_trans/collector.rs
@@ -628,7 +628,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
                                               def_id: DefId)
                                               -> bool {
             if !match tcx.lookup_item_type(def_id).ty.sty {
-                ty::TyFnDef(def_id, _, _) => {
+                ty::TyFnDef(def_id, ..) => {
                     // Some constructors also have type TyFnDef but they are
                     // always instantiated inline and don't result in
                     // translation item. Same for FFI functions.
@@ -1214,8 +1214,7 @@ fn create_trans_items_for_default_impls<'a, 'tcx>(scx: &SharedCrateContext<'a, '
         hir::ItemImpl(_,
                       _,
                       ref generics,
-                      _,
-                      _,
+                      ..,
                       ref items) => {
             if generics.is_type_parameterized() {
                 return
diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs
index bdfeee37625e..1bf1023dcd89 100644
--- a/src/librustc_trans/debuginfo/metadata.rs
+++ b/src/librustc_trans/debuginfo/metadata.rs
@@ -252,7 +252,7 @@ impl<'tcx> TypeMap<'tcx> {
                                        principal.substs,
                                        &mut unique_type_id);
             },
-            ty::TyFnDef(_, _, &ty::BareFnTy{ unsafety, abi, ref sig } ) |
+            ty::TyFnDef(.., &ty::BareFnTy{ unsafety, abi, ref sig } ) |
             ty::TyFnPtr(&ty::BareFnTy{ unsafety, abi, ref sig } ) => {
                 if unsafety == hir::Unsafety::Unsafe {
                     unique_type_id.push_str("unsafe ");
@@ -756,7 +756,7 @@ pub fn type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                 }
             }
         }
-        ty::TyFnDef(_, _, ref barefnty) | ty::TyFnPtr(ref barefnty) => {
+        ty::TyFnDef(.., ref barefnty) | ty::TyFnPtr(ref barefnty) => {
             let fn_metadata = subroutine_type_metadata(cx,
                                                        unique_type_id,
                                                        &barefnty.sig,
@@ -1679,7 +1679,7 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
     let type_rep = adt::represent_type(cx, enum_type);
 
     let discriminant_type_metadata = match *type_rep {
-        adt::CEnum(inttype, _, _) => {
+        adt::CEnum(inttype, ..) => {
             return FinalMetadata(discriminant_type_metadata(inttype))
         },
         adt::RawNullablePointer { .. }           |
@@ -1962,4 +1962,4 @@ pub fn extend_scope_to_file(ccx: &CrateContext,
             scope_metadata,
             file_metadata)
     }
-}
\ No newline at end of file
+}
diff --git a/src/librustc_trans/debuginfo/type_names.rs b/src/librustc_trans/debuginfo/type_names.rs
index bd839243e201..8291f84054d0 100644
--- a/src/librustc_trans/debuginfo/type_names.rs
+++ b/src/librustc_trans/debuginfo/type_names.rs
@@ -100,7 +100,7 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
             push_item_name(cx, principal.def_id, false, output);
             push_type_params(cx, principal.substs, output);
         },
-        ty::TyFnDef(_, _, &ty::BareFnTy{ unsafety, abi, ref sig } ) |
+        ty::TyFnDef(.., &ty::BareFnTy{ unsafety, abi, ref sig } ) |
         ty::TyFnPtr(&ty::BareFnTy{ unsafety, abi, ref sig } ) => {
             if unsafety == hir::Unsafety::Unsafe {
                 output.push_str("unsafe ");
diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs
index 8bef7584db9e..c0ff6c508bf3 100644
--- a/src/librustc_trans/intrinsic.rs
+++ b/src/librustc_trans/intrinsic.rs
@@ -544,7 +544,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
 
         }
 
-        (_, _) => {
+        (..) => {
             let intr = match Intrinsic::find(&name) {
                 Some(intr) => intr,
                 None => bug!("unknown intrinsic '{}'", name),
diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs
index 3ab4290e7b9b..fbd04d7b3802 100644
--- a/src/librustc_trans/mir/block.rs
+++ b/src/librustc_trans/mir/block.rs
@@ -406,7 +406,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
 
                 // Handle intrinsics old trans wants Expr's for, ourselves.
                 let intrinsic = match (&callee.ty.sty, &callee.data) {
-                    (&ty::TyFnDef(def_id, _, _), &Intrinsic) => {
+                    (&ty::TyFnDef(def_id, ..), &Intrinsic) => {
                         Some(bcx.tcx().item_name(def_id).as_str())
                     }
                     _ => None
@@ -880,7 +880,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                 // FIXME #19925 Remove this hack after a release cycle.
                 let f = Callee::def(bcx.ccx(), def_id, substs);
                 let ty = match f.ty.sty {
-                    ty::TyFnDef(_, _, f) => bcx.tcx().mk_fn_ptr(f),
+                    ty::TyFnDef(.., f) => bcx.tcx().mk_fn_ptr(f),
                     _ => f.ty
                 };
                 val = OperandRef {
diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs
index deef0b09a17b..3d85da42a6dc 100644
--- a/src/librustc_trans/trans_item.rs
+++ b/src/librustc_trans/trans_item.rs
@@ -454,7 +454,7 @@ pub fn push_unique_type_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                              &trait_data.projection_bounds,
                              output);
         },
-        ty::TyFnDef(_, _, &ty::BareFnTy{ unsafety, abi, ref sig } ) |
+        ty::TyFnDef(.., &ty::BareFnTy{ unsafety, abi, ref sig } ) |
         ty::TyFnPtr(&ty::BareFnTy{ unsafety, abi, ref sig } ) => {
             if unsafety == hir::Unsafety::Unsafe {
                 output.push_str("unsafe ");
diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs
index acb6653214dc..49db56d2dabd 100644
--- a/src/librustc_typeck/check/callee.rs
+++ b/src/librustc_typeck/check/callee.rs
@@ -186,7 +186,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         let error_fn_sig;
 
         let fn_sig = match callee_ty.sty {
-            ty::TyFnDef(_, _, &ty::BareFnTy {ref sig, ..}) |
+            ty::TyFnDef(.., &ty::BareFnTy {ref sig, ..}) |
             ty::TyFnPtr(&ty::BareFnTy {ref sig, ..}) => {
                 sig
             }
diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs
index 54e63497e620..1fda38d8a330 100644
--- a/src/librustc_typeck/check/cast.rs
+++ b/src/librustc_typeck/check/cast.rs
@@ -319,7 +319,7 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
             (Some(t_from), Some(t_cast)) => (t_from, t_cast),
             // Function item types may need to be reified before casts.
             (None, Some(t_cast)) => {
-                if let ty::TyFnDef(_, _, f) = self.expr_ty.sty {
+                if let ty::TyFnDef(.., f) = self.expr_ty.sty {
                     // Attempt a coercion to a fn pointer type.
                     let res = fcx.try_coerce(self.expr, fcx.tcx.mk_fn_ptr(f));
                     if !res.is_ok() {
diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs
index 365c18d5e666..60ca9309eea0 100644
--- a/src/librustc_typeck/check/coercion.rs
+++ b/src/librustc_typeck/check/coercion.rs
@@ -195,7 +195,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
         }
 
         match a.sty {
-            ty::TyFnDef(_, _, a_f) => {
+            ty::TyFnDef(.., a_f) => {
                 // Function items are coercible to any closure
                 // type; function pointers are not (that would
                 // require double indirection).
diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs
index bde7f20f5e6e..eb87c230b74a 100644
--- a/src/librustc_typeck/check/intrinsic.rs
+++ b/src/librustc_typeck/check/intrinsic.rs
@@ -53,7 +53,7 @@ fn equate_intrinsic_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     if i_n_tps != n_tps {
         let span = match it.node {
             hir::ForeignItemFn(_, ref generics) => generics.span,
-            hir::ForeignItemStatic(_, _) => it.span
+            hir::ForeignItemStatic(..) => it.span
         };
 
         struct_span_err!(tcx.sess, span, E0094,
diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs
index be77ca435a18..dbf74e371df4 100644
--- a/src/librustc_typeck/check/method/confirm.rs
+++ b/src/librustc_typeck/check/method/confirm.rs
@@ -501,7 +501,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
                                 assert!(adr.unsize.is_none());
                                 (adr.autoderefs, None)
                             }
-                            Some(AutoPtr(_, _)) => {
+                            Some(AutoPtr(..)) => {
                                 (adr.autoderefs, adr.unsize.map(|target| {
                                     target.builtin_deref(false, NoPreference)
                                             .expect("fixup: AutoPtr is not &T").ty
diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs
index edee73008687..058049992dc0 100644
--- a/src/librustc_typeck/check/method/probe.rs
+++ b/src/librustc_typeck/check/method/probe.rs
@@ -1314,8 +1314,8 @@ impl<'tcx> Candidate<'tcx> {
         Pick {
             item: self.item.clone(),
             kind: match self.kind {
-                InherentImplCandidate(_, _) => InherentImplPick,
-                ExtensionImplCandidate(def_id, _, _) => {
+                InherentImplCandidate(..) => InherentImplPick,
+                ExtensionImplCandidate(def_id, ..) => {
                     ExtensionImplPick(def_id)
                 }
                 ObjectCandidate => ObjectPick,
@@ -1340,10 +1340,10 @@ impl<'tcx> Candidate<'tcx> {
 
     fn to_source(&self) -> CandidateSource {
         match self.kind {
-            InherentImplCandidate(_, _) => {
+            InherentImplCandidate(..) => {
                 ImplSource(self.item.container().id())
             }
-            ExtensionImplCandidate(def_id, _, _) => ImplSource(def_id),
+            ExtensionImplCandidate(def_id, ..) => ImplSource(def_id),
             ObjectCandidate |
             TraitCandidate |
             WhereClauseCandidate(_) => TraitSource(self.item.container().id()),
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 36c2494a0065..0aa523e9d5e4 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -536,7 +536,7 @@ fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                            fn_id: ast::NodeId) {
     let raw_fty = ccx.tcx.lookup_item_type(ccx.tcx.map.local_def_id(fn_id)).ty;
     let fn_ty = match raw_fty.sty {
-        ty::TyFnDef(_, _, f) => f,
+        ty::TyFnDef(.., f) => f,
         _ => span_bug!(body.span, "check_bare_fn: function type expected")
     };
 
@@ -732,7 +732,7 @@ pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) {
     let _indenter = indenter();
     match it.node {
       // Consts can play a role in type-checking, so they are included here.
-      hir::ItemStatic(_, _, ref e) |
+      hir::ItemStatic(.., ref e) |
       hir::ItemConst(_, ref e) => check_const(ccx, &e, it.id),
       hir::ItemEnum(ref enum_definition, _) => {
         check_enum_variants(ccx,
@@ -2410,7 +2410,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             self.tcx.types.err
         } else {
             match method_fn_ty.sty {
-                ty::TyFnDef(_, _, ref fty) => {
+                ty::TyFnDef(.., ref fty) => {
                     // HACK(eddyb) ignore self in the definition (see above).
                     let expected_arg_tys = self.expected_types_for_fn_args(sp, expected,
                                                                            fty.sig.0.output,
@@ -2647,7 +2647,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                            t)
                         }, arg_ty);
                     }
-                    ty::TyFnDef(_, _, f) => {
+                    ty::TyFnDef(.., f) => {
                         let ptr_ty = self.tcx.mk_fn_ptr(f);
                         let ptr_ty = self.resolve_type_vars_if_possible(&ptr_ty);
                         self.type_error_message(arg.span,
@@ -3983,7 +3983,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                         _ => false,
                     }
                 }
-                hir::StmtExpr(_, _) | hir::StmtSemi(_, _) => true,
+                hir::StmtExpr(..) | hir::StmtSemi(..) => true,
             } {
                 self.tcx
                     .sess
@@ -4209,7 +4209,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         self.tcx.prohibit_type_params(&segments[..segments.len() - poly_segments]);
 
         match def {
-            Def::Local(_, nid) | Def::Upvar(_, nid, _, _) => {
+            Def::Local(_, nid) | Def::Upvar(_, nid, ..) => {
                 let ty = self.local_ty(span, nid);
                 let ty = self.normalize_associated_types_in(span, &ty);
                 self.write_ty(node_id, ty);
diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs
index cef2bb07e35c..939deee27c60 100644
--- a/src/librustc_typeck/check/regionck.rs
+++ b/src/librustc_typeck/check/regionck.rs
@@ -576,7 +576,7 @@ impl<'a, 'gcx, 'tcx, 'v> Visitor<'v> for RegionCtxt<'a, 'gcx, 'tcx> {
                     }
                 }
                 /*
-                adjustment::AutoObject(_, ref bounds, _, _) => {
+                adjustment::AutoObject(_, ref bounds, ..) => {
                     // Determine if we are casting `expr` to a trait
                     // instance. If so, we have to be sure that the type
                     // of the source obeys the new region bound.
@@ -643,7 +643,7 @@ impl<'a, 'gcx, 'tcx, 'v> Visitor<'v> for RegionCtxt<'a, 'gcx, 'tcx> {
                 intravisit::walk_expr(self, expr);
             }
 
-            hir::ExprMethodCall(_, _, ref args) => {
+            hir::ExprMethodCall(.., ref args) => {
                 self.constrain_call(expr, Some(&args[0]),
                                     args[1..].iter().map(|e| &**e), false);
 
@@ -758,7 +758,7 @@ impl<'a, 'gcx, 'tcx, 'v> Visitor<'v> for RegionCtxt<'a, 'gcx, 'tcx> {
                 intravisit::walk_expr(self, expr);
             }
 
-            hir::ExprClosure(_, _, ref body, _) => {
+            hir::ExprClosure(.., ref body, _) => {
                 self.check_expr_fn_block(expr, &body);
             }
 
@@ -1156,7 +1156,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
     let _ = mc.cat_pattern(discr_cmt, root_pat, |_, sub_cmt, sub_pat| {
                 match sub_pat.node {
                     // `ref x` pattern
-                    PatKind::Binding(hir::BindByRef(mutbl), _, _) => {
+                    PatKind::Binding(hir::BindByRef(mutbl), ..) => {
                         self.link_region_from_node_type(sub_pat.span, sub_pat.id,
                                                         mutbl, sub_cmt);
                     }
@@ -1269,7 +1269,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
                     borrow_kind = borrow_kind;
                 }
 
-                Categorization::Deref(_, _, mc::UnsafePtr(..)) |
+                Categorization::Deref(.., mc::UnsafePtr(..)) |
                 Categorization::StaticItem |
                 Categorization::Upvar(..) |
                 Categorization::Local(..) |
diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs
index a85e295784e9..f4a0df4611d3 100644
--- a/src/librustc_typeck/check/upvar.rs
+++ b/src/librustc_typeck/check/upvar.rs
@@ -283,8 +283,8 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> {
         debug!("adjust_upvar_borrow_kind_for_consume: guarantor={:?}",
                guarantor);
         match guarantor.cat {
-            Categorization::Deref(_, _, mc::BorrowedPtr(..)) |
-            Categorization::Deref(_, _, mc::Implicit(..)) => {
+            Categorization::Deref(.., mc::BorrowedPtr(..)) |
+            Categorization::Deref(.., mc::Implicit(..)) => {
                 match cmt.note {
                     mc::NoteUpvarRef(upvar_id) => {
                         debug!("adjust_upvar_borrow_kind_for_consume: \
@@ -344,7 +344,7 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> {
                 }
             }
 
-            Categorization::Deref(_, _, mc::UnsafePtr(..)) |
+            Categorization::Deref(.., mc::UnsafePtr(..)) |
             Categorization::StaticItem |
             Categorization::Rvalue(_) |
             Categorization::Local(_) |
@@ -376,7 +376,7 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> {
                 }
             }
 
-            Categorization::Deref(_, _, mc::UnsafePtr(..)) |
+            Categorization::Deref(.., mc::UnsafePtr(..)) |
             Categorization::StaticItem |
             Categorization::Rvalue(_) |
             Categorization::Local(_) |
diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs
index 8eb7d3456876..6e87c29c4b36 100644
--- a/src/librustc_typeck/check/wfcheck.rs
+++ b/src/librustc_typeck/check/wfcheck.rs
@@ -112,7 +112,7 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
                           ref trait_ref, ref self_ty, _) => {
                 self.check_impl(item, self_ty, trait_ref);
             }
-            hir::ItemImpl(_, hir::ImplPolarity::Negative, _, Some(_), _, _) => {
+            hir::ItemImpl(_, hir::ImplPolarity::Negative, _, Some(_), ..) => {
                 // FIXME(#27579) what amount of WF checking do we need for neg impls?
 
                 let trait_ref = ccx.tcx.impl_trait_ref(ccx.tcx.map.local_def_id(item.id)).unwrap();
@@ -286,7 +286,7 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
             let type_scheme = fcx.tcx.lookup_item_type(fcx.tcx.map.local_def_id(item.id));
             let item_ty = fcx.instantiate_type_scheme(item.span, free_substs, &type_scheme.ty);
             let bare_fn_ty = match item_ty.sty {
-                ty::TyFnDef(_, _, ref bare_fn_ty) => bare_fn_ty,
+                ty::TyFnDef(.., ref bare_fn_ty) => bare_fn_ty,
                 _ => {
                     span_bug!(item.span, "Fn item without fn type");
                 }
diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs
index 3bd0e890bb81..4be032c6f7f0 100644
--- a/src/librustc_typeck/check/writeback.rs
+++ b/src/librustc_typeck/check/writeback.rs
@@ -201,7 +201,7 @@ impl<'cx, 'gcx, 'tcx, 'v> Visitor<'v> for WritebackCx<'cx, 'gcx, 'tcx> {
         self.visit_method_map_entry(ResolvingExpr(e.span),
                                     MethodCall::expr(e.id));
 
-        if let hir::ExprClosure(_, ref decl, _, _) = e.node {
+        if let hir::ExprClosure(_, ref decl, ..) = e.node {
             for input in &decl.inputs {
                 self.visit_node_id(ResolvingExpr(e.span), input.id);
             }
@@ -323,7 +323,7 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
 
                     // Free regions that come from early-bound regions are valid.
                     ty::ReFree(ty::FreeRegion {
-                        bound_region: ty::BoundRegion::BrNamed(def_id, _, _), ..
+                        bound_region: ty::BoundRegion::BrNamed(def_id, ..), ..
                     }) if self.free_to_bound_regions.contains_key(&def_id) => {
                         self.free_to_bound_regions[&def_id]
                     }
diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs
index 70682bb8c8f3..d2b7f07b9ce6 100644
--- a/src/librustc_typeck/coherence/mod.rs
+++ b/src/librustc_typeck/coherence/mod.rs
@@ -86,7 +86,7 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> {
             TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) |
             TyStr | TyArray(..) | TySlice(..) | TyFnDef(..) | TyFnPtr(_) |
             TyTuple(..) | TyParam(..) | TyError | TyNever |
-            TyRawPtr(_) | TyRef(_, _) | TyProjection(..) => {
+            TyRawPtr(_) | TyRef(..) | TyProjection(..) => {
                 None
             }
 
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index a012fd418cac..fcc0b09e31ac 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -740,7 +740,7 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
             tcx.impl_trait_refs.borrow_mut().insert(ccx.tcx.map.local_def_id(it.id),
                                                     Some(trait_ref));
         }
-        hir::ItemImpl(_, _,
+        hir::ItemImpl(..,
                       ref generics,
                       ref opt_trait_ref,
                       ref selfty,
@@ -1456,7 +1456,7 @@ fn generics_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                         generics
                     }
 
-                    ItemTrait(_, ref generics, _, _) => {
+                    ItemTrait(_, ref generics, ..) => {
                         // Add in the self type parameter.
                         //
                         // Something of a hack: use the node id for the trait, also as
@@ -1566,7 +1566,7 @@ fn type_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
         let ty = match ccx.tcx.map.get(node_id) {
             NodeItem(item) => {
                 match item.node {
-                    ItemStatic(ref t, _, _) | ItemConst(ref t, _) => {
+                    ItemStatic(ref t, ..) | ItemConst(ref t, _) => {
                         ccx.icx(&()).to_ty(&ElidableRscope::new(ty::ReStatic), &t)
                     }
                     ItemFn(ref decl, unsafety, _, abi, ref generics, _) => {
diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs
index 24eb29f45a5e..1e38f464651b 100644
--- a/src/librustc_typeck/variance/constraints.rs
+++ b/src/librustc_typeck/variance/constraints.rs
@@ -415,7 +415,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
                 }
             }
 
-            ty::TyFnDef(_, _, &ty::BareFnTy { ref sig, .. }) |
+            ty::TyFnDef(.., &ty::BareFnTy { ref sig, .. }) |
             ty::TyFnPtr(&ty::BareFnTy { ref sig, .. }) => {
                 self.add_constraints_from_sig(generics, sig, variance);
             }
diff --git a/src/librustc_typeck/variance/terms.rs b/src/librustc_typeck/variance/terms.rs
index 1238f7cbcb33..577a47a35e12 100644
--- a/src/librustc_typeck/variance/terms.rs
+++ b/src/librustc_typeck/variance/terms.rs
@@ -238,7 +238,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for TermsContext<'a, 'tcx> {
             hir::ItemUnion(_, ref generics) => {
                 self.add_inferreds_for_item(item.id, false, generics);
             }
-            hir::ItemTrait(_, ref generics, _, _) => {
+            hir::ItemTrait(_, ref generics, ..) => {
                 // Note: all inputs for traits are ultimately
                 // constrained to be invariant. See `visit_item` in
                 // the impl for `ConstraintContext` in `constraints.rs`.
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index b7e371e23f32..18c12f98fb42 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -180,7 +180,7 @@ fn build_external_function<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx
                                      did: DefId) -> clean::Function {
     let t = tcx.lookup_item_type(did);
     let (decl, style, abi) = match t.ty.sty {
-        ty::TyFnDef(_, _, ref f) => ((did, &f.sig).clean(cx), f.unsafety, f.abi),
+        ty::TyFnDef(.., ref f) => ((did, &f.sig).clean(cx), f.unsafety, f.abi),
         _ => panic!("bad function"),
     };
 
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index f8ec5a55e7d4..4bab79ea8a99 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -642,7 +642,7 @@ fn external_path_params(cx: &DocContext, trait_did: Option, has_self: boo
                 output: output
             }
         },
-        (_, _) => {
+        (..) => {
             PathParameters::AngleBracketed {
                 lifetimes: lifetimes,
                 types: types.clean(cx),
@@ -717,7 +717,7 @@ impl<'tcx> Clean for ty::TraitRef<'tcx> {
             if let ty::TyTuple(ts) = ty_s.sty {
                 for &ty_s in ts {
                     if let ty::TyRef(ref reg, _) = ty_s.sty {
-                        if let &ty::Region::ReLateBound(_, _) = *reg {
+                        if let &ty::Region::ReLateBound(..) = *reg {
                             debug!("  hit an ReLateBound {:?}", reg);
                             if let Some(lt) = reg.clean(cx) {
                                 late_bounds.push(lt);
@@ -1794,7 +1794,7 @@ impl<'tcx> Clean for ty::Ty<'tcx> {
                 mutability: mt.mutbl.clean(cx),
                 type_: box mt.ty.clean(cx),
             },
-            ty::TyFnDef(_, _, ref fty) |
+            ty::TyFnDef(.., ref fty) |
             ty::TyFnPtr(ref fty) => BareFunction(box BareFunctionDecl {
                 unsafety: fty.unsafety,
                 generics: Generics {
@@ -2699,7 +2699,7 @@ fn name_from_pat(p: &hir::Pat) -> String {
     match p.node {
         PatKind::Wild => "_".to_string(),
         PatKind::Binding(_, ref p, _) => p.node.to_string(),
-        PatKind::TupleStruct(ref p, _, _) | PatKind::Path(None, ref p) => path_to_string(p),
+        PatKind::TupleStruct(ref p, ..) | PatKind::Path(None, ref p) => path_to_string(p),
         PatKind::Path(..) => panic!("tried to get argument name from qualified PatKind::Path, \
                                      which is not allowed in function arguments"),
         PatKind::Struct(ref name, ref fields, etc) => {
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index 6f66ce88df7a..61b80be96998 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -1891,7 +1891,7 @@ fn short_stability(item: &clean::Item, cx: &Context, show_reason: bool) -> Vec 0 =>
                         format!(" (#{})", Escape(&tracker_url), issue_no,
                                 issue_no),
-                    (true, _, _) =>
+                    (true, ..) =>
                         format!(" ({})", Escape(&stab.feature)),
                     _ => String::new(),
                 }
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index 0e685f063bd7..cc5cdf9f4e74 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -20,6 +20,7 @@
 
 #![feature(box_patterns)]
 #![feature(box_syntax)]
+#![feature(dotdot_in_tuple_patterns)]
 #![feature(libc)]
 #![feature(rustc_private)]
 #![feature(set_stdio)]
@@ -420,7 +421,7 @@ fn rust_input(cratefile: &str, externs: Externs, matches: &getopts::Matches) ->
     let mut pm = plugins::PluginManager::new(PathBuf::from(path));
     for pass in &passes {
         let plugin = match PASSES.iter()
-                                 .position(|&(p, _, _)| {
+                                 .position(|&(p, ..)| {
                                      p == *pass
                                  }) {
             Some(i) => PASSES[i].1,
diff --git a/src/libserialize/hex.rs b/src/libserialize/hex.rs
index 31b71dbc80b6..b5b344e8d5f2 100644
--- a/src/libserialize/hex.rs
+++ b/src/libserialize/hex.rs
@@ -82,7 +82,7 @@ impl fmt::Display for FromHexError {
 impl error::Error for FromHexError {
     fn description(&self) -> &str {
         match *self {
-            InvalidHexCharacter(_, _) => "invalid character",
+            InvalidHexCharacter(..) => "invalid character",
             InvalidHexLength => "invalid length",
         }
     }
diff --git a/src/libstd/path.rs b/src/libstd/path.rs
index 9a5b1da0f08f..0a9c77f25384 100644
--- a/src/libstd/path.rs
+++ b/src/libstd/path.rs
@@ -332,7 +332,7 @@ impl<'a> Prefix<'a> {
     pub fn is_verbatim(&self) -> bool {
         use self::Prefix::*;
         match *self {
-            Verbatim(_) | VerbatimDisk(_) | VerbatimUNC(_, _) => true,
+            Verbatim(_) | VerbatimDisk(_) | VerbatimUNC(..) => true,
             _ => false,
         }
     }
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index bbd334514458..105f911dd575 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -561,7 +561,7 @@ impl Pat {
             }
             PatKind::Wild |
             PatKind::Lit(_) |
-            PatKind::Range(_, _) |
+            PatKind::Range(..) |
             PatKind::Ident(..) |
             PatKind::Path(..) |
             PatKind::Mac(_) => {
diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs
index 7db03e9a8634..b0696a986e3c 100644
--- a/src/libsyntax/ext/tt/macro_parser.rs
+++ b/src/libsyntax/ext/tt/macro_parser.rs
@@ -156,7 +156,7 @@ pub fn count_names(ms: &[TokenTree]) -> usize {
             TokenTree::Token(_, MatchNt(..)) => {
                 1
             }
-            TokenTree::Token(_, _) => 0,
+            TokenTree::Token(..) => 0,
         }
     })
 }
@@ -231,7 +231,7 @@ pub fn nameize(p_s: &ParseSess, ms: &[TokenTree], res: &[Rc])
             TokenTree::Token(sp, SubstNt(..)) => {
                 return Err((sp, "missing fragment specifier".to_string()))
             }
-            TokenTree::Token(_, _) => (),
+            TokenTree::Token(..) => (),
         }
 
         Ok(())
diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs
index dc0fb02ea45d..ff01d3758154 100644
--- a/src/libsyntax/parse/token.rs
+++ b/src/libsyntax/parse/token.rs
@@ -180,7 +180,7 @@ impl Token {
             Ident(..)                   => true,
             Underscore                  => true,
             Tilde                       => true,
-            Literal(_, _)               => true,
+            Literal(..)                 => true,
             Not                         => true,
             BinOp(Minus)                => true,
             BinOp(Star)                 => true,
@@ -202,8 +202,8 @@ impl Token {
     /// Returns `true` if the token is any literal
     pub fn is_lit(&self) -> bool {
         match *self {
-            Literal(_, _) => true,
-            _             => false,
+            Literal(..) => true,
+            _           => false,
         }
     }
 
diff --git a/src/libsyntax_ext/asm.rs b/src/libsyntax_ext/asm.rs
index 6f368e1bc6f0..77425b809de1 100644
--- a/src/libsyntax_ext/asm.rs
+++ b/src/libsyntax_ext/asm.rs
@@ -233,7 +233,7 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt,
                     p.bump();
                     state = st;
                 }
-                (&token::Eof, _, _) => break 'statement,
+                (&token::Eof, ..) => break 'statement,
                 _ => break,
             }
         }
diff --git a/src/libsyntax_ext/deriving/debug.rs b/src/libsyntax_ext/deriving/debug.rs
index b974699003b9..f367fed9cc2c 100644
--- a/src/libsyntax_ext/deriving/debug.rs
+++ b/src/libsyntax_ext/deriving/debug.rs
@@ -78,7 +78,7 @@ fn show_substructure(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P {
+        EnumMatching(.., ref fields) => {
             let mut stmts = vec![];
             if !is_struct {
                 // tuple struct/"normal" variant
diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs
index b37d53329839..600f5d335c47 100644
--- a/src/libsyntax_ext/deriving/generic/mod.rs
+++ b/src/libsyntax_ext/deriving/generic/mod.rs
@@ -976,7 +976,7 @@ impl<'a> MethodDef<'a> {
                         other: other_fields.iter_mut()
                             .map(|l| {
                                 match l.next().unwrap() {
-                                    (_, _, ex, _) => ex,
+                                    (.., ex, _) => ex,
                                 }
                             })
                             .collect(),
@@ -1527,7 +1527,7 @@ impl<'a> TraitDef<'a> {
             VariantData::Struct(..) => {
                 let field_pats = subpats.into_iter()
                     .zip(&ident_exprs)
-                    .map(|(pat, &(sp, ident, _, _))| {
+                    .map(|(pat, &(sp, ident, ..))| {
                         if ident.is_none() {
                             cx.span_bug(sp, "a braced struct with unnamed fields in `derive`");
                         }
@@ -1583,7 +1583,7 @@ pub fn cs_fold(use_foldl: bool,
     where F: FnMut(&mut ExtCtxt, Span, P, P, &[P]) -> P
 {
     match *substructure.fields {
-        EnumMatching(_, _, ref all_fields) |
+        EnumMatching(.., ref all_fields) |
         Struct(_, ref all_fields) => {
             if use_foldl {
                 all_fields.iter().fold(base, |old, field| {
@@ -1623,7 +1623,7 @@ pub fn cs_same_method(f: F,
     where F: FnOnce(&mut ExtCtxt, Span, Vec>) -> P
 {
     match *substructure.fields {
-        EnumMatching(_, _, ref all_fields) |
+        EnumMatching(.., ref all_fields) |
         Struct(_, ref all_fields) => {
             // call self_n.method(other_1_n, other_2_n, ...)
             let called = all_fields.iter()
diff --git a/src/libsyntax_ext/deriving/hash.rs b/src/libsyntax_ext/deriving/hash.rs
index 0941ebca868e..97d7f2ce8003 100644
--- a/src/libsyntax_ext/deriving/hash.rs
+++ b/src/libsyntax_ext/deriving/hash.rs
@@ -82,7 +82,7 @@ fn hash_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure)
 
     let fields = match *substr.fields {
         Struct(_, ref fs) => fs,
-        EnumMatching(_, _, ref fs) => {
+        EnumMatching(.., ref fs) => {
             let variant_value = deriving::call_intrinsic(cx,
                                                          trait_span,
                                                          "discriminant_value",
diff --git a/src/libsyntax_ext/lib.rs b/src/libsyntax_ext/lib.rs
index 4bae9ec5a1a1..2065d92fd6ed 100644
--- a/src/libsyntax_ext/lib.rs
+++ b/src/libsyntax_ext/lib.rs
@@ -19,6 +19,7 @@
        html_root_url = "https://doc.rust-lang.org/nightly/")]
 #![cfg_attr(not(stage0), deny(warnings))]
 
+#![feature(dotdot_in_tuple_patterns)]
 #![feature(rustc_macro_lib)]
 #![feature(rustc_macro_internals)]
 #![feature(rustc_private)]
diff --git a/src/libterm/terminfo/parm.rs b/src/libterm/terminfo/parm.rs
index fbc6bfb6c8d9..bd5ab92e8b07 100644
--- a/src/libterm/terminfo/parm.rs
+++ b/src/libterm/terminfo/parm.rs
@@ -199,7 +199,7 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables) -> Result {
+                            _ => {
                                 return Err("first two params not numbers with %i".to_string())
                             }
                         }
diff --git a/src/test/run-make/save-analysis/foo.rs b/src/test/run-make/save-analysis/foo.rs
index 7a1c200ba20e..3f36ebe64923 100644
--- a/src/test/run-make/save-analysis/foo.rs
+++ b/src/test/run-make/save-analysis/foo.rs
@@ -10,9 +10,9 @@
 
 #![ crate_name = "test" ]
 #![feature(box_syntax)]
+#![feature(dotdot_in_tuple_patterns)]
 #![feature(rustc_private)]
 
-
 extern crate graphviz;
 // A simple rust project
 
@@ -206,7 +206,7 @@ fn matchSomeEnum(val: SomeEnum) {
     match val {
         SomeEnum::Ints(int1, int2) => { println(&(int1+int2).to_string()); }
         SomeEnum::Floats(float1, float2) => { println(&(float2*float1).to_string()); }
-        SomeEnum::Strings(_, _, s3) => { println(s3); }
+        SomeEnum::Strings(.., s3) => { println(s3); }
         SomeEnum::MyTypes(mt1, mt2) => { println(&(mt1.field1 - mt2.field1).to_string()); }
     }
 }
@@ -225,7 +225,7 @@ fn matchSomeStructEnum2(se: SomeStructEnum) {
     match se {
         EnumStruct{a: ref aaa, ..} => println(&aaa.to_string()),
         EnumStruct2{f1, f2: f2} => println(&f1.field1.to_string()),
-        EnumStruct3{f1, f3: SomeEnum::Ints(_, _), f2} => println(&f1.field1.to_string()),
+        EnumStruct3{f1, f3: SomeEnum::Ints(..), f2} => println(&f1.field1.to_string()),
         _ => {},
     }
 }
@@ -435,4 +435,4 @@ fn test_format_args() {
     print!("Hello {0}", name);
     print!("{0} + {} = {}", x, y);
     print!("x is {}, y is {1}, name is {n}", x, y, n = name);
-}
\ No newline at end of file
+}
diff --git a/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin_attr.rs b/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin_attr.rs
index c6174745bfc0..5df95ba5facb 100644
--- a/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin_attr.rs
+++ b/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin_attr.rs
@@ -12,6 +12,7 @@
 
 #![feature(plugin_registrar)]
 #![feature(box_syntax)]
+#![feature(dotdot_in_tuple_patterns)]
 #![feature(rustc_private)]
 
 extern crate syntax;
@@ -75,7 +76,7 @@ fn expand(cx: &mut ExtCtxt,
 fn totalsum_substructure(cx: &mut ExtCtxt, trait_span: Span,
                          substr: &Substructure) -> P {
     let fields = match *substr.fields {
-        Struct(_, ref fs) | EnumMatching(_, _, ref fs) => fs,
+        Struct(_, ref fs) | EnumMatching(.., ref fs) => fs,
         _ => cx.span_bug(trait_span, "impossible substructure")
     };
 

From 8d3fd03855c597ebaf81d727bae76217237f0a3f Mon Sep 17 00:00:00 2001
From: Andrew Paseltiner 
Date: Sun, 4 Sep 2016 10:16:25 -0400
Subject: [PATCH 159/443] Clean up thread-local storage docs

`std` no longer contains an implementation of scoped TLS.
---
 src/libstd/thread/mod.rs | 35 +++++++++++++++--------------------
 1 file changed, 15 insertions(+), 20 deletions(-)

diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs
index e3f3f9dd6de1..d8e021bb04ff 100644
--- a/src/libstd/thread/mod.rs
+++ b/src/libstd/thread/mod.rs
@@ -135,29 +135,24 @@
 //!
 //! ## Thread-local storage
 //!
-//! This module also provides an implementation of thread local storage for Rust
-//! programs. Thread local storage is a method of storing data into a global
-//! variable which each thread in the program will have its own copy of.
+//! This module also provides an implementation of thread-local storage for Rust
+//! programs. Thread-local storage is a method of storing data into a global
+//! variable that each thread in the program will have its own copy of.
 //! Threads do not share this data, so accesses do not need to be synchronized.
 //!
-//! At a high level, this module provides two variants of storage:
-//!
-//! * Owned thread-local storage. This is a type of thread local key which
-//!   owns the value that it contains, and will destroy the value when the
-//!   thread exits. This variant is created with the `thread_local!` macro and
-//!   can contain any value which is `'static` (no borrowed pointers).
-//!
-//! * Scoped thread-local storage. This type of key is used to store a reference
-//!   to a value into local storage temporarily for the scope of a function
-//!   call. There are no restrictions on what types of values can be placed
-//!   into this key.
-//!
-//! Both forms of thread local storage provide an accessor function, `with`,
-//! which will yield a shared reference to the value to the specified
-//! closure. Thread-local keys only allow shared access to values as there is no
-//! way to guarantee uniqueness if a mutable borrow was allowed. Most values
+//! A thread-local key owns the value it contains and will destroy the value when the
+//! thread exits. It is created with the [`thread_local!`] macro and can contain any
+//! value that is `'static` (no borrowed pointers). It provides an accessor function,
+//! [`with`], that yields a shared reference to the value to the specified
+//! closure. Thread-local keys allow only shared access to values, as there would be no
+//! way to guarantee uniqueness if mutable borrows were allowed. Most values
 //! will want to make use of some form of **interior mutability** through the
-//! `Cell` or `RefCell` types.
+//! [`Cell`] or [`RefCell`] types.
+//!
+//! [`Cell`]: ../cell/struct.Cell.html
+//! [`RefCell`]: ../cell/struct.RefCell.html
+//! [`thread_local!`]: ../macro.thread_local!.html
+//! [`with`]: struct.LocalKey.html#method.with
 
 #![stable(feature = "rust1", since = "1.0.0")]
 

From 1aa777b51f03593eb557d4e550830f8406ee37c3 Mon Sep 17 00:00:00 2001
From: Cobrand 
Date: Sun, 4 Sep 2016 21:14:41 +0200
Subject: [PATCH 160/443] Updated E0559 to new format

Refactored a method that printed one suggested field name,
into a method that returns an `Option` of a suggestion

Updated test cases accordingly
---
 src/librustc_typeck/check/mod.rs              | 28 +++++++++++--------
 src/test/compile-fail/E0559.rs                |  4 ++-
 .../struct-fields-hints-no-dupe.rs            |  5 ++--
 src/test/compile-fail/struct-fields-hints.rs  |  5 ++--
 .../compile-fail/suggest-private-fields.rs    | 20 +++++++------
 .../compile-fail/union/union-suggest-field.rs |  5 ++--
 6 files changed, 40 insertions(+), 27 deletions(-)

diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index f4fea5542b3d..8518689fcb40 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -118,7 +118,6 @@ use syntax::parse::token::{self, InternedString, keywords};
 use syntax::ptr::P;
 use syntax::util::lev_distance::find_best_match_for_name;
 use syntax_pos::{self, Span};
-use errors::DiagnosticBuilder;
 
 use rustc::hir::intravisit::{self, Visitor};
 use rustc::hir::{self, PatKind};
@@ -2996,7 +2995,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             }, expr_t);
             match expr_t.sty {
                 ty::TyStruct(def, _) | ty::TyUnion(def, _) => {
-                    Self::suggest_field_names(&mut err, def.struct_variant(), field, vec![]);
+                    if let Some(suggested_field_name) =
+                        Self::suggest_field_name(def.struct_variant(), field, vec![]) {
+                        err.span_help(field.span,
+                                      &format!("did you mean `{}`?", suggested_field_name));
+                    };
                 }
                 ty::TyRawPtr(..) => {
                     err.note(&format!("`{0}` is a native pointer; perhaps you need to deref with \
@@ -3009,11 +3012,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         }
     }
 
-    // displays hints about the closest matches in field names
-    fn suggest_field_names(err: &mut DiagnosticBuilder,
-                           variant: ty::VariantDef<'tcx>,
-                           field: &Spanned,
-                           skip : Vec) {
+    // Return an hint about the closest match in field names
+    fn suggest_field_name(variant: ty::VariantDef<'tcx>,
+                          field: &Spanned,
+                          skip : Vec)
+                          -> Option {
         let name = field.node.as_str();
         let names = variant.fields.iter().filter_map(|field| {
             // ignore already set fields and private fields from non-local crates
@@ -3026,10 +3029,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         });
 
         // only find fits with at least one matching letter
-        if let Some(name) = find_best_match_for_name(names, &name, Some(name.len())) {
-            err.span_help(field.span,
-                          &format!("did you mean `{}`?", name));
-        }
+        find_best_match_for_name(names, &name, Some(name.len()))
     }
 
     // Check tuple index expressions
@@ -3125,7 +3125,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             ty);
         // prevent all specified fields from being suggested
         let skip_fields = skip_fields.iter().map(|ref x| x.name.node.as_str());
-        Self::suggest_field_names(&mut err, variant, &field.name, skip_fields.collect());
+        if let Some(field_name) = Self::suggest_field_name(variant,
+                                                           &field.name,
+                                                           skip_fields.collect()) {
+            err.span_label(field.name.span,&format!("did you mean `{}`?",field_name));
+        };
         err.emit();
     }
 
diff --git a/src/test/compile-fail/E0559.rs b/src/test/compile-fail/E0559.rs
index 80eeb203a850..aeeeae422281 100644
--- a/src/test/compile-fail/E0559.rs
+++ b/src/test/compile-fail/E0559.rs
@@ -13,5 +13,7 @@ enum Field {
 }
 
 fn main() {
-    let s = Field::Fool { joke: 0 }; //~ ERROR E0559
+    let s = Field::Fool { joke: 0 };
+    //~^ ERROR E0559
+    //~| NOTE did you mean `x`?
 }
diff --git a/src/test/compile-fail/struct-fields-hints-no-dupe.rs b/src/test/compile-fail/struct-fields-hints-no-dupe.rs
index 5f1f8ca856f9..f25f01af33fd 100644
--- a/src/test/compile-fail/struct-fields-hints-no-dupe.rs
+++ b/src/test/compile-fail/struct-fields-hints-no-dupe.rs
@@ -17,8 +17,9 @@ struct A {
 fn main() {
     let a = A {
         foo : 5,
-        bar : 42,//~ ERROR struct `A` has no field named `bar`
-        //~^ HELP did you mean `barr`?
+        bar : 42,
+        //~^ ERROR struct `A` has no field named `bar`
+        //~| NOTE did you mean `barr`?
         car : 9,
     };
 }
diff --git a/src/test/compile-fail/struct-fields-hints.rs b/src/test/compile-fail/struct-fields-hints.rs
index 4ba1fd2f7bb3..62ec6e6b0d24 100644
--- a/src/test/compile-fail/struct-fields-hints.rs
+++ b/src/test/compile-fail/struct-fields-hints.rs
@@ -17,7 +17,8 @@ struct A {
 fn main() {
     let a = A {
         foo : 5,
-        bar : 42,//~ ERROR struct `A` has no field named `bar`
-        //~^ HELP did you mean `car`?
+        bar : 42,
+        //~^ ERROR struct `A` has no field named `bar`
+        //~| NOTE did you mean `car`?
     };
 }
diff --git a/src/test/compile-fail/suggest-private-fields.rs b/src/test/compile-fail/suggest-private-fields.rs
index 41bd00a518c5..906bfc78498e 100644
--- a/src/test/compile-fail/suggest-private-fields.rs
+++ b/src/test/compile-fail/suggest-private-fields.rs
@@ -22,16 +22,20 @@ struct A {
 fn main () {
     // external crate struct
     let k = B {
-        aa: 20, //~ ERROR struct `xc::B` has no field named `aa`
-        //~^ HELP did you mean `a`?
-        bb: 20, //~ ERROR struct `xc::B` has no field named `bb`
-        //~^ HELP did you mean `a`?
+        aa: 20,
+        //~^ ERROR struct `xc::B` has no field named `aa`
+        //~| NOTE did you mean `a`?
+        bb: 20,
+        //~^ ERROR struct `xc::B` has no field named `bb`
+        //~| NOTE did you mean `a`?
     };
     // local crate struct
     let l = A {
-        aa: 20, //~ ERROR struct `A` has no field named `aa`
-        //~^ HELP did you mean `a`?
-        bb: 20, //~ ERROR struct `A` has no field named `bb`
-        //~^ HELP did you mean `b`?
+        aa: 20,
+        //~^ ERROR struct `A` has no field named `aa`
+        //~| NOTE did you mean `a`?
+        bb: 20,
+        //~^ ERROR struct `A` has no field named `bb`
+        //~| NOTE did you mean `b`?
     };
 }
diff --git a/src/test/compile-fail/union/union-suggest-field.rs b/src/test/compile-fail/union/union-suggest-field.rs
index b05e9b6e2733..92811b6b5be1 100644
--- a/src/test/compile-fail/union/union-suggest-field.rs
+++ b/src/test/compile-fail/union/union-suggest-field.rs
@@ -19,8 +19,9 @@ impl U {
 }
 
 fn main() {
-    let u = U { principle: 0 }; //~ ERROR union `U` has no field named `principle`
-                                //~^ HELP did you mean `principal`?
+    let u = U { principle: 0 };
+    //~^ ERROR union `U` has no field named `principle`
+    //~| NOTE did you mean `principal`?
     let w = u.principial; //~ ERROR attempted access of field `principial` on type `U`
                           //~^ HELP did you mean `principal`?
 

From b9a8c1a06300c4d042b5455d83cacd689bad6283 Mon Sep 17 00:00:00 2001
From: Matt Ickstadt 
Date: Thu, 1 Sep 2016 13:52:33 -0500
Subject: [PATCH 161/443] Fix incorrect LLVM Linkage enum

The `Linkage` enum in librustc_llvm got out of sync with the version in LLVM and it caused two variants of the #[linkage=""] attribute to break.

This adds the functions `LLVMRustGetLinkage` and `LLVMRustSetLinkage` which convert between the Rust Linkage enum and the LLVM one, which should stop this from breaking every time LLVM changes it.

Fixes #33992
---
 src/librustc_llvm/ffi.rs            | 28 ++++------
 src/librustc_trans/base.rs          | 64 +++++++++++------------
 src/librustc_trans/callee.rs        |  2 +-
 src/librustc_trans/closure.rs       |  4 +-
 src/librustc_trans/common.rs        |  2 +-
 src/librustc_trans/consts.rs        |  8 +--
 src/librustc_trans/debuginfo/gdb.rs |  2 +-
 src/librustc_trans/declare.rs       |  2 +-
 src/librustc_trans/trans_item.rs    | 14 ++---
 src/rustllvm/RustWrapper.cpp        | 80 +++++++++++++++++++++++++++++
 src/test/run-pass/issue-33992.rs    | 40 +++++++++++++++
 11 files changed, 180 insertions(+), 66 deletions(-)
 create mode 100644 src/test/run-pass/issue-33992.rs

diff --git a/src/librustc_llvm/ffi.rs b/src/librustc_llvm/ffi.rs
index 92fe568a72c5..50c68d5e75ee 100644
--- a/src/librustc_llvm/ffi.rs
+++ b/src/librustc_llvm/ffi.rs
@@ -47,12 +47,7 @@ pub enum CallConv {
     X86_VectorCall = 80
 }
 
-/// LLVMLinkage
-///
-/// This enum omits the obsolete (and no-op) linkage types DLLImportLinkage,
-/// DLLExportLinkage, GhostLinkage and LinkOnceODRAutoHideLinkage.
-/// LinkerPrivateLinkage and LinkerPrivateWeakLinkage are not included either;
-/// they've been removed in upstream LLVM commit r203866.
+/// LLVMRustLinkage
 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
 #[repr(C)]
 pub enum Linkage {
@@ -60,13 +55,13 @@ pub enum Linkage {
     AvailableExternallyLinkage = 1,
     LinkOnceAnyLinkage = 2,
     LinkOnceODRLinkage = 3,
-    WeakAnyLinkage = 5,
-    WeakODRLinkage = 6,
-    AppendingLinkage = 7,
-    InternalLinkage = 8,
-    PrivateLinkage = 9,
-    ExternalWeakLinkage = 12,
-    CommonLinkage = 14,
+    WeakAnyLinkage = 4,
+    WeakODRLinkage = 5,
+    AppendingLinkage = 6,
+    InternalLinkage = 7,
+    PrivateLinkage = 8,
+    ExternalWeakLinkage = 9,
+    CommonLinkage = 10,
 }
 
 /// LLVMDiagnosticSeverity
@@ -253,8 +248,7 @@ pub enum FileType {
     ObjectFile,
 }
 
-/// Enum pinned in LLVMContext, used in
-/// LLVMSetMetadata so ABI-stable.
+/// LLVMMetadataType
 #[derive(Copy, Clone)]
 #[repr(C)]
 pub enum MetadataType {
@@ -821,8 +815,8 @@ extern {
     /* Operations on global variables, functions, and aliases (globals) */
     pub fn LLVMGetGlobalParent(Global: ValueRef) -> ModuleRef;
     pub fn LLVMIsDeclaration(Global: ValueRef) -> Bool;
-    pub fn LLVMGetLinkage(Global: ValueRef) -> c_uint;
-    pub fn LLVMSetLinkage(Global: ValueRef, Link: Linkage);
+    pub fn LLVMRustGetLinkage(Global: ValueRef) -> Linkage;
+    pub fn LLVMRustSetLinkage(Global: ValueRef, RustLinkage: Linkage);
     pub fn LLVMGetSection(Global: ValueRef) -> *const c_char;
     pub fn LLVMSetSection(Global: ValueRef, Section: *const c_char);
     pub fn LLVMGetVisibility(Global: ValueRef) -> c_uint;
diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs
index 99126095ede3..53d55f4a903d 100644
--- a/src/librustc_trans/base.rs
+++ b/src/librustc_trans/base.rs
@@ -1198,17 +1198,17 @@ pub fn llvm_linkage_by_name(name: &str) -> Option {
     // ghost, dllimport, dllexport and linkonce_odr_autohide are not supported
     // and don't have to be, LLVM treats them as no-ops.
     match name {
-        "appending" => Some(llvm::AppendingLinkage),
-        "available_externally" => Some(llvm::AvailableExternallyLinkage),
-        "common" => Some(llvm::CommonLinkage),
-        "extern_weak" => Some(llvm::ExternalWeakLinkage),
-        "external" => Some(llvm::ExternalLinkage),
-        "internal" => Some(llvm::InternalLinkage),
-        "linkonce" => Some(llvm::LinkOnceAnyLinkage),
-        "linkonce_odr" => Some(llvm::LinkOnceODRLinkage),
-        "private" => Some(llvm::PrivateLinkage),
-        "weak" => Some(llvm::WeakAnyLinkage),
-        "weak_odr" => Some(llvm::WeakODRLinkage),
+        "appending" => Some(llvm::Linkage::AppendingLinkage),
+        "available_externally" => Some(llvm::Linkage::AvailableExternallyLinkage),
+        "common" => Some(llvm::Linkage::CommonLinkage),
+        "extern_weak" => Some(llvm::Linkage::ExternalWeakLinkage),
+        "external" => Some(llvm::Linkage::ExternalLinkage),
+        "internal" => Some(llvm::Linkage::InternalLinkage),
+        "linkonce" => Some(llvm::Linkage::LinkOnceAnyLinkage),
+        "linkonce_odr" => Some(llvm::Linkage::LinkOnceODRLinkage),
+        "private" => Some(llvm::Linkage::PrivateLinkage),
+        "weak" => Some(llvm::Linkage::WeakAnyLinkage),
+        "weak_odr" => Some(llvm::Linkage::WeakODRLinkage),
         _ => None,
     }
 }
@@ -1401,10 +1401,10 @@ fn internalize_symbols<'a, 'tcx>(sess: &Session,
         // are referenced via a declaration in some other codegen unit.
         for ccx in ccxs.iter_need_trans() {
             for val in iter_globals(ccx.llmod()).chain(iter_functions(ccx.llmod())) {
-                let linkage = llvm::LLVMGetLinkage(val);
+                let linkage = llvm::LLVMRustGetLinkage(val);
                 // We only care about external declarations (not definitions)
                 // and available_externally definitions.
-                let is_available_externally = linkage == llvm::AvailableExternallyLinkage as c_uint;
+                let is_available_externally = linkage == llvm::Linkage::AvailableExternallyLinkage;
                 let is_decl = llvm::LLVMIsDeclaration(val) != 0;
 
                 if is_decl || is_available_externally {
@@ -1446,11 +1446,11 @@ fn internalize_symbols<'a, 'tcx>(sess: &Session,
         // then give it internal linkage.
         for ccx in ccxs.iter_need_trans() {
             for val in iter_globals(ccx.llmod()).chain(iter_functions(ccx.llmod())) {
-                let linkage = llvm::LLVMGetLinkage(val);
+                let linkage = llvm::LLVMRustGetLinkage(val);
 
-                let is_externally_visible = (linkage == llvm::ExternalLinkage as c_uint) ||
-                                            (linkage == llvm::LinkOnceODRLinkage as c_uint) ||
-                                            (linkage == llvm::WeakODRLinkage as c_uint);
+                let is_externally_visible = (linkage == llvm::Linkage::ExternalLinkage) ||
+                                            (linkage == llvm::Linkage::LinkOnceODRLinkage) ||
+                                            (linkage == llvm::Linkage::WeakODRLinkage);
                 let is_definition = llvm::LLVMIsDeclaration(val) == 0;
 
                 // If this is a definition (as opposed to just a declaration)
@@ -1465,7 +1465,7 @@ fn internalize_symbols<'a, 'tcx>(sess: &Session,
                     let has_fixed_linkage = linkage_fixed_explicitly.contains(&name_cow);
 
                     if !is_referenced_somewhere && !is_reachable && !has_fixed_linkage {
-                        llvm::LLVMSetLinkage(val, llvm::InternalLinkage);
+                        llvm::LLVMRustSetLinkage(val, llvm::Linkage::InternalLinkage);
                         llvm::LLVMSetDLLStorageClass(val,
                                                      llvm::DLLStorageClass::Default);
                         llvm::UnsetComdat(val);
@@ -1495,8 +1495,8 @@ fn create_imps(cx: &CrateContextList) {
         for ccx in cx.iter_need_trans() {
             let exported: Vec<_> = iter_globals(ccx.llmod())
                                        .filter(|&val| {
-                                           llvm::LLVMGetLinkage(val) ==
-                                           llvm::ExternalLinkage as c_uint &&
+                                           llvm::LLVMRustGetLinkage(val) ==
+                                           llvm::Linkage::ExternalLinkage &&
                                            llvm::LLVMIsDeclaration(val) == 0
                                        })
                                        .collect();
@@ -1512,7 +1512,7 @@ fn create_imps(cx: &CrateContextList) {
                                               imp_name.as_ptr() as *const _);
                 let init = llvm::LLVMConstBitCast(val, i8p_ty.to_ref());
                 llvm::LLVMSetInitializer(imp, init);
-                llvm::LLVMSetLinkage(imp, llvm::ExternalLinkage);
+                llvm::LLVMRustSetLinkage(imp, llvm::Linkage::ExternalLinkage);
             }
         }
     }
@@ -1937,17 +1937,17 @@ fn collect_and_partition_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a
                     output.push_str(&cgu_name[..]);
 
                     let linkage_abbrev = match linkage {
-                        llvm::ExternalLinkage => "External",
-                        llvm::AvailableExternallyLinkage => "Available",
-                        llvm::LinkOnceAnyLinkage => "OnceAny",
-                        llvm::LinkOnceODRLinkage => "OnceODR",
-                        llvm::WeakAnyLinkage => "WeakAny",
-                        llvm::WeakODRLinkage => "WeakODR",
-                        llvm::AppendingLinkage => "Appending",
-                        llvm::InternalLinkage => "Internal",
-                        llvm::PrivateLinkage => "Private",
-                        llvm::ExternalWeakLinkage => "ExternalWeak",
-                        llvm::CommonLinkage => "Common",
+                        llvm::Linkage::ExternalLinkage => "External",
+                        llvm::Linkage::AvailableExternallyLinkage => "Available",
+                        llvm::Linkage::LinkOnceAnyLinkage => "OnceAny",
+                        llvm::Linkage::LinkOnceODRLinkage => "OnceODR",
+                        llvm::Linkage::WeakAnyLinkage => "WeakAny",
+                        llvm::Linkage::WeakODRLinkage => "WeakODR",
+                        llvm::Linkage::AppendingLinkage => "Appending",
+                        llvm::Linkage::InternalLinkage => "Internal",
+                        llvm::Linkage::PrivateLinkage => "Private",
+                        llvm::Linkage::ExternalWeakLinkage => "ExternalWeak",
+                        llvm::Linkage::CommonLinkage => "Common",
                     };
 
                     output.push_str("[");
diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs
index 33cacbe194bb..51e79d1e4b33 100644
--- a/src/librustc_trans/callee.rs
+++ b/src/librustc_trans/callee.rs
@@ -472,7 +472,7 @@ fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
             // FIXME(eddyb) Doubt all extern fn should allow unwinding.
             attributes::unwind(llfn, true);
             unsafe {
-                llvm::LLVMSetLinkage(llfn, llvm::ExternalLinkage);
+                llvm::LLVMRustSetLinkage(llfn, llvm::Linkage::ExternalLinkage);
             }
         }
 
diff --git a/src/librustc_trans/closure.rs b/src/librustc_trans/closure.rs
index 842a8fddb83e..83882c27e8e7 100644
--- a/src/librustc_trans/closure.rs
+++ b/src/librustc_trans/closure.rs
@@ -110,10 +110,10 @@ pub fn trans_closure_body_via_mir<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
 
         unsafe {
             if ccx.sess().target.target.options.allows_weak_linkage {
-                llvm::LLVMSetLinkage(llfn, llvm::WeakODRLinkage);
+                llvm::LLVMRustSetLinkage(llfn, llvm::Linkage::WeakODRLinkage);
                 llvm::SetUniqueComdat(ccx.llmod(), llfn);
             } else {
-                llvm::LLVMSetLinkage(llfn, llvm::InternalLinkage);
+                llvm::LLVMRustSetLinkage(llfn, llvm::Linkage::InternalLinkage);
             }
         }
 
diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs
index 6ae6f8aead77..bd98eee8869b 100644
--- a/src/librustc_trans/common.rs
+++ b/src/librustc_trans/common.rs
@@ -817,7 +817,7 @@ pub fn C_cstr(cx: &CrateContext, s: InternedString, null_terminated: bool) -> Va
         });
         llvm::LLVMSetInitializer(g, sc);
         llvm::LLVMSetGlobalConstant(g, True);
-        llvm::LLVMSetLinkage(g, llvm::InternalLinkage);
+        llvm::LLVMRustSetLinkage(g, llvm::Linkage::InternalLinkage);
 
         cx.const_cstr_cache().borrow_mut().insert(s, g);
         g
diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs
index 2b6e2a23261b..15f7132e52d2 100644
--- a/src/librustc_trans/consts.rs
+++ b/src/librustc_trans/consts.rs
@@ -11,7 +11,7 @@
 
 use llvm;
 use llvm::{SetUnnamedAddr};
-use llvm::{InternalLinkage, ValueRef, True};
+use llvm::{ValueRef, True};
 use rustc_const_eval::ConstEvalErr;
 use rustc::hir::def_id::DefId;
 use rustc::hir::map as hir_map;
@@ -53,7 +53,7 @@ pub fn addr_of_mut(ccx: &CrateContext,
         });
         llvm::LLVMSetInitializer(gv, cv);
         llvm::LLVMSetAlignment(gv, align);
-        llvm::LLVMSetLinkage(gv, InternalLinkage);
+        llvm::LLVMRustSetLinkage(gv, llvm::Linkage::InternalLinkage);
         SetUnnamedAddr(gv, true);
         gv
     }
@@ -142,7 +142,7 @@ pub fn get_static(ccx: &CrateContext, def_id: DefId) -> ValueRef {
                     unsafe {
                         // Declare a symbol `foo` with the desired linkage.
                         let g1 = declare::declare_global(ccx, &sym, llty2);
-                        llvm::LLVMSetLinkage(g1, linkage);
+                        llvm::LLVMRustSetLinkage(g1, linkage);
 
                         // Declare an internal global `extern_with_linkage_foo` which
                         // is initialized with the address of `foo`.  If `foo` is
@@ -156,7 +156,7 @@ pub fn get_static(ccx: &CrateContext, def_id: DefId) -> ValueRef {
                             ccx.sess().span_fatal(span,
                                 &format!("symbol `{}` is already defined", &sym))
                         });
-                        llvm::LLVMSetLinkage(g2, llvm::InternalLinkage);
+                        llvm::LLVMRustSetLinkage(g2, llvm::Linkage::InternalLinkage);
                         llvm::LLVMSetInitializer(g2, g1);
                         g2
                     }
diff --git a/src/librustc_trans/debuginfo/gdb.rs b/src/librustc_trans/debuginfo/gdb.rs
index 0a8d490dcd2d..8f937d3fe25c 100644
--- a/src/librustc_trans/debuginfo/gdb.rs
+++ b/src/librustc_trans/debuginfo/gdb.rs
@@ -77,7 +77,7 @@ pub fn get_or_insert_gdb_debug_scripts_section_global(ccx: &CrateContext)
             llvm::LLVMSetInitializer(section_var, C_bytes(ccx, section_contents));
             llvm::LLVMSetGlobalConstant(section_var, llvm::True);
             llvm::LLVMSetUnnamedAddr(section_var, llvm::True);
-            llvm::LLVMSetLinkage(section_var, llvm::Linkage::LinkOnceODRLinkage);
+            llvm::LLVMRustSetLinkage(section_var, llvm::Linkage::LinkOnceODRLinkage);
             // This should make sure that the whole section is not larger than
             // the string it contains. Otherwise we get a warning from GDB.
             llvm::LLVMSetAlignment(section_var, 1);
diff --git a/src/librustc_trans/declare.rs b/src/librustc_trans/declare.rs
index 4d9ee187ac50..0c1156a98743 100644
--- a/src/librustc_trans/declare.rs
+++ b/src/librustc_trans/declare.rs
@@ -164,7 +164,7 @@ pub fn define_internal_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                                     name: &str,
                                     fn_type: ty::Ty<'tcx>) -> ValueRef {
     let llfn = define_fn(ccx, name, fn_type);
-    unsafe { llvm::LLVMSetLinkage(llfn, llvm::InternalLinkage) };
+    unsafe { llvm::LLVMRustSetLinkage(llfn, llvm::Linkage::InternalLinkage) };
     llfn
 }
 
diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs
index deef0b09a17b..9a55877a1345 100644
--- a/src/librustc_trans/trans_item.rs
+++ b/src/librustc_trans/trans_item.rs
@@ -160,7 +160,7 @@ impl<'a, 'tcx> TransItem<'tcx> {
                 &format!("symbol `{}` is already defined", symbol_name))
         });
 
-        unsafe { llvm::LLVMSetLinkage(g, linkage) };
+        unsafe { llvm::LLVMRustSetLinkage(g, linkage) };
 
         let instance = Instance::mono(ccx.shared(), def_id);
         ccx.instances().borrow_mut().insert(instance, g);
@@ -180,10 +180,10 @@ impl<'a, 'tcx> TransItem<'tcx> {
 
         let attrs = ccx.tcx().get_attrs(instance.def);
         let lldecl = declare::declare_fn(ccx, symbol_name, mono_ty);
-        unsafe { llvm::LLVMSetLinkage(lldecl, linkage) };
+        unsafe { llvm::LLVMRustSetLinkage(lldecl, linkage) };
         base::set_link_section(ccx, lldecl, &attrs);
-        if linkage == llvm::LinkOnceODRLinkage ||
-            linkage == llvm::WeakODRLinkage {
+        if linkage == llvm::Linkage::LinkOnceODRLinkage ||
+            linkage == llvm::Linkage::WeakODRLinkage {
             llvm::SetUniqueComdat(ccx.llmod(), lldecl);
         }
 
@@ -214,9 +214,9 @@ impl<'a, 'tcx> TransItem<'tcx> {
 
         assert!(declare::get_defined_value(ccx, symbol_name).is_none());
         let llfn = declare::declare_cfn(ccx, symbol_name, llfnty);
-        unsafe { llvm::LLVMSetLinkage(llfn, linkage) };
-        if linkage == llvm::LinkOnceODRLinkage ||
-           linkage == llvm::WeakODRLinkage {
+        unsafe { llvm::LLVMRustSetLinkage(llfn, linkage) };
+        if linkage == llvm::Linkage::LinkOnceODRLinkage ||
+           linkage == llvm::Linkage::WeakODRLinkage {
             llvm::SetUniqueComdat(ccx.llmod(), llfn);
         }
         attributes::set_frame_pointer_elimination(ccx, llfn);
diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp
index 82fb2b0918f7..124eb1eba4f7 100644
--- a/src/rustllvm/RustWrapper.cpp
+++ b/src/rustllvm/RustWrapper.cpp
@@ -1232,3 +1232,83 @@ extern "C" void LLVMRustUnsetComdat(LLVMValueRef V) {
     GlobalObject *GV = unwrap(V);
     GV->setComdat(nullptr);
 }
+
+enum class LLVMRustLinkage {
+    ExternalLinkage = 0,
+    AvailableExternallyLinkage = 1,
+    LinkOnceAnyLinkage = 2,
+    LinkOnceODRLinkage = 3,
+    WeakAnyLinkage = 4,
+    WeakODRLinkage = 5,
+    AppendingLinkage = 6,
+    InternalLinkage = 7,
+    PrivateLinkage = 8,
+    ExternalWeakLinkage = 9,
+    CommonLinkage = 10,
+};
+
+static LLVMRustLinkage to_rust(LLVMLinkage linkage) {
+    switch (linkage) {
+        case LLVMExternalLinkage:
+            return LLVMRustLinkage::ExternalLinkage;
+        case LLVMAvailableExternallyLinkage:
+            return LLVMRustLinkage::AvailableExternallyLinkage;
+        case LLVMLinkOnceAnyLinkage:
+            return LLVMRustLinkage::LinkOnceAnyLinkage;
+        case LLVMLinkOnceODRLinkage:
+            return LLVMRustLinkage::LinkOnceODRLinkage;
+        case LLVMWeakAnyLinkage:
+            return LLVMRustLinkage::WeakAnyLinkage;
+        case LLVMWeakODRLinkage:
+            return LLVMRustLinkage::WeakODRLinkage;
+        case LLVMAppendingLinkage:
+            return LLVMRustLinkage::AppendingLinkage;
+        case LLVMInternalLinkage:
+            return LLVMRustLinkage::InternalLinkage;
+        case LLVMPrivateLinkage:
+            return LLVMRustLinkage::PrivateLinkage;
+        case LLVMExternalWeakLinkage:
+            return LLVMRustLinkage::ExternalWeakLinkage;
+        case LLVMCommonLinkage:
+            return LLVMRustLinkage::CommonLinkage;
+        default:
+            llvm_unreachable("Invalid LLVMRustLinkage value!");
+    }
+}
+
+static LLVMLinkage from_rust(LLVMRustLinkage linkage) {
+    switch (linkage) {
+        case LLVMRustLinkage::ExternalLinkage:
+            return LLVMExternalLinkage;
+        case LLVMRustLinkage::AvailableExternallyLinkage:
+            return LLVMAvailableExternallyLinkage;
+        case LLVMRustLinkage::LinkOnceAnyLinkage:
+            return LLVMLinkOnceAnyLinkage;
+        case LLVMRustLinkage::LinkOnceODRLinkage:
+            return LLVMLinkOnceODRLinkage;
+        case LLVMRustLinkage::WeakAnyLinkage:
+            return LLVMWeakAnyLinkage;
+        case LLVMRustLinkage::WeakODRLinkage:
+            return LLVMWeakODRLinkage;
+        case LLVMRustLinkage::AppendingLinkage:
+            return LLVMAppendingLinkage;
+        case LLVMRustLinkage::InternalLinkage:
+            return LLVMInternalLinkage;
+        case LLVMRustLinkage::PrivateLinkage:
+            return LLVMPrivateLinkage;
+        case LLVMRustLinkage::ExternalWeakLinkage:
+            return LLVMExternalWeakLinkage;
+        case LLVMRustLinkage::CommonLinkage:
+            return LLVMCommonLinkage;
+        default:
+            llvm_unreachable("Invalid LLVMRustLinkage value!");
+    } 
+}
+
+extern "C" LLVMRustLinkage LLVMRustGetLinkage(LLVMValueRef V) {
+    return to_rust(LLVMGetLinkage(V));
+}
+
+extern "C" void LLVMRustSetLinkage(LLVMValueRef V, LLVMRustLinkage RustLinkage) {
+    LLVMSetLinkage(V, from_rust(RustLinkage));
+}
diff --git a/src/test/run-pass/issue-33992.rs b/src/test/run-pass/issue-33992.rs
new file mode 100644
index 000000000000..5729469f6975
--- /dev/null
+++ b/src/test/run-pass/issue-33992.rs
@@ -0,0 +1,40 @@
+// 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.
+
+// ignore-windows
+// ignore-macos
+
+#![feature(linkage)]
+
+#[linkage = "common"]
+pub static mut TEST1: u32 = 0u32;
+
+#[linkage = "external"]
+pub static TEST2: bool = true;
+
+#[linkage = "internal"]
+pub static TEST3: bool = true;
+
+#[linkage = "linkonce"]
+pub static TEST4: bool = true;
+
+#[linkage = "linkonce_odr"]
+pub static TEST5: bool = true;
+
+#[linkage = "private"]
+pub static TEST6: bool = true;
+
+#[linkage = "weak"]
+pub static TEST7: bool = true;
+
+#[linkage = "weak_odr"]
+pub static TEST8: bool = true;
+
+fn main() {}
\ No newline at end of file

From 3be6d1f954f2c8d36d40cea56494386e4259819c Mon Sep 17 00:00:00 2001
From: Vadim Petrochenkov 
Date: Fri, 26 Aug 2016 19:23:42 +0300
Subject: [PATCH 162/443] Make `private_in_public` compatibility lint
 warn-by-default again

---
 src/librustc/lint/builtin.rs                                | 2 +-
 src/librustc_privacy/diagnostics.rs                         | 4 ++++
 src/test/compile-fail/issue-28514.rs                        | 2 ++
 src/test/compile-fail/issue-30079.rs                        | 1 +
 src/test/compile-fail/private-in-public-warn.rs             | 4 ++--
 src/test/compile-fail/private-variant-and-crate-reexport.rs | 1 +
 6 files changed, 11 insertions(+), 3 deletions(-)

diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs
index ed94e5fe377c..173f8d496990 100644
--- a/src/librustc/lint/builtin.rs
+++ b/src/librustc/lint/builtin.rs
@@ -114,7 +114,7 @@ declare_lint! {
 
 declare_lint! {
     pub PRIVATE_IN_PUBLIC,
-    Deny,
+    Warn,
     "detect private items in public interfaces not caught by the old implementation"
 }
 
diff --git a/src/librustc_privacy/diagnostics.rs b/src/librustc_privacy/diagnostics.rs
index 891b6adea789..66afe5835bf6 100644
--- a/src/librustc_privacy/diagnostics.rs
+++ b/src/librustc_privacy/diagnostics.rs
@@ -17,6 +17,8 @@ A private trait was used on a public type parameter bound. Erroneous code
 examples:
 
 ```compile_fail,E0445
+#![deny(private_in_public)]
+
 trait Foo {
     fn dummy(&self) { }
 }
@@ -45,6 +47,8 @@ E0446: r##"
 A private type was used in a public type signature. Erroneous code example:
 
 ```compile_fail,E0446
+#![deny(private_in_public)]
+
 mod Foo {
     struct Bar(u32);
 
diff --git a/src/test/compile-fail/issue-28514.rs b/src/test/compile-fail/issue-28514.rs
index 6ee375503c2a..fb25166531dc 100644
--- a/src/test/compile-fail/issue-28514.rs
+++ b/src/test/compile-fail/issue-28514.rs
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#![deny(private_in_public)]
+
 pub use inner::C;
 
 mod inner {
diff --git a/src/test/compile-fail/issue-30079.rs b/src/test/compile-fail/issue-30079.rs
index 55c58ed021b2..6a54e53f1463 100644
--- a/src/test/compile-fail/issue-30079.rs
+++ b/src/test/compile-fail/issue-30079.rs
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#![deny(private_in_public)]
 #![allow(unused)]
 
 struct SemiPriv;
diff --git a/src/test/compile-fail/private-in-public-warn.rs b/src/test/compile-fail/private-in-public-warn.rs
index 6d6af77be92b..455de37aee96 100644
--- a/src/test/compile-fail/private-in-public-warn.rs
+++ b/src/test/compile-fail/private-in-public-warn.rs
@@ -13,8 +13,8 @@
 
 #![feature(associated_consts)]
 #![feature(associated_type_defaults)]
-#![allow(dead_code)]
-#![allow(unused_variables)]
+#![deny(private_in_public)]
+#![allow(unused)]
 #![allow(improper_ctypes)]
 
 mod types {
diff --git a/src/test/compile-fail/private-variant-and-crate-reexport.rs b/src/test/compile-fail/private-variant-and-crate-reexport.rs
index ce029e7eff7f..dce533e73fee 100644
--- a/src/test/compile-fail/private-variant-and-crate-reexport.rs
+++ b/src/test/compile-fail/private-variant-and-crate-reexport.rs
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#![deny(private_in_public)]
 #![allow(dead_code)]
 
 extern crate core;

From e4784fc3137b9bdd3a45483f490b1f362506c794 Mon Sep 17 00:00:00 2001
From: Andrew Paseltiner 
Date: Sun, 4 Sep 2016 22:57:27 -0400
Subject: [PATCH 163/443] Remove mention of `unsafe_no_drop_flag` from
 Reference and Nomicon

---
 src/doc/nomicon/safe-unsafe-meaning.md |  4 ----
 src/doc/reference.md                   | 10 ----------
 2 files changed, 14 deletions(-)

diff --git a/src/doc/nomicon/safe-unsafe-meaning.md b/src/doc/nomicon/safe-unsafe-meaning.md
index c4f939a608b7..adede0ec9111 100644
--- a/src/doc/nomicon/safe-unsafe-meaning.md
+++ b/src/doc/nomicon/safe-unsafe-meaning.md
@@ -26,10 +26,6 @@ can therefore be trusted. You can use `unsafe` on a trait implementation
 to declare that the implementation of that trait has adhered to whatever
 contracts the trait's documentation requires.
 
-There is also the `#[unsafe_no_drop_flag]` attribute, which exists for
-historic reasons and is being phased out. See the section on [drop flags]
-for details.
-
 The standard library has a number of unsafe functions, including:
 
 * `slice::get_unchecked`, which performs unchecked indexing, allowing
diff --git a/src/doc/reference.md b/src/doc/reference.md
index cc5d9c3685ab..f29cdf6b0803 100644
--- a/src/doc/reference.md
+++ b/src/doc/reference.md
@@ -2059,10 +2059,6 @@ macro scope.
   outside of its dynamic extent), and thus this attribute has the word
   "unsafe" in its name. To use this, the
   `unsafe_destructor_blind_to_params` feature gate must be enabled.
-- `unsafe_no_drop_flag` - on structs, remove the flag that prevents
-  destructors from being run twice. Destructors might be run multiple times on
-  the same object with this attribute. To use this, the `unsafe_no_drop_flag` feature
-  gate must be enabled.
 - `doc` - Doc comments such as `/// foo` are equivalent to `#[doc = "foo"]`.
 - `rustc_on_unimplemented` - Write a custom note to be shown along with the error
    when the trait is found to be unimplemented on a type.
@@ -2458,12 +2454,6 @@ The currently implemented features of the reference compiler are:
 * `unboxed_closures` - Rust's new closure design, which is currently a work in
                        progress feature with many known bugs.
 
-* `unsafe_no_drop_flag` - Allows use of the `#[unsafe_no_drop_flag]` attribute,
-                          which removes hidden flag added to a type that
-                          implements the `Drop` trait. The design for the
-                          `Drop` flag is subject to change, and this feature
-                          may be removed in the future.
-
 * `unmarked_api` - Allows use of items within a `#![staged_api]` crate
                    which have not been marked with a stability marker.
                    Such items should not be allowed by the compiler to exist,

From 0ddf060b6d347f89afb584501c86a4fa96ec7acc Mon Sep 17 00:00:00 2001
From: Andrew Cann 
Date: Tue, 9 Aug 2016 20:57:41 +0800
Subject: [PATCH 164/443] Make write_ty and friends return adjusted type

---
 src/librustc_typeck/check/_match.rs  |   4 +-
 src/librustc_typeck/check/callee.rs  |  23 +--
 src/librustc_typeck/check/closure.rs |   8 +-
 src/librustc_typeck/check/mod.rs     | 241 ++++++++++++++-------------
 src/librustc_typeck/check/op.rs      |  23 +--
 5 files changed, 153 insertions(+), 146 deletions(-)

diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index 12fce4b928e0..1f0faab8f2c4 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -371,7 +371,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                        discrim: &'gcx hir::Expr,
                        arms: &'gcx [hir::Arm],
                        expected: Expectation<'tcx>,
-                       match_src: hir::MatchSource) {
+                       match_src: hir::MatchSource) -> Ty<'tcx> {
         let tcx = self.tcx;
 
         // Not entirely obvious: if matches may create ref bindings, we
@@ -480,7 +480,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             };
         }
 
-        self.write_ty(expr.id, result_ty);
+        self.write_ty(expr.id, result_ty)
     }
 }
 
diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs
index 49db56d2dabd..4f673606de52 100644
--- a/src/librustc_typeck/check/callee.rs
+++ b/src/librustc_typeck/check/callee.rs
@@ -45,7 +45,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                       call_expr: &'gcx hir::Expr,
                       callee_expr: &'gcx hir::Expr,
                       arg_exprs: &'gcx [P],
-                      expected: Expectation<'tcx>)
+                      expected: Expectation<'tcx>) -> Ty<'tcx>
     {
         self.check_expr(callee_expr);
         let original_callee_ty = self.expr_ty(callee_expr);
@@ -60,20 +60,20 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         match result {
             None => {
                 // this will report an error since original_callee_ty is not a fn
-                self.confirm_builtin_call(call_expr, original_callee_ty, arg_exprs, expected);
+                self.confirm_builtin_call(call_expr, original_callee_ty, arg_exprs, expected)
             }
 
             Some(CallStep::Builtin) => {
-                self.confirm_builtin_call(call_expr, callee_ty, arg_exprs, expected);
+                self.confirm_builtin_call(call_expr, callee_ty, arg_exprs, expected)
             }
 
             Some(CallStep::DeferredClosure(fn_sig)) => {
-                self.confirm_deferred_closure_call(call_expr, arg_exprs, expected, fn_sig);
+                self.confirm_deferred_closure_call(call_expr, arg_exprs, expected, fn_sig)
             }
 
             Some(CallStep::Overloaded(method_callee)) => {
                 self.confirm_overloaded_call(call_expr, callee_expr,
-                                             arg_exprs, expected, method_callee);
+                                             arg_exprs, expected, method_callee)
             }
         }
     }
@@ -181,7 +181,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                             call_expr: &hir::Expr,
                             callee_ty: Ty<'tcx>,
                             arg_exprs: &'gcx [P],
-                            expected: Expectation<'tcx>)
+                            expected: Expectation<'tcx>) -> Ty<'tcx>
     {
         let error_fn_sig;
 
@@ -245,14 +245,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                   fn_sig.variadic,
                                   TupleArgumentsFlag::DontTupleArguments);
 
-        self.write_call(call_expr, fn_sig.output);
+        self.write_ty(call_expr.id, fn_sig.output)
     }
 
     fn confirm_deferred_closure_call(&self,
                                      call_expr: &hir::Expr,
                                      arg_exprs: &'gcx [P],
                                      expected: Expectation<'tcx>,
-                                     fn_sig: ty::FnSig<'tcx>)
+                                     fn_sig: ty::FnSig<'tcx>) -> Ty<'tcx>
     {
         // `fn_sig` is the *signature* of the cosure being called. We
         // don't know the full details yet (`Fn` vs `FnMut` etc), but we
@@ -272,7 +272,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                   fn_sig.variadic,
                                   TupleArgumentsFlag::TupleArguments);
 
-        self.write_call(call_expr, fn_sig.output);
+        self.write_ty(call_expr.id, fn_sig.output)
     }
 
     fn confirm_overloaded_call(&self,
@@ -280,7 +280,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                callee_expr: &'gcx hir::Expr,
                                arg_exprs: &'gcx [P],
                                expected: Expectation<'tcx>,
-                               method_callee: ty::MethodCallee<'tcx>)
+                               method_callee: ty::MethodCallee<'tcx>) -> Ty<'tcx>
     {
         let output_type =
             self.check_method_argument_types(call_expr.span,
@@ -289,9 +289,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                              arg_exprs,
                                              TupleArgumentsFlag::TupleArguments,
                                              expected);
-        self.write_call(call_expr, output_type);
+        let ty = self.write_ty(call_expr.id, output_type);
 
         self.write_overloaded_call_method_map(call_expr, method_callee);
+        ty
     }
 
     fn write_overloaded_call_method_map(&self,
diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs
index 8980cb907602..1f4201aa39cd 100644
--- a/src/librustc_typeck/check/closure.rs
+++ b/src/librustc_typeck/check/closure.rs
@@ -24,7 +24,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                               _capture: hir::CaptureClause,
                               decl: &'gcx hir::FnDecl,
                               body: &'gcx hir::Block,
-                              expected: Expectation<'tcx>) {
+                              expected: Expectation<'tcx>) -> Ty<'tcx> {
         debug!("check_expr_closure(expr={:?},expected={:?})",
                expr,
                expected);
@@ -44,7 +44,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                      opt_kind: Option,
                      decl: &'gcx hir::FnDecl,
                      body: &'gcx hir::Block,
-                     expected_sig: Option>) {
+                     expected_sig: Option>) -> Ty<'tcx> {
         let expr_def_id = self.tcx.map.local_def_id(expr.id);
 
         debug!("check_closure opt_kind={:?} expected_sig={:?}",
@@ -70,7 +70,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             self.parameter_environment.free_substs,
             upvar_tys);
 
-        self.write_ty(expr.id, closure_type);
+        let ty = self.write_ty(expr.id, closure_type);
 
         let fn_sig = self.tcx.liberate_late_bound_regions(
             self.tcx.region_maps.call_site_extent(expr.id, body.id), &fn_ty.sig);
@@ -93,6 +93,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             Some(kind) => { self.tables.borrow_mut().closure_kinds.insert(expr_def_id, kind); }
             None => { }
         }
+
+        ty
     }
 
     fn deduce_expectations_from_expected_type(&self, expected_ty: Ty<'tcx>)
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 0aa523e9d5e4..5c528cc46a73 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -1530,7 +1530,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     }
 
     #[inline]
-    pub fn write_ty(&self, node_id: ast::NodeId, ty: Ty<'tcx>) {
+    pub fn write_ty(&self, node_id: ast::NodeId, ty: Ty<'tcx>) -> Ty<'tcx> {
         debug!("write_ty({}, {:?}) in fcx {}",
                node_id, ty, self.tag());
         self.tables.borrow_mut().node_types.insert(node_id, ty);
@@ -1538,10 +1538,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         // Add adjustments to !-expressions
         if ty.is_never() {
             if let Some(hir::map::NodeExpr(_)) = self.tcx.map.find(node_id) {
-                let adj = adjustment::AdjustNeverToAny(self.next_diverging_ty_var());
+                let adj_ty = self.next_diverging_ty_var();
+                let adj = adjustment::AdjustNeverToAny(adj_ty);
                 self.write_adjustment(node_id, adj);
+                return adj_ty;
             }
         }
+        ty
     }
 
     pub fn write_substs(&self, node_id: ast::NodeId, substs: ty::ItemSubsts<'tcx>) {
@@ -1715,16 +1718,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         ty_substituted
     }
 
-    pub fn write_nil(&self, node_id: ast::NodeId) {
-        self.write_ty(node_id, self.tcx.mk_nil());
+    pub fn write_nil(&self, node_id: ast::NodeId) -> Ty<'tcx> {
+        self.write_ty(node_id, self.tcx.mk_nil())
     }
 
-    pub fn write_never(&self, node_id: ast::NodeId) {
-        self.write_ty(node_id, self.tcx.types.never);
+    pub fn write_never(&self, node_id: ast::NodeId) -> Ty<'tcx> {
+        self.write_ty(node_id, self.tcx.types.never)
     }
 
-    pub fn write_error(&self, node_id: ast::NodeId) {
-        self.write_ty(node_id, self.tcx.types.err);
+    pub fn write_error(&self, node_id: ast::NodeId) -> Ty<'tcx> {
+        self.write_ty(node_id, self.tcx.types.err)
     }
 
     pub fn require_type_meets(&self,
@@ -2666,12 +2669,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         (0..len).map(|_| self.tcx.types.err).collect()
     }
 
-    fn write_call(&self,
-                  call_expr: &hir::Expr,
-                  output: Ty<'tcx>) {
-        self.write_ty(call_expr.id, output);
-    }
-
     // AST fragment checking
     fn check_lit(&self,
                  lit: &ast::Lit,
@@ -2727,35 +2724,37 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
     pub fn check_expr_has_type(&self,
                                expr: &'gcx hir::Expr,
-                               expected: Ty<'tcx>) {
-        self.check_expr_with_hint(expr, expected);
+                               expected: Ty<'tcx>) -> Ty<'tcx> {
+        let ty = self.check_expr_with_hint(expr, expected);
         self.demand_suptype(expr.span, expected, self.expr_ty(expr));
+        ty
     }
 
     fn check_expr_coercable_to_type(&self,
                                     expr: &'gcx hir::Expr,
-                                    expected: Ty<'tcx>) {
-        self.check_expr_with_hint(expr, expected);
+                                    expected: Ty<'tcx>) -> Ty<'tcx> {
+        let ty = self.check_expr_with_hint(expr, expected);
         self.demand_coerce(expr, expected);
+        ty
     }
 
     fn check_expr_with_hint(&self, expr: &'gcx hir::Expr,
-                            expected: Ty<'tcx>) {
+                            expected: Ty<'tcx>) -> Ty<'tcx> {
         self.check_expr_with_expectation(expr, ExpectHasType(expected))
     }
 
     fn check_expr_with_expectation(&self,
                                    expr: &'gcx hir::Expr,
-                                   expected: Expectation<'tcx>) {
+                                   expected: Expectation<'tcx>) -> Ty<'tcx> {
         self.check_expr_with_expectation_and_lvalue_pref(expr, expected, NoPreference)
     }
 
-    fn check_expr(&self, expr: &'gcx hir::Expr)  {
+    fn check_expr(&self, expr: &'gcx hir::Expr) -> Ty<'tcx> {
         self.check_expr_with_expectation(expr, NoExpectation)
     }
 
     fn check_expr_with_lvalue_pref(&self, expr: &'gcx hir::Expr,
-                                   lvalue_pref: LvaluePreference)  {
+                                   lvalue_pref: LvaluePreference) -> Ty<'tcx> {
         self.check_expr_with_expectation_and_lvalue_pref(expr, NoExpectation, lvalue_pref)
     }
 
@@ -2820,7 +2819,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                          args: &'gcx [P],
                          tps: &[P],
                          expected: Expectation<'tcx>,
-                         lvalue_pref: LvaluePreference) {
+                         lvalue_pref: LvaluePreference) -> Ty<'tcx> {
         let rcvr = &args[0];
         self.check_expr_with_lvalue_pref(&rcvr, lvalue_pref);
 
@@ -2856,7 +2855,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                                       DontTupleArguments,
                                                       expected);
 
-        self.write_call(expr, ret_ty);
+        self.write_ty(expr.id, ret_ty)
     }
 
     // A generic function for checking the then and else in an if
@@ -2867,7 +2866,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                        opt_else_expr: Option<&'gcx hir::Expr>,
                        id: ast::NodeId,
                        sp: Span,
-                       expected: Expectation<'tcx>) {
+                       expected: Expectation<'tcx>) -> Ty<'tcx> {
         self.check_expr_has_type(cond_expr, self.tcx.types.bool);
 
         let expected = expected.adjust_for_branches(self);
@@ -2932,7 +2931,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             }
         };
 
-        self.write_ty(id, if_ty);
+        self.write_ty(id, if_ty)
     }
 
     // Check field access expressions
@@ -2940,7 +2939,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                    expr: &'gcx hir::Expr,
                    lvalue_pref: LvaluePreference,
                    base: &'gcx hir::Expr,
-                   field: &Spanned) {
+                   field: &Spanned) -> Ty<'tcx> {
         self.check_expr_with_lvalue_pref(base, lvalue_pref);
         let expr_t = self.structurally_resolved_type(expr.span,
                                                      self.expr_ty(base));
@@ -2954,9 +2953,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                         let field_ty = self.field_ty(expr.span, field, substs);
                         if field.vis.is_accessible_from(self.body_id, &self.tcx().map) {
                             autoderef.finalize(lvalue_pref, Some(base));
-                            self.write_ty(expr.id, field_ty);
+                            let ty = self.write_ty(expr.id, field_ty);
                             self.write_autoderef_adjustment(base.id, autoderefs);
-                            return;
+                            return ty;
                         }
                         private_candidate = Some((base_def.did, field_ty));
                     }
@@ -2968,7 +2967,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
         if let Some((did, field_ty)) = private_candidate {
             let struct_path = self.tcx().item_path_str(did);
-            self.write_ty(expr.id, field_ty);
+            let ty = self.write_ty(expr.id, field_ty);
             let msg = format!("field `{}` of struct `{}` is private", field.node, struct_path);
             let mut err = self.tcx().sess.struct_span_err(expr.span, &msg);
             // Also check if an accessible method exists, which is often what is meant.
@@ -2977,8 +2976,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                   field.node));
             }
             err.emit();
+            ty
         } else if field.node == keywords::Invalid.name() {
-            self.write_error(expr.id);
+            self.write_error(expr.id)
         } else if self.method_exists(field.span, field.node, expr_t, expr.id, true) {
             self.type_error_struct(field.span, |actual| {
                 format!("attempted to take value of method `{}` on type \
@@ -2987,7 +2987,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 .help("maybe a `()` to call it is missing? \
                        If not, try an anonymous function")
                 .emit();
-            self.write_error(expr.id);
+            self.write_error(expr.id)
         } else {
             let mut err = self.type_error_struct(expr.span, |actual| {
                 format!("attempted access of field `{}` on type `{}`, \
@@ -3005,7 +3005,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 _ => {}
             }
             err.emit();
-            self.write_error(expr.id);
+            self.write_error(expr.id)
         }
     }
 
@@ -3037,7 +3037,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                        expr: &'gcx hir::Expr,
                        lvalue_pref: LvaluePreference,
                        base: &'gcx hir::Expr,
-                       idx: codemap::Spanned) {
+                       idx: codemap::Spanned) -> Ty<'tcx> {
         self.check_expr_with_lvalue_pref(base, lvalue_pref);
         let expr_t = self.structurally_resolved_type(expr.span,
                                                      self.expr_ty(base));
@@ -3070,9 +3070,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
             if let Some(field_ty) = field {
                 autoderef.finalize(lvalue_pref, Some(base));
-                self.write_ty(expr.id, field_ty);
+                let ty = self.write_ty(expr.id, field_ty);
                 self.write_autoderef_adjustment(base.id, autoderefs);
-                return;
+                return ty;
             }
         }
         autoderef.unambiguous_final_ty();
@@ -3081,8 +3081,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             let struct_path = self.tcx().item_path_str(did);
             let msg = format!("field `{}` of struct `{}` is private", idx.node, struct_path);
             self.tcx().sess.span_err(expr.span, &msg);
-            self.write_ty(expr.id, field_ty);
-            return;
+            return self.write_ty(expr.id, field_ty)
         }
 
         self.type_error_message(
@@ -3102,7 +3101,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             },
             expr_t);
 
-        self.write_error(expr.id);
+        self.write_error(expr.id)
     }
 
     fn report_unknown_field(&self,
@@ -3207,17 +3206,20 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     fn check_struct_fields_on_error(&self,
                                     id: ast::NodeId,
                                     fields: &'gcx [hir::Field],
-                                    base_expr: &'gcx Option>) {
+                                    base_expr: &'gcx Option>) -> Ty<'tcx> {
         // Make sure to still write the types
         // otherwise we might ICE
-        self.write_error(id);
+        let ty = self.write_error(id);
         for field in fields {
             self.check_expr(&field.expr);
         }
         match *base_expr {
-            Some(ref base) => self.check_expr(&base),
+            Some(ref base) => {
+                self.check_expr(&base);
+            },
             None => {}
         }
+        ty
     }
 
     pub fn check_struct_path(&self,
@@ -3267,15 +3269,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                          expr: &hir::Expr,
                          path: &hir::Path,
                          fields: &'gcx [hir::Field],
-                         base_expr: &'gcx Option>)
+                         base_expr: &'gcx Option>) -> Ty<'tcx>
     {
         // Find the relevant variant
         let (variant, expr_ty) = if let Some(variant_ty) = self.check_struct_path(path, expr.id,
                                                                                   expr.span) {
             variant_ty
         } else {
-            self.check_struct_fields_on_error(expr.id, fields, base_expr);
-            return;
+            return self.check_struct_fields_on_error(expr.id, fields, base_expr);
         };
 
         self.check_expr_struct_fields(expr_ty, path.span, variant, fields,
@@ -3299,6 +3300,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 }
             }
         }
+        expr_ty
     }
 
 
@@ -3315,13 +3317,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     fn check_expr_with_expectation_and_lvalue_pref(&self,
                                                    expr: &'gcx hir::Expr,
                                                    expected: Expectation<'tcx>,
-                                                   lvalue_pref: LvaluePreference) {
+                                                   lvalue_pref: LvaluePreference) -> Ty<'tcx> {
         debug!(">> typechecking: expr={:?} expected={:?}",
                expr, expected);
 
         let tcx = self.tcx;
         let id = expr.id;
-        match expr.node {
+        let ty = match expr.node {
           hir::ExprBox(ref subexpr) => {
             let expected_inner = expected.to_option(self).map_or(NoExpectation, |ty| {
                 match ty.sty {
@@ -3331,18 +3333,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             });
             self.check_expr_with_expectation(subexpr, expected_inner);
             let referent_ty = self.expr_ty(&subexpr);
-            self.write_ty(id, tcx.mk_box(referent_ty));
+            self.write_ty(id, tcx.mk_box(referent_ty))
           }
 
           hir::ExprLit(ref lit) => {
             let typ = self.check_lit(&lit, expected);
-            self.write_ty(id, typ);
+            self.write_ty(id, typ)
           }
           hir::ExprBinary(op, ref lhs, ref rhs) => {
-            self.check_binop(expr, op, lhs, rhs);
+            self.check_binop(expr, op, lhs, rhs)
           }
           hir::ExprAssignOp(op, ref lhs, ref rhs) => {
-            self.check_binop_assign(expr, op, lhs, rhs);
+            self.check_binop_assign(expr, op, lhs, rhs)
           }
           hir::ExprUnary(unop, ref oprnd) => {
             let expected_inner = match unop {
@@ -3357,10 +3359,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 hir::UnDeref => lvalue_pref,
                 _ => NoPreference
             };
-            self.check_expr_with_expectation_and_lvalue_pref(&oprnd,
-                                                             expected_inner,
-                                                             lvalue_pref);
-            let mut oprnd_t = self.expr_ty(&oprnd);
+            let mut oprnd_t = self.check_expr_with_expectation_and_lvalue_pref(&oprnd,
+                                                                               expected_inner,
+                                                                               lvalue_pref);
 
             if !oprnd_t.references_error() {
                 match unop {
@@ -3402,7 +3403,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     }
                 }
             }
-            self.write_ty(id, oprnd_t);
+            self.write_ty(id, oprnd_t)
           }
           hir::ExprAddrOf(mutbl, ref oprnd) => {
             let hint = expected.only_has_type(self).map_or(NoExpectation, |ty| {
@@ -3421,9 +3422,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 }
             });
             let lvalue_pref = LvaluePreference::from_mutbl(mutbl);
-            self.check_expr_with_expectation_and_lvalue_pref(&oprnd, hint, lvalue_pref);
+            let ty = self.check_expr_with_expectation_and_lvalue_pref(&oprnd, hint, lvalue_pref);
 
-            let tm = ty::TypeAndMut { ty: self.expr_ty(&oprnd), mutbl: mutbl };
+            let tm = ty::TypeAndMut { ty: ty, mutbl: mutbl };
             let oprnd_t = if tm.ty.references_error() {
                 tcx.types.err
             } else {
@@ -3443,24 +3444,25 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 let region = self.next_region_var(infer::AddrOfRegion(expr.span));
                 tcx.mk_ref(region, tm)
             };
-            self.write_ty(id, oprnd_t);
+            self.write_ty(id, oprnd_t)
           }
           hir::ExprPath(ref opt_qself, ref path) => {
               let opt_self_ty = opt_qself.as_ref().map(|qself| self.to_ty(&qself.ty));
               let (def, opt_ty, segments) = self.resolve_ty_and_def_ufcs(opt_self_ty, path,
                                                                          expr.id, expr.span);
-              if def != Def::Err {
-                  self.instantiate_value_path(segments, opt_ty, def, expr.span, id);
+              let ty = if def != Def::Err {
+                  self.instantiate_value_path(segments, opt_ty, def, expr.span, id)
               } else {
                   self.set_tainted_by_errors();
-                  self.write_error(id);
-              }
+                  self.write_error(id)
+              };
 
               // We always require that the type provided as the value for
               // a type parameter outlives the moment of instantiation.
               self.opt_node_ty_substs(expr.id, |item_substs| {
                   self.add_wf_bounds(&item_substs.substs, expr);
               });
+              ty
           }
           hir::ExprInlineAsm(_, ref outputs, ref inputs) => {
               for output in outputs {
@@ -3469,10 +3471,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
               for input in inputs {
                   self.check_expr(input);
               }
-              self.write_nil(id);
+              self.write_nil(id)
           }
-          hir::ExprBreak(_) => { self.write_never(id); }
-          hir::ExprAgain(_) => { self.write_never(id); }
+          hir::ExprBreak(_) => { self.write_never(id) }
+          hir::ExprAgain(_) => { self.write_never(id) }
           hir::ExprRet(ref expr_opt) => {
             if let Some(ref e) = *expr_opt {
                 self.check_expr_coercable_to_type(&e, self.ret_ty);
@@ -3490,10 +3492,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                         .emit();
                 }
             }
-            self.write_never(id);
+            self.write_never(id)
           }
           hir::ExprAssign(ref lhs, ref rhs) => {
-            self.check_expr_with_lvalue_pref(&lhs, PreferMutLvalue);
+            let lhs_ty = self.check_expr_with_lvalue_pref(&lhs, PreferMutLvalue);
 
             let tcx = self.tcx;
             if !tcx.expr_is_lval(&lhs) {
@@ -3506,21 +3508,19 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 .emit();
             }
 
-            let lhs_ty = self.expr_ty(&lhs);
-            self.check_expr_coercable_to_type(&rhs, lhs_ty);
-            let rhs_ty = self.expr_ty(&rhs);
+            let rhs_ty = self.check_expr_coercable_to_type(&rhs, lhs_ty);
 
             self.require_expr_have_sized_type(&lhs, traits::AssignmentLhsSized);
 
             if lhs_ty.references_error() || rhs_ty.references_error() {
-                self.write_error(id);
+                self.write_error(id)
             } else {
-                self.write_nil(id);
+                self.write_nil(id)
             }
           }
           hir::ExprIf(ref cond, ref then_blk, ref opt_else_expr) => {
             self.check_then_else(&cond, &then_blk, opt_else_expr.as_ref().map(|e| &**e),
-                                 id, expr.span, expected);
+                                 id, expr.span, expected)
           }
           hir::ExprWhile(ref cond, ref body, _) => {
             self.check_expr_has_type(&cond, tcx.types.bool);
@@ -3528,43 +3528,47 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             let cond_ty = self.expr_ty(&cond);
             let body_ty = self.node_ty(body.id);
             if cond_ty.references_error() || body_ty.references_error() {
-                self.write_error(id);
+                self.write_error(id)
             }
             else {
-                self.write_nil(id);
+                self.write_nil(id)
             }
           }
           hir::ExprLoop(ref body, _) => {
             self.check_block_no_value(&body);
             if !may_break(tcx, expr.id, &body) {
-                self.write_never(id);
+                self.write_never(id)
             } else {
-                self.write_nil(id);
+                self.write_nil(id)
             }
           }
           hir::ExprMatch(ref discrim, ref arms, match_src) => {
-            self.check_match(expr, &discrim, arms, expected, match_src);
+            self.check_match(expr, &discrim, arms, expected, match_src)
           }
           hir::ExprClosure(capture, ref decl, ref body, _) => {
-              self.check_expr_closure(expr, capture, &decl, &body, expected);
+              self.check_expr_closure(expr, capture, &decl, &body, expected)
           }
           hir::ExprBlock(ref b) => {
             self.check_block_with_expected(&b, expected);
-            self.write_ty(id, self.node_ty(b.id));
+            let ty = self.node_ty(b.id);
+            self.write_ty(id, ty)
           }
           hir::ExprCall(ref callee, ref args) => {
-              self.check_call(expr, &callee, &args[..], expected);
+              let ret_ty = self.check_call(expr, &callee, &args[..], expected);
 
               // we must check that return type of called functions is WF:
-              let ret_ty = self.expr_ty(expr);
               self.register_wf_obligation(ret_ty, expr.span, traits::MiscObligation);
+              ret_ty
           }
           hir::ExprMethodCall(name, ref tps, ref args) => {
-              self.check_method_call(expr, name, &args[..], &tps[..], expected, lvalue_pref);
+              let ty = self.check_method_call(expr, name, &args[..], &tps[..], expected, lvalue_pref);
               let arg_tys = args.iter().map(|a| self.expr_ty(&a));
               let args_err = arg_tys.fold(false, |rest_err, a| rest_err || a.references_error());
               if args_err {
-                  self.write_error(id);
+                  self.write_error(id)
+              }
+              else {
+                  ty
               }
           }
           hir::ExprCast(ref e, ref t) => {
@@ -3576,26 +3580,26 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             // if appropriate.
             let t_cast = self.to_ty(t);
             let t_cast = self.resolve_type_vars_if_possible(&t_cast);
-            self.check_expr_with_expectation(e, ExpectCastableToType(t_cast));
-            let t_expr = self.expr_ty(e);
+            let t_expr = self.check_expr_with_expectation(e, ExpectCastableToType(t_cast));
             let t_cast = self.resolve_type_vars_if_possible(&t_cast);
 
             // Eagerly check for some obvious errors.
             if t_expr.references_error() || t_cast.references_error() {
-                self.write_error(id);
+                self.write_error(id)
             } else {
                 // Write a type for the whole expression, assuming everything is going
                 // to work out Ok.
-                self.write_ty(id, t_cast);
+                let ty = self.write_ty(id, t_cast);
 
                 // Defer other checks until we're done type checking.
                 let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut();
                 match cast::CastCheck::new(self, e, t_expr, t_cast, t.span, expr.span) {
                     Ok(cast_check) => {
                         deferred_cast_checks.push(cast_check);
+                        ty
                     }
                     Err(ErrorReported) => {
-                        self.write_error(id);
+                        self.write_error(id)
                     }
                 }
             }
@@ -3603,7 +3607,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
           hir::ExprType(ref e, ref t) => {
             let typ = self.to_ty(&t);
             self.check_expr_eq_type(&e, typ);
-            self.write_ty(id, typ);
+            self.write_ty(id, typ)
           }
           hir::ExprVec(ref args) => {
             let uty = expected.to_option(self).and_then(|uty| {
@@ -3617,8 +3621,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             let coerce_to = uty.unwrap_or(unified);
 
             for (i, e) in args.iter().enumerate() {
-                self.check_expr_with_hint(e, coerce_to);
-                let e_ty = self.expr_ty(e);
+                let e_ty = self.check_expr_with_hint(e, coerce_to);
                 let origin = TypeOrigin::Misc(e.span);
 
                 // Special-case the first element, as it has no "previous expressions".
@@ -3636,7 +3639,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     }
                 }
             }
-            self.write_ty(id, tcx.mk_array(unified, args.len()));
+            self.write_ty(id, tcx.mk_array(unified, args.len()))
           }
           hir::ExprRepeat(ref element, ref count_expr) => {
             self.check_expr_has_type(&count_expr, tcx.types.usize);
@@ -3660,8 +3663,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 }
                 None => {
                     let t: Ty = self.next_ty_var();
-                    self.check_expr_has_type(&element, t);
-                    (self.expr_ty(&element), t)
+                    let element_ty = self.check_expr_has_type(&element, t);
+                    (element_ty, t)
                 }
             };
 
@@ -3672,10 +3675,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             }
 
             if element_ty.references_error() {
-                self.write_error(id);
+                self.write_error(id)
             } else {
                 let t = tcx.mk_array(t, count);
-                self.write_ty(id, t);
+                self.write_ty(id, t)
             }
           }
           hir::ExprTup(ref elts) => {
@@ -3695,49 +3698,46 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                         ety
                     }
                     _ => {
-                        self.check_expr_with_expectation(&e, NoExpectation);
-                        self.expr_ty(&e)
+                        self.check_expr_with_expectation(&e, NoExpectation)
                     }
                 };
                 err_field = err_field || t.references_error();
                 t
             }).collect();
             if err_field {
-                self.write_error(id);
+                self.write_error(id)
             } else {
                 let typ = tcx.mk_tup(elt_ts);
-                self.write_ty(id, typ);
+                self.write_ty(id, typ)
             }
           }
           hir::ExprStruct(ref path, ref fields, ref base_expr) => {
-            self.check_expr_struct(expr, path, fields, base_expr);
+            let ty = self.check_expr_struct(expr, path, fields, base_expr);
 
             self.require_expr_have_sized_type(expr, traits::StructInitializerSized);
+            ty
           }
           hir::ExprField(ref base, ref field) => {
-            self.check_field(expr, lvalue_pref, &base, field);
+            self.check_field(expr, lvalue_pref, &base, field)
           }
           hir::ExprTupField(ref base, idx) => {
-            self.check_tup_field(expr, lvalue_pref, &base, idx);
+            self.check_tup_field(expr, lvalue_pref, &base, idx)
           }
           hir::ExprIndex(ref base, ref idx) => {
-              self.check_expr_with_lvalue_pref(&base, lvalue_pref);
-              self.check_expr(&idx);
-
-              let base_t = self.expr_ty(&base);
-              let idx_t = self.expr_ty(&idx);
+              let base_t = self.check_expr_with_lvalue_pref(&base, lvalue_pref);
+              let idx_t = self.check_expr(&idx);
 
               if base_t.references_error() {
-                  self.write_ty(id, base_t);
+                  self.write_ty(id, base_t)
               } else if idx_t.references_error() {
-                  self.write_ty(id, idx_t);
+                  self.write_ty(id, idx_t)
               } else {
                   let base_t = self.structurally_resolved_type(expr.span, base_t);
                   match self.lookup_indexing(expr, base, base_t, idx_t, lvalue_pref) {
                       Some((index_ty, element_ty)) => {
                           let idx_expr_ty = self.expr_ty(idx);
                           self.demand_eqtype(expr.span, index_ty, idx_expr_ty);
-                          self.write_ty(id, element_ty);
+                          self.write_ty(id, element_ty)
                       }
                       None => {
                           self.check_expr_has_type(&idx, self.tcx.types.err);
@@ -3773,18 +3773,19 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                               }
                           }
                           err.emit();
-                          self.write_ty(id, self.tcx().types.err);
+                          self.write_ty(id, self.tcx().types.err)
                       }
                   }
               }
            }
-        }
+        };
 
         debug!("type of expr({}) {} is...", expr.id,
                pprust::expr_to_string(expr));
         debug!("... {:?}, expected is {:?}",
-               self.expr_ty(expr),
+               ty,
                expected);
+        ty
     }
 
     // Finish resolving a path in a struct expression or pattern `S::A { .. }` if necessary.
@@ -3878,9 +3879,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             // referent for the reference that results is *equal to* the
             // type of the lvalue it is referencing, and not some
             // supertype thereof.
-            self.check_expr_with_lvalue_pref(init, LvaluePreference::from_mutbl(m));
-            let init_ty = self.expr_ty(init);
+            let init_ty = self.check_expr_with_lvalue_pref(init, LvaluePreference::from_mutbl(m));
             self.demand_eqtype(init.span, init_ty, local_ty);
+            init_ty
         } else {
             self.check_expr_coercable_to_type(init, local_ty)
         };
@@ -3905,7 +3906,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         }
     }
 
-    pub fn check_stmt(&self, stmt: &'gcx hir::Stmt)  {
+    pub fn check_stmt(&self, stmt: &'gcx hir::Stmt) {
         let node_id;
         let mut saw_bot = false;
         let mut saw_err = false;
@@ -3945,7 +3946,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             self.write_error(node_id);
         }
         else {
-            self.write_nil(node_id)
+            self.write_nil(node_id);
         }
     }
 
diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs
index a8b1683f6d35..feb3258c88c2 100644
--- a/src/librustc_typeck/check/op.rs
+++ b/src/librustc_typeck/check/op.rs
@@ -23,7 +23,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                               expr: &'gcx hir::Expr,
                               op: hir::BinOp,
                               lhs_expr: &'gcx hir::Expr,
-                              rhs_expr: &'gcx hir::Expr)
+                              rhs_expr: &'gcx hir::Expr) -> Ty<'tcx>
     {
         self.check_expr_with_lvalue_pref(lhs_expr, PreferMutLvalue);
 
@@ -32,12 +32,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             self.check_overloaded_binop(expr, lhs_expr, lhs_ty, rhs_expr, op, IsAssign::Yes);
         let rhs_ty = self.resolve_type_vars_with_obligations(rhs_ty);
 
-        if !lhs_ty.is_ty_var() && !rhs_ty.is_ty_var() && is_builtin_binop(lhs_ty, rhs_ty, op) {
+        let ty = if !lhs_ty.is_ty_var() && !rhs_ty.is_ty_var() && is_builtin_binop(lhs_ty, rhs_ty, op) {
             self.enforce_builtin_binop_types(lhs_expr, lhs_ty, rhs_expr, rhs_ty, op);
-            self.write_nil(expr.id);
+            self.tcx.mk_nil()
         } else {
-            self.write_ty(expr.id, return_ty);
-        }
+            return_ty
+        };
+        let ty = self.write_ty(expr.id, ty);
 
         let tcx = self.tcx;
         if !tcx.expr_is_lval(lhs_expr) {
@@ -49,6 +50,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 &format!("invalid expression for left-hand side"))
             .emit();
         }
+        ty
     }
 
     /// Check a potentially overloaded binary operator.
@@ -56,7 +58,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                        expr: &'gcx hir::Expr,
                        op: hir::BinOp,
                        lhs_expr: &'gcx hir::Expr,
-                       rhs_expr: &'gcx hir::Expr)
+                       rhs_expr: &'gcx hir::Expr) -> Ty<'tcx>
     {
         let tcx = self.tcx;
 
@@ -70,12 +72,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         self.check_expr(lhs_expr);
         let lhs_ty = self.resolve_type_vars_with_obligations(self.expr_ty(lhs_expr));
 
-        match BinOpCategory::from(op) {
+        let ty = match BinOpCategory::from(op) {
             BinOpCategory::Shortcircuit => {
                 // && and || are a simple case.
                 self.demand_suptype(lhs_expr.span, tcx.mk_bool(), lhs_ty);
                 self.check_expr_coercable_to_type(rhs_expr, tcx.mk_bool());
-                self.write_ty(expr.id, tcx.mk_bool());
+                tcx.mk_bool()
             }
             _ => {
                 // Otherwise, we always treat operators as if they are
@@ -107,9 +109,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     self.demand_suptype(expr.span, builtin_return_ty, return_ty);
                 }
 
-                self.write_ty(expr.id, return_ty);
+                return_ty
             }
-        }
+        };
+        self.write_ty(expr.id, ty)
     }
 
     fn enforce_builtin_binop_types(&self,

From b93435fd79e26e09b8aa786eb682c82ec81f0293 Mon Sep 17 00:00:00 2001
From: Andrew Cann 
Date: Wed, 10 Aug 2016 00:13:20 +0800
Subject: [PATCH 165/443] Remove most uses of expr_ty

---
 src/librustc_typeck/check/_match.rs | 20 +++----
 src/librustc_typeck/check/callee.rs |  3 +-
 src/librustc_typeck/check/mod.rs    | 85 ++++++++++++-----------------
 src/librustc_typeck/check/op.rs     |  8 +--
 4 files changed, 47 insertions(+), 69 deletions(-)

diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index 1f0faab8f2c4..2bb0abfab4ee 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -37,12 +37,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 self.write_ty(pat.id, expected);
             }
             PatKind::Lit(ref lt) => {
-                self.check_expr(<);
-                let expr_ty = self.expr_ty(<);
+                let expr_t = self.check_expr(<);
 
                 // Byte string patterns behave the same way as array patterns
                 // They can denote both statically and dynamically sized byte arrays
-                let mut pat_ty = expr_ty;
+                let mut pat_ty = expr_t;
                 if let hir::ExprLit(ref lt) = lt.node {
                     if let ast::LitKind::ByteStr(_) = lt.node {
                         let expected_ty = self.structurally_resolved_type(pat.span, expected);
@@ -63,7 +62,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 // relation at all but rather that there exists a LUB (so
                 // that they can be compared). However, in practice,
                 // constants are always scalars or strings.  For scalars
-                // subtyping is irrelevant, and for strings `expr_ty` is
+                // subtyping is irrelevant, and for strings `expr_t` is
                 // type is `&'static str`, so if we say that
                 //
                 //     &'static str <: expected
@@ -72,11 +71,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 self.demand_suptype(pat.span, expected, pat_ty);
             }
             PatKind::Range(ref begin, ref end) => {
-                self.check_expr(begin);
-                self.check_expr(end);
-
-                let lhs_ty = self.expr_ty(begin);
-                let rhs_ty = self.expr_ty(end);
+                let lhs_ty = self.check_expr(begin);
+                let rhs_ty = self.check_expr(end);
 
                 // Check that both end-points are of numeric or char type.
                 let numeric_or_char = |ty: Ty| ty.is_numeric() || ty.is_char();
@@ -385,8 +381,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                         });
         let discrim_ty;
         if let Some(m) = contains_ref_bindings {
-            self.check_expr_with_lvalue_pref(discrim, LvaluePreference::from_mutbl(m));
-            discrim_ty = self.expr_ty(discrim);
+            discrim_ty = self.check_expr_with_lvalue_pref(discrim, LvaluePreference::from_mutbl(m));
         } else {
             // ...but otherwise we want to use any supertype of the
             // discriminant. This is sort of a workaround, see note (*) in
@@ -429,8 +424,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             if let Some(ref e) = arm.guard {
                 self.check_expr_has_type(e, tcx.types.bool);
             }
-            self.check_expr_with_expectation(&arm.body, expected);
-            let arm_ty = self.expr_ty(&arm.body);
+            let arm_ty = self.check_expr_with_expectation(&arm.body, expected);
 
             if result_ty.references_error() || arm_ty.references_error() {
                 result_ty = tcx.types.err;
diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs
index 4f673606de52..bc3c5aba7100 100644
--- a/src/librustc_typeck/check/callee.rs
+++ b/src/librustc_typeck/check/callee.rs
@@ -47,8 +47,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                       arg_exprs: &'gcx [P],
                       expected: Expectation<'tcx>) -> Ty<'tcx>
     {
-        self.check_expr(callee_expr);
-        let original_callee_ty = self.expr_ty(callee_expr);
+        let original_callee_ty = self.check_expr(callee_expr);
 
         let mut autoderef = self.autoderef(callee_expr.span, original_callee_ty);
         let result = autoderef.by_ref().flat_map(|(adj_ty, idx)| {
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 5c528cc46a73..774969daf388 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -1750,13 +1750,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         self.require_type_meets(ty, span, code, ty::BoundSized);
     }
 
-    pub fn require_expr_have_sized_type(&self,
-                                        expr: &hir::Expr,
-                                        code: traits::ObligationCauseCode<'tcx>)
-    {
-        self.require_type_is_sized(self.expr_ty(expr), expr.span, code);
-    }
-
     pub fn register_builtin_bound(&self,
                                   ty: Ty<'tcx>,
                                   builtin_bound: ty::BuiltinBound,
@@ -1801,7 +1794,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                           adjustment: Option<&adjustment::AutoAdjustment<'tcx>>)
                           -> Ty<'tcx>
     {
-        let raw_ty = self.expr_ty(expr);
+        let raw_ty = self.node_ty(expr.id);
         let raw_ty = self.shallow_resolve(raw_ty);
         let resolve_ty = |ty: Ty<'tcx>| self.resolve_type_vars_if_possible(&ty);
         raw_ty.adjust(self.tcx, expr.span, expr.id, adjustment, |method_call| {
@@ -2623,12 +2616,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         // arguments which we skipped above.
         if variadic {
             for arg in args.iter().skip(expected_arg_count) {
-                self.check_expr(&arg);
+                let arg_ty = self.check_expr(&arg);
 
                 // There are a few types which get autopromoted when passed via varargs
                 // in C but we just error out instead and require explicit casts.
                 let arg_ty = self.structurally_resolved_type(arg.span,
-                                                             self.expr_ty(&arg));
+                                                             arg_ty);
                 match arg_ty.sty {
                     ty::TyFloat(ast::FloatTy::F32) => {
                         self.type_error_message(arg.span, |t| {
@@ -2718,15 +2711,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     fn check_expr_eq_type(&self,
                           expr: &'gcx hir::Expr,
                           expected: Ty<'tcx>) {
-        self.check_expr_with_hint(expr, expected);
-        self.demand_eqtype(expr.span, expected, self.expr_ty(expr));
+        let ty = self.check_expr_with_hint(expr, expected);
+        self.demand_eqtype(expr.span, expected, ty);
     }
 
     pub fn check_expr_has_type(&self,
                                expr: &'gcx hir::Expr,
                                expected: Ty<'tcx>) -> Ty<'tcx> {
         let ty = self.check_expr_with_hint(expr, expected);
-        self.demand_suptype(expr.span, expected, self.expr_ty(expr));
+        self.demand_suptype(expr.span, expected, ty);
         ty
     }
 
@@ -2821,10 +2814,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                          expected: Expectation<'tcx>,
                          lvalue_pref: LvaluePreference) -> Ty<'tcx> {
         let rcvr = &args[0];
-        self.check_expr_with_lvalue_pref(&rcvr, lvalue_pref);
+        let rcvr_t = self.check_expr_with_lvalue_pref(&rcvr, lvalue_pref);
 
         // no need to check for bot/err -- callee does that
-        let expr_t = self.structurally_resolved_type(expr.span, self.expr_ty(&rcvr));
+        let expr_t = self.structurally_resolved_type(expr.span, rcvr_t);
 
         let tps = tps.iter().map(|ast_ty| self.to_ty(&ast_ty)).collect::>();
         let fn_ty = match self.lookup_method(method_name.span,
@@ -2867,7 +2860,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                        id: ast::NodeId,
                        sp: Span,
                        expected: Expectation<'tcx>) -> Ty<'tcx> {
-        self.check_expr_has_type(cond_expr, self.tcx.types.bool);
+        let cond_ty = self.check_expr_has_type(cond_expr, self.tcx.types.bool);
 
         let expected = expected.adjust_for_branches(self);
         self.check_block_with_expected(then_blk, expected);
@@ -2876,8 +2869,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         let unit = self.tcx.mk_nil();
         let (origin, expected, found, result) =
         if let Some(else_expr) = opt_else_expr {
-            self.check_expr_with_expectation(else_expr, expected);
-            let else_ty = self.expr_ty(else_expr);
+            let else_ty = self.check_expr_with_expectation(else_expr, expected);
             let origin = TypeOrigin::IfExpression(sp);
 
             // Only try to coerce-unify if we have a then expression
@@ -2919,7 +2911,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
         let if_ty = match result {
             Ok(ty) => {
-                if self.expr_ty(cond_expr).references_error() {
+                if cond_ty.references_error() {
                     self.tcx.types.err
                 } else {
                     ty
@@ -2940,9 +2932,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                    lvalue_pref: LvaluePreference,
                    base: &'gcx hir::Expr,
                    field: &Spanned) -> Ty<'tcx> {
-        self.check_expr_with_lvalue_pref(base, lvalue_pref);
+        let expr_t = self.check_expr_with_lvalue_pref(base, lvalue_pref);
         let expr_t = self.structurally_resolved_type(expr.span,
-                                                     self.expr_ty(base));
+                                                     expr_t);
         let mut private_candidate = None;
         let mut autoderef = self.autoderef(expr.span, expr_t);
         while let Some((base_t, autoderefs)) = autoderef.next() {
@@ -3038,9 +3030,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                        lvalue_pref: LvaluePreference,
                        base: &'gcx hir::Expr,
                        idx: codemap::Spanned) -> Ty<'tcx> {
-        self.check_expr_with_lvalue_pref(base, lvalue_pref);
+        let expr_t = self.check_expr_with_lvalue_pref(base, lvalue_pref);
         let expr_t = self.structurally_resolved_type(expr.span,
-                                                     self.expr_ty(base));
+                                                     expr_t);
         let mut private_candidate = None;
         let mut tuple_like = false;
         let mut autoderef = self.autoderef(expr.span, expr_t);
@@ -3272,18 +3264,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                          base_expr: &'gcx Option>) -> Ty<'tcx>
     {
         // Find the relevant variant
-        let (variant, expr_ty) = if let Some(variant_ty) = self.check_struct_path(path, expr.id,
+        let (variant, expr_t) = if let Some(variant_ty) = self.check_struct_path(path, expr.id,
                                                                                   expr.span) {
             variant_ty
         } else {
             return self.check_struct_fields_on_error(expr.id, fields, base_expr);
         };
 
-        self.check_expr_struct_fields(expr_ty, path.span, variant, fields,
+        self.check_expr_struct_fields(expr_t, path.span, variant, fields,
                                       base_expr.is_none());
         if let &Some(ref base_expr) = base_expr {
-            self.check_expr_has_type(base_expr, expr_ty);
-            match expr_ty.sty {
+            self.check_expr_has_type(base_expr, expr_t);
+            match expr_t.sty {
                 ty::TyStruct(adt, substs) => {
                     self.tables.borrow_mut().fru_field_types.insert(
                         expr.id,
@@ -3300,7 +3292,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 }
             }
         }
-        expr_ty
+        expr_t
     }
 
 
@@ -3331,8 +3323,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     _ => NoExpectation
                 }
             });
-            self.check_expr_with_expectation(subexpr, expected_inner);
-            let referent_ty = self.expr_ty(&subexpr);
+            let referent_ty = self.check_expr_with_expectation(subexpr, expected_inner);
             self.write_ty(id, tcx.mk_box(referent_ty))
           }
 
@@ -3510,7 +3501,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
             let rhs_ty = self.check_expr_coercable_to_type(&rhs, lhs_ty);
 
-            self.require_expr_have_sized_type(&lhs, traits::AssignmentLhsSized);
+            self.require_type_is_sized(lhs_ty, lhs.span, traits::AssignmentLhsSized);
 
             if lhs_ty.references_error() || rhs_ty.references_error() {
                 self.write_error(id)
@@ -3523,9 +3514,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                  id, expr.span, expected)
           }
           hir::ExprWhile(ref cond, ref body, _) => {
-            self.check_expr_has_type(&cond, tcx.types.bool);
+            let cond_ty = self.check_expr_has_type(&cond, tcx.types.bool);
             self.check_block_no_value(&body);
-            let cond_ty = self.expr_ty(&cond);
             let body_ty = self.node_ty(body.id);
             if cond_ty.references_error() || body_ty.references_error() {
                 self.write_error(id)
@@ -3714,7 +3704,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
           hir::ExprStruct(ref path, ref fields, ref base_expr) => {
             let ty = self.check_expr_struct(expr, path, fields, base_expr);
 
-            self.require_expr_have_sized_type(expr, traits::StructInitializerSized);
+            self.require_type_is_sized(ty, expr.span, traits::StructInitializerSized);
             ty
           }
           hir::ExprField(ref base, ref field) => {
@@ -3735,8 +3725,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                   let base_t = self.structurally_resolved_type(expr.span, base_t);
                   match self.lookup_indexing(expr, base, base_t, idx_t, lvalue_pref) {
                       Some((index_ty, element_ty)) => {
-                          let idx_expr_ty = self.expr_ty(idx);
-                          self.demand_eqtype(expr.span, index_ty, idx_expr_ty);
+                          self.demand_eqtype(expr.span, index_ty, idx_t);
                           self.write_ty(id, element_ty)
                       }
                       None => {
@@ -3865,7 +3854,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
     pub fn check_decl_initializer(&self,
                                   local: &'gcx hir::Local,
-                                  init: &'gcx hir::Expr)
+                                  init: &'gcx hir::Expr) -> Ty<'tcx>
     {
         let ref_bindings = self.tcx.pat_contains_ref_binding(&local.pat);
 
@@ -3884,7 +3873,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             init_ty
         } else {
             self.check_expr_coercable_to_type(init, local_ty)
-        };
+        }
     }
 
     pub fn check_decl_local(&self, local: &'gcx hir::Local)  {
@@ -3892,8 +3881,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         self.write_ty(local.id, t);
 
         if let Some(ref init) = local.init {
-            self.check_decl_initializer(local, &init);
-            let init_ty = self.expr_ty(&init);
+            let init_ty = self.check_decl_initializer(local, &init);
             if init_ty.references_error() {
                 self.write_ty(local.id, init_ty);
             }
@@ -3926,17 +3914,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
           hir::StmtExpr(ref expr, id) => {
             node_id = id;
             // Check with expected type of ()
-            self.check_expr_has_type(&expr, self.tcx.mk_nil());
-            let expr_ty = self.expr_ty(&expr);
-            saw_bot = saw_bot || self.type_var_diverges(expr_ty);
-            saw_err = saw_err || expr_ty.references_error();
+            let expr_t = self.check_expr_has_type(&expr, self.tcx.mk_nil());
+            saw_bot = saw_bot || self.type_var_diverges(expr_t);
+            saw_err = saw_err || expr_t.references_error();
           }
           hir::StmtSemi(ref expr, id) => {
             node_id = id;
-            self.check_expr(&expr);
-            let expr_ty = self.expr_ty(&expr);
-            saw_bot |= self.type_var_diverges(expr_ty);
-            saw_err |= expr_ty.references_error();
+            let expr_t = self.check_expr(&expr);
+            saw_bot |= self.type_var_diverges(expr_t);
+            saw_err |= expr_t.references_error();
           }
         }
         if saw_bot {
@@ -4023,8 +4009,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                         ety
                     }
                     _ => {
-                        self.check_expr_with_expectation(&e, expected);
-                        self.expr_ty(&e)
+                        self.check_expr_with_expectation(&e, expected)
                     }
                 };
 
diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs
index feb3258c88c2..5462826ef904 100644
--- a/src/librustc_typeck/check/op.rs
+++ b/src/librustc_typeck/check/op.rs
@@ -25,9 +25,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                               lhs_expr: &'gcx hir::Expr,
                               rhs_expr: &'gcx hir::Expr) -> Ty<'tcx>
     {
-        self.check_expr_with_lvalue_pref(lhs_expr, PreferMutLvalue);
+        let lhs_ty = self.check_expr_with_lvalue_pref(lhs_expr, PreferMutLvalue);
 
-        let lhs_ty = self.resolve_type_vars_with_obligations(self.expr_ty(lhs_expr));
+        let lhs_ty = self.resolve_type_vars_with_obligations(lhs_ty);
         let (rhs_ty, return_ty) =
             self.check_overloaded_binop(expr, lhs_expr, lhs_ty, rhs_expr, op, IsAssign::Yes);
         let rhs_ty = self.resolve_type_vars_with_obligations(rhs_ty);
@@ -69,8 +69,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                lhs_expr,
                rhs_expr);
 
-        self.check_expr(lhs_expr);
-        let lhs_ty = self.resolve_type_vars_with_obligations(self.expr_ty(lhs_expr));
+        let lhs_ty = self.check_expr(lhs_expr);
+        let lhs_ty = self.resolve_type_vars_with_obligations(lhs_ty);
 
         let ty = match BinOpCategory::from(op) {
             BinOpCategory::Shortcircuit => {

From c7ea3e8d134b941a0ed2f3d6b535649d081bf92d Mon Sep 17 00:00:00 2001
From: Andrew Cann 
Date: Thu, 18 Aug 2016 14:21:13 +0800
Subject: [PATCH 166/443] Remove redundant error checking around ExprMethodCall

---
 src/librustc_typeck/check/mod.rs | 10 +---------
 1 file changed, 1 insertion(+), 9 deletions(-)

diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 774969daf388..df789897bf15 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -3551,15 +3551,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
               ret_ty
           }
           hir::ExprMethodCall(name, ref tps, ref args) => {
-              let ty = self.check_method_call(expr, name, &args[..], &tps[..], expected, lvalue_pref);
-              let arg_tys = args.iter().map(|a| self.expr_ty(&a));
-              let args_err = arg_tys.fold(false, |rest_err, a| rest_err || a.references_error());
-              if args_err {
-                  self.write_error(id)
-              }
-              else {
-                  ty
-              }
+              self.check_method_call(expr, name, &args[..], &tps[..], expected, lvalue_pref)
           }
           hir::ExprCast(ref e, ref t) => {
             if let hir::TyFixedLengthVec(_, ref count_expr) = t.node {

From 06ad8fe261aae7b58b70be58f6a3ac6d5d9d2328 Mon Sep 17 00:00:00 2001
From: Andrew Cann 
Date: Thu, 18 Aug 2016 17:16:42 +0800
Subject: [PATCH 167/443] Factor write_ty out of check_binop*

---
 src/librustc_typeck/check/mod.rs | 6 ++++--
 src/librustc_typeck/check/op.rs  | 6 ++----
 2 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index df789897bf15..7a5b2bdeb163 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -3332,10 +3332,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             self.write_ty(id, typ)
           }
           hir::ExprBinary(op, ref lhs, ref rhs) => {
-            self.check_binop(expr, op, lhs, rhs)
+            let ty = self.check_binop(expr, op, lhs, rhs);
+            self.write_ty(id, ty)
           }
           hir::ExprAssignOp(op, ref lhs, ref rhs) => {
-            self.check_binop_assign(expr, op, lhs, rhs)
+            let ty = self.check_binop_assign(expr, op, lhs, rhs);
+            self.write_ty(id, ty)
           }
           hir::ExprUnary(unop, ref oprnd) => {
             let expected_inner = match unop {
diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs
index 5462826ef904..af7e12bd48dc 100644
--- a/src/librustc_typeck/check/op.rs
+++ b/src/librustc_typeck/check/op.rs
@@ -38,7 +38,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         } else {
             return_ty
         };
-        let ty = self.write_ty(expr.id, ty);
 
         let tcx = self.tcx;
         if !tcx.expr_is_lval(lhs_expr) {
@@ -72,7 +71,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         let lhs_ty = self.check_expr(lhs_expr);
         let lhs_ty = self.resolve_type_vars_with_obligations(lhs_ty);
 
-        let ty = match BinOpCategory::from(op) {
+        match BinOpCategory::from(op) {
             BinOpCategory::Shortcircuit => {
                 // && and || are a simple case.
                 self.demand_suptype(lhs_expr.span, tcx.mk_bool(), lhs_ty);
@@ -111,8 +110,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
                 return_ty
             }
-        };
-        self.write_ty(expr.id, ty)
+        }
     }
 
     fn enforce_builtin_binop_types(&self,

From 91b39b5e65ac66f85bc6be749593690417d0373e Mon Sep 17 00:00:00 2001
From: Andrew Cann 
Date: Thu, 18 Aug 2016 21:09:21 +0800
Subject: [PATCH 168/443] Factor write_ty out of more checking functions

---
 src/librustc_typeck/check/_match.rs |  6 ++++--
 src/librustc_typeck/check/mod.rs    | 27 +++++++++++----------------
 2 files changed, 15 insertions(+), 18 deletions(-)

diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index 2bb0abfab4ee..b69afbf8ff03 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -473,8 +473,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 }
             };
         }
-
-        self.write_ty(expr.id, result_ty)
+        
+        result_ty
     }
 }
 
@@ -545,6 +545,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
         // Type check the path.
         let pat_ty = self.instantiate_value_path(segments, opt_ty, def, pat.span, pat.id);
+        self.write_ty(pat.id, pat_ty);
         self.demand_suptype(pat.span, expected, pat_ty);
     }
 
@@ -603,6 +604,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
         // Type check the path.
         let pat_ty = self.instantiate_value_path(segments, opt_ty, def, pat.span, pat.id);
+        self.write_ty(pat.id, pat_ty);
 
         let pat_ty = if pat_ty.is_fn() {
             // Replace constructor type with constructed type for tuple struct patterns.
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 7a5b2bdeb163..4d5160a4de6b 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -2857,7 +2857,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                        cond_expr: &'gcx hir::Expr,
                        then_blk: &'gcx hir::Block,
                        opt_else_expr: Option<&'gcx hir::Expr>,
-                       id: ast::NodeId,
                        sp: Span,
                        expected: Expectation<'tcx>) -> Ty<'tcx> {
         let cond_ty = self.check_expr_has_type(cond_expr, self.tcx.types.bool);
@@ -2909,7 +2908,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                  }))
         };
 
-        let if_ty = match result {
+        match result {
             Ok(ty) => {
                 if cond_ty.references_error() {
                     self.tcx.types.err
@@ -2921,9 +2920,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 self.report_mismatched_types(origin, expected, found, e);
                 self.tcx.types.err
             }
-        };
-
-        self.write_ty(id, if_ty)
+        }
     }
 
     // Check field access expressions
@@ -3447,7 +3444,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                   self.instantiate_value_path(segments, opt_ty, def, expr.span, id)
               } else {
                   self.set_tainted_by_errors();
-                  self.write_error(id)
+                  tcx.types.err
               };
 
               // We always require that the type provided as the value for
@@ -3455,7 +3452,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
               self.opt_node_ty_substs(expr.id, |item_substs| {
                   self.add_wf_bounds(&item_substs.substs, expr);
               });
-              ty
+
+              self.write_ty(id, ty)
           }
           hir::ExprInlineAsm(_, ref outputs, ref inputs) => {
               for output in outputs {
@@ -3512,8 +3510,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             }
           }
           hir::ExprIf(ref cond, ref then_blk, ref opt_else_expr) => {
-            self.check_then_else(&cond, &then_blk, opt_else_expr.as_ref().map(|e| &**e),
-                                 id, expr.span, expected)
+            let if_ty = self.check_then_else(&cond, &then_blk, opt_else_expr.as_ref().map(|e| &**e),
+                                 expr.span, expected);
+            self.write_ty(id, if_ty)
           }
           hir::ExprWhile(ref cond, ref body, _) => {
             let cond_ty = self.check_expr_has_type(&cond, tcx.types.bool);
@@ -3535,7 +3534,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             }
           }
           hir::ExprMatch(ref discrim, ref arms, match_src) => {
-            self.check_match(expr, &discrim, arms, expected, match_src)
+            let result_ty = self.check_match(expr, &discrim, arms, expected, match_src);
+            self.write_ty(expr.id, result_ty)
           }
           hir::ExprClosure(capture, ref decl, ref body, _) => {
               self.check_expr_closure(expr, capture, &decl, &body, expected)
@@ -3571,16 +3571,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             if t_expr.references_error() || t_cast.references_error() {
                 self.write_error(id)
             } else {
-                // Write a type for the whole expression, assuming everything is going
-                // to work out Ok.
-                let ty = self.write_ty(id, t_cast);
-
                 // Defer other checks until we're done type checking.
                 let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut();
                 match cast::CastCheck::new(self, e, t_expr, t_cast, t.span, expr.span) {
                     Ok(cast_check) => {
                         deferred_cast_checks.push(cast_check);
-                        ty
+                        self.write_ty(id, t_cast)
                     }
                     Err(ErrorReported) => {
                         self.write_error(id)
@@ -4328,7 +4324,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         debug!("instantiate_value_path: type of {:?} is {:?}",
                node_id,
                ty_substituted);
-        self.write_ty(node_id, ty_substituted);
         self.write_substs(node_id, ty::ItemSubsts {
             substs: substs
         });

From f22dd2e2d9f29869ff7956cecb5a616ce50e3e89 Mon Sep 17 00:00:00 2001
From: Andrew Cann 
Date: Thu, 18 Aug 2016 22:07:57 +0800
Subject: [PATCH 169/443] Factor write_ty out of field/indexing methods

---
 src/librustc_typeck/check/mod.rs | 38 ++++++++++++++++----------------
 1 file changed, 19 insertions(+), 19 deletions(-)

diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 4d5160a4de6b..30f4202fccbf 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -2942,9 +2942,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                         let field_ty = self.field_ty(expr.span, field, substs);
                         if field.vis.is_accessible_from(self.body_id, &self.tcx().map) {
                             autoderef.finalize(lvalue_pref, Some(base));
-                            let ty = self.write_ty(expr.id, field_ty);
                             self.write_autoderef_adjustment(base.id, autoderefs);
-                            return ty;
+                            return field_ty;
                         }
                         private_candidate = Some((base_def.did, field_ty));
                     }
@@ -2956,7 +2955,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
         if let Some((did, field_ty)) = private_candidate {
             let struct_path = self.tcx().item_path_str(did);
-            let ty = self.write_ty(expr.id, field_ty);
             let msg = format!("field `{}` of struct `{}` is private", field.node, struct_path);
             let mut err = self.tcx().sess.struct_span_err(expr.span, &msg);
             // Also check if an accessible method exists, which is often what is meant.
@@ -2965,9 +2963,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                   field.node));
             }
             err.emit();
-            ty
+            field_ty
         } else if field.node == keywords::Invalid.name() {
-            self.write_error(expr.id)
+            self.tcx().types.err
         } else if self.method_exists(field.span, field.node, expr_t, expr.id, true) {
             self.type_error_struct(field.span, |actual| {
                 format!("attempted to take value of method `{}` on type \
@@ -2976,7 +2974,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 .help("maybe a `()` to call it is missing? \
                        If not, try an anonymous function")
                 .emit();
-            self.write_error(expr.id)
+            self.tcx().types.err
         } else {
             let mut err = self.type_error_struct(expr.span, |actual| {
                 format!("attempted access of field `{}` on type `{}`, \
@@ -2994,7 +2992,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 _ => {}
             }
             err.emit();
-            self.write_error(expr.id)
+            self.tcx().types.err
         }
     }
 
@@ -3059,9 +3057,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
             if let Some(field_ty) = field {
                 autoderef.finalize(lvalue_pref, Some(base));
-                let ty = self.write_ty(expr.id, field_ty);
                 self.write_autoderef_adjustment(base.id, autoderefs);
-                return ty;
+                return field_ty;
             }
         }
         autoderef.unambiguous_final_ty();
@@ -3070,7 +3067,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             let struct_path = self.tcx().item_path_str(did);
             let msg = format!("field `{}` of struct `{}` is private", idx.node, struct_path);
             self.tcx().sess.span_err(expr.span, &msg);
-            return self.write_ty(expr.id, field_ty)
+            return field_ty;
         }
 
         self.type_error_message(
@@ -3090,7 +3087,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             },
             expr_t);
 
-        self.write_error(expr.id)
+        self.tcx().types.err
     }
 
     fn report_unknown_field(&self,
@@ -3698,25 +3695,27 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             ty
           }
           hir::ExprField(ref base, ref field) => {
-            self.check_field(expr, lvalue_pref, &base, field)
+            let ty = self.check_field(expr, lvalue_pref, &base, field);
+            self.write_ty(id, ty)
           }
           hir::ExprTupField(ref base, idx) => {
-            self.check_tup_field(expr, lvalue_pref, &base, idx)
+            let ty = self.check_tup_field(expr, lvalue_pref, &base, idx);
+            self.write_ty(id, ty)
           }
           hir::ExprIndex(ref base, ref idx) => {
               let base_t = self.check_expr_with_lvalue_pref(&base, lvalue_pref);
               let idx_t = self.check_expr(&idx);
 
-              if base_t.references_error() {
-                  self.write_ty(id, base_t)
+              let ty = if base_t.references_error() {
+                  base_t
               } else if idx_t.references_error() {
-                  self.write_ty(id, idx_t)
+                  idx_t
               } else {
                   let base_t = self.structurally_resolved_type(expr.span, base_t);
                   match self.lookup_indexing(expr, base, base_t, idx_t, lvalue_pref) {
                       Some((index_ty, element_ty)) => {
                           self.demand_eqtype(expr.span, index_ty, idx_t);
-                          self.write_ty(id, element_ty)
+                          element_ty
                       }
                       None => {
                           self.check_expr_has_type(&idx, self.tcx.types.err);
@@ -3752,10 +3751,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                               }
                           }
                           err.emit();
-                          self.write_ty(id, self.tcx().types.err)
+                          self.tcx().types.err
                       }
                   }
-              }
+              };
+              self.write_ty(id, ty)
            }
         };
 

From 144b8cf5db99df4f6132f1ac5b59184f8907965d Mon Sep 17 00:00:00 2001
From: Andrew Cann 
Date: Thu, 18 Aug 2016 22:51:01 +0800
Subject: [PATCH 170/443] Factor write_ty out of check_struct_expr

---
 src/librustc_typeck/check/_match.rs |  1 +
 src/librustc_typeck/check/mod.rs    | 16 +++++-----------
 2 files changed, 6 insertions(+), 11 deletions(-)

diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index b69afbf8ff03..838cf36b8853 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -497,6 +497,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             }
             return;
         };
+        self.write_ty(pat.id, pat_ty);
 
         // Type check the path.
         self.demand_eqtype(pat.span, expected, pat_ty);
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 30f4202fccbf..f70d7c577486 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -1711,7 +1711,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         self.add_obligations_for_parameters(cause, &bounds);
 
         let ty_substituted = self.instantiate_type_scheme(path.span, substs, &ty);
-        self.write_ty(node_id, ty_substituted);
         self.write_substs(node_id, ty::ItemSubsts {
             substs: substs
         });
@@ -3190,12 +3189,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     }
 
     fn check_struct_fields_on_error(&self,
-                                    id: ast::NodeId,
                                     fields: &'gcx [hir::Field],
-                                    base_expr: &'gcx Option>) -> Ty<'tcx> {
-        // Make sure to still write the types
-        // otherwise we might ICE
-        let ty = self.write_error(id);
+                                    base_expr: &'gcx Option>) {
         for field in fields {
             self.check_expr(&field.expr);
         }
@@ -3205,7 +3200,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             },
             None => {}
         }
-        ty
     }
 
     pub fn check_struct_path(&self,
@@ -3262,7 +3256,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                                                                   expr.span) {
             variant_ty
         } else {
-            return self.check_struct_fields_on_error(expr.id, fields, base_expr);
+            self.check_struct_fields_on_error(fields, base_expr);
+            return self.tcx().types.err;
         };
 
         self.check_expr_struct_fields(expr_t, path.span, variant, fields,
@@ -3286,6 +3281,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 }
             }
         }
+        self.require_type_is_sized(expr_t, expr.span, traits::StructInitializerSized);
         expr_t
     }
 
@@ -3690,9 +3686,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
           }
           hir::ExprStruct(ref path, ref fields, ref base_expr) => {
             let ty = self.check_expr_struct(expr, path, fields, base_expr);
-
-            self.require_type_is_sized(ty, expr.span, traits::StructInitializerSized);
-            ty
+            self.write_ty(id, ty)
           }
           hir::ExprField(ref base, ref field) => {
             let ty = self.check_field(expr, lvalue_pref, &base, field);

From 21720641dc4d3b921eb5be2a4c66900003a742dd Mon Sep 17 00:00:00 2001
From: Andrew Cann 
Date: Thu, 18 Aug 2016 23:30:11 +0800
Subject: [PATCH 171/443] Factor write_ty out of check_expr_closure

---
 src/librustc_typeck/check/closure.rs | 4 +---
 src/librustc_typeck/check/mod.rs     | 3 ++-
 2 files changed, 3 insertions(+), 4 deletions(-)

diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs
index 1f4201aa39cd..9e41d1b5676e 100644
--- a/src/librustc_typeck/check/closure.rs
+++ b/src/librustc_typeck/check/closure.rs
@@ -70,8 +70,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             self.parameter_environment.free_substs,
             upvar_tys);
 
-        let ty = self.write_ty(expr.id, closure_type);
-
         let fn_sig = self.tcx.liberate_late_bound_regions(
             self.tcx.region_maps.call_site_extent(expr.id, body.id), &fn_ty.sig);
         let fn_sig =
@@ -94,7 +92,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             None => { }
         }
 
-        ty
+        closure_type
     }
 
     fn deduce_expectations_from_expected_type(&self, expected_ty: Ty<'tcx>)
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index f70d7c577486..4c400f1092c5 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -3531,7 +3531,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             self.write_ty(expr.id, result_ty)
           }
           hir::ExprClosure(capture, ref decl, ref body, _) => {
-              self.check_expr_closure(expr, capture, &decl, &body, expected)
+              let ty = self.check_expr_closure(expr, capture, &decl, &body, expected);
+              self.write_ty(id, ty)
           }
           hir::ExprBlock(ref b) => {
             self.check_block_with_expected(&b, expected);

From 9cd8d7a24f73e7de91cc3ba4461eeb6fe8a086f3 Mon Sep 17 00:00:00 2001
From: Andrew Cann 
Date: Thu, 18 Aug 2016 23:52:05 +0800
Subject: [PATCH 172/443] Factor write_ty out of function checking functions

---
 src/librustc_typeck/check/callee.rs | 18 +++++++++++-------
 src/librustc_typeck/check/mod.rs    | 10 ++++------
 2 files changed, 15 insertions(+), 13 deletions(-)

diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs
index bc3c5aba7100..5bd4f13a1119 100644
--- a/src/librustc_typeck/check/callee.rs
+++ b/src/librustc_typeck/check/callee.rs
@@ -15,7 +15,7 @@ use CrateCtxt;
 use middle::cstore::LOCAL_CRATE;
 use hir::def::Def;
 use hir::def_id::DefId;
-use rustc::infer;
+use rustc::{infer, traits};
 use rustc::ty::{self, LvaluePreference, Ty};
 use syntax::parse::token;
 use syntax::ptr::P;
@@ -56,7 +56,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         let callee_ty = autoderef.unambiguous_final_ty();
         autoderef.finalize(LvaluePreference::NoPreference, Some(callee_expr));
 
-        match result {
+        let output = match result {
             None => {
                 // this will report an error since original_callee_ty is not a fn
                 self.confirm_builtin_call(call_expr, original_callee_ty, arg_exprs, expected)
@@ -74,7 +74,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 self.confirm_overloaded_call(call_expr, callee_expr,
                                              arg_exprs, expected, method_callee)
             }
-        }
+        };
+
+        // we must check that return type of called functions is WF:
+        self.register_wf_obligation(output, call_expr.span, traits::MiscObligation);
+
+        output
     }
 
     fn try_overloaded_call_step(&self,
@@ -244,7 +249,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                   fn_sig.variadic,
                                   TupleArgumentsFlag::DontTupleArguments);
 
-        self.write_ty(call_expr.id, fn_sig.output)
+        fn_sig.output
     }
 
     fn confirm_deferred_closure_call(&self,
@@ -271,7 +276,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                   fn_sig.variadic,
                                   TupleArgumentsFlag::TupleArguments);
 
-        self.write_ty(call_expr.id, fn_sig.output)
+        fn_sig.output
     }
 
     fn confirm_overloaded_call(&self,
@@ -288,10 +293,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                              arg_exprs,
                                              TupleArgumentsFlag::TupleArguments,
                                              expected);
-        let ty = self.write_ty(call_expr.id, output_type);
 
         self.write_overloaded_call_method_map(call_expr, method_callee);
-        ty
+        output_type
     }
 
     fn write_overloaded_call_method_map(&self,
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 4c400f1092c5..8406b491737e 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -2847,7 +2847,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                                       DontTupleArguments,
                                                       expected);
 
-        self.write_ty(expr.id, ret_ty)
+        ret_ty
     }
 
     // A generic function for checking the then and else in an if
@@ -3541,13 +3541,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
           }
           hir::ExprCall(ref callee, ref args) => {
               let ret_ty = self.check_call(expr, &callee, &args[..], expected);
-
-              // we must check that return type of called functions is WF:
-              self.register_wf_obligation(ret_ty, expr.span, traits::MiscObligation);
-              ret_ty
+              self.write_ty(id, ret_ty)
           }
           hir::ExprMethodCall(name, ref tps, ref args) => {
-              self.check_method_call(expr, name, &args[..], &tps[..], expected, lvalue_pref)
+              let ret_ty = self.check_method_call(expr, name, &args[..], &tps[..], expected, lvalue_pref);
+              self.write_ty(id, ret_ty)
           }
           hir::ExprCast(ref e, ref t) => {
             if let hir::TyFixedLengthVec(_, ref count_expr) = t.node {

From adb19ff277262ce629e092feabdc5f5f5a2ac408 Mon Sep 17 00:00:00 2001
From: Andrew Cann 
Date: Fri, 19 Aug 2016 00:13:15 +0800
Subject: [PATCH 173/443] Add AdjustNeverToAny in check_expr

---
 src/librustc_typeck/check/mod.rs | 130 ++++++++++++++-----------------
 1 file changed, 57 insertions(+), 73 deletions(-)

diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 8406b491737e..2a12b7055d4e 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -1530,21 +1530,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     }
 
     #[inline]
-    pub fn write_ty(&self, node_id: ast::NodeId, ty: Ty<'tcx>) -> Ty<'tcx> {
+    pub fn write_ty(&self, node_id: ast::NodeId, ty: Ty<'tcx>) {
         debug!("write_ty({}, {:?}) in fcx {}",
                node_id, ty, self.tag());
         self.tables.borrow_mut().node_types.insert(node_id, ty);
-
-        // Add adjustments to !-expressions
-        if ty.is_never() {
-            if let Some(hir::map::NodeExpr(_)) = self.tcx.map.find(node_id) {
-                let adj_ty = self.next_diverging_ty_var();
-                let adj = adjustment::AdjustNeverToAny(adj_ty);
-                self.write_adjustment(node_id, adj);
-                return adj_ty;
-            }
-        }
-        ty
     }
 
     pub fn write_substs(&self, node_id: ast::NodeId, substs: ty::ItemSubsts<'tcx>) {
@@ -1717,16 +1706,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         ty_substituted
     }
 
-    pub fn write_nil(&self, node_id: ast::NodeId) -> Ty<'tcx> {
-        self.write_ty(node_id, self.tcx.mk_nil())
+    pub fn write_nil(&self, node_id: ast::NodeId) {
+        self.write_ty(node_id, self.tcx.mk_nil());
     }
 
-    pub fn write_never(&self, node_id: ast::NodeId) -> Ty<'tcx> {
-        self.write_ty(node_id, self.tcx.types.never)
+    pub fn write_never(&self, node_id: ast::NodeId) {
+        self.write_ty(node_id, self.tcx.types.never);
     }
 
-    pub fn write_error(&self, node_id: ast::NodeId) -> Ty<'tcx> {
-        self.write_ty(node_id, self.tcx.types.err)
+    pub fn write_error(&self, node_id: ast::NodeId) {
+        self.write_ty(node_id, self.tcx.types.err);
     }
 
     pub fn require_type_meets(&self,
@@ -3314,20 +3303,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 }
             });
             let referent_ty = self.check_expr_with_expectation(subexpr, expected_inner);
-            self.write_ty(id, tcx.mk_box(referent_ty))
+            tcx.mk_box(referent_ty)
           }
 
           hir::ExprLit(ref lit) => {
-            let typ = self.check_lit(&lit, expected);
-            self.write_ty(id, typ)
+            self.check_lit(&lit, expected)
           }
           hir::ExprBinary(op, ref lhs, ref rhs) => {
-            let ty = self.check_binop(expr, op, lhs, rhs);
-            self.write_ty(id, ty)
+            self.check_binop(expr, op, lhs, rhs)
           }
           hir::ExprAssignOp(op, ref lhs, ref rhs) => {
-            let ty = self.check_binop_assign(expr, op, lhs, rhs);
-            self.write_ty(id, ty)
+            self.check_binop_assign(expr, op, lhs, rhs)
           }
           hir::ExprUnary(unop, ref oprnd) => {
             let expected_inner = match unop {
@@ -3386,7 +3372,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     }
                 }
             }
-            self.write_ty(id, oprnd_t)
+            oprnd_t
           }
           hir::ExprAddrOf(mutbl, ref oprnd) => {
             let hint = expected.only_has_type(self).map_or(NoExpectation, |ty| {
@@ -3408,7 +3394,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             let ty = self.check_expr_with_expectation_and_lvalue_pref(&oprnd, hint, lvalue_pref);
 
             let tm = ty::TypeAndMut { ty: ty, mutbl: mutbl };
-            let oprnd_t = if tm.ty.references_error() {
+            if tm.ty.references_error() {
                 tcx.types.err
             } else {
                 // Note: at this point, we cannot say what the best lifetime
@@ -3426,8 +3412,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 // as long as it needs to live.
                 let region = self.next_region_var(infer::AddrOfRegion(expr.span));
                 tcx.mk_ref(region, tm)
-            };
-            self.write_ty(id, oprnd_t)
+            }
           }
           hir::ExprPath(ref opt_qself, ref path) => {
               let opt_self_ty = opt_qself.as_ref().map(|qself| self.to_ty(&qself.ty));
@@ -3446,7 +3431,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                   self.add_wf_bounds(&item_substs.substs, expr);
               });
 
-              self.write_ty(id, ty)
+              ty
           }
           hir::ExprInlineAsm(_, ref outputs, ref inputs) => {
               for output in outputs {
@@ -3455,10 +3440,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
               for input in inputs {
                   self.check_expr(input);
               }
-              self.write_nil(id)
+              tcx.mk_nil()
           }
-          hir::ExprBreak(_) => { self.write_never(id) }
-          hir::ExprAgain(_) => { self.write_never(id) }
+          hir::ExprBreak(_) => { tcx.types.never }
+          hir::ExprAgain(_) => { tcx.types.never }
           hir::ExprRet(ref expr_opt) => {
             if let Some(ref e) = *expr_opt {
                 self.check_expr_coercable_to_type(&e, self.ret_ty);
@@ -3476,7 +3461,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                         .emit();
                 }
             }
-            self.write_never(id)
+            tcx.types.never
           }
           hir::ExprAssign(ref lhs, ref rhs) => {
             let lhs_ty = self.check_expr_with_lvalue_pref(&lhs, PreferMutLvalue);
@@ -3497,55 +3482,49 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             self.require_type_is_sized(lhs_ty, lhs.span, traits::AssignmentLhsSized);
 
             if lhs_ty.references_error() || rhs_ty.references_error() {
-                self.write_error(id)
+                tcx.types.err
             } else {
-                self.write_nil(id)
+                tcx.mk_nil()
             }
           }
           hir::ExprIf(ref cond, ref then_blk, ref opt_else_expr) => {
-            let if_ty = self.check_then_else(&cond, &then_blk, opt_else_expr.as_ref().map(|e| &**e),
-                                 expr.span, expected);
-            self.write_ty(id, if_ty)
+            self.check_then_else(&cond, &then_blk, opt_else_expr.as_ref().map(|e| &**e),
+                                 expr.span, expected)
           }
           hir::ExprWhile(ref cond, ref body, _) => {
             let cond_ty = self.check_expr_has_type(&cond, tcx.types.bool);
             self.check_block_no_value(&body);
             let body_ty = self.node_ty(body.id);
             if cond_ty.references_error() || body_ty.references_error() {
-                self.write_error(id)
+                tcx.types.err
             }
             else {
-                self.write_nil(id)
+                tcx.mk_nil()
             }
           }
           hir::ExprLoop(ref body, _) => {
             self.check_block_no_value(&body);
             if !may_break(tcx, expr.id, &body) {
-                self.write_never(id)
+                tcx.types.never
             } else {
-                self.write_nil(id)
+                tcx.mk_nil()
             }
           }
           hir::ExprMatch(ref discrim, ref arms, match_src) => {
-            let result_ty = self.check_match(expr, &discrim, arms, expected, match_src);
-            self.write_ty(expr.id, result_ty)
+            self.check_match(expr, &discrim, arms, expected, match_src)
           }
           hir::ExprClosure(capture, ref decl, ref body, _) => {
-              let ty = self.check_expr_closure(expr, capture, &decl, &body, expected);
-              self.write_ty(id, ty)
+              self.check_expr_closure(expr, capture, &decl, &body, expected)
           }
           hir::ExprBlock(ref b) => {
             self.check_block_with_expected(&b, expected);
-            let ty = self.node_ty(b.id);
-            self.write_ty(id, ty)
+            self.node_ty(b.id)
           }
           hir::ExprCall(ref callee, ref args) => {
-              let ret_ty = self.check_call(expr, &callee, &args[..], expected);
-              self.write_ty(id, ret_ty)
+              self.check_call(expr, &callee, &args[..], expected)
           }
           hir::ExprMethodCall(name, ref tps, ref args) => {
-              let ret_ty = self.check_method_call(expr, name, &args[..], &tps[..], expected, lvalue_pref);
-              self.write_ty(id, ret_ty)
+              self.check_method_call(expr, name, &args[..], &tps[..], expected, lvalue_pref)
           }
           hir::ExprCast(ref e, ref t) => {
             if let hir::TyFixedLengthVec(_, ref count_expr) = t.node {
@@ -3561,17 +3540,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
             // Eagerly check for some obvious errors.
             if t_expr.references_error() || t_cast.references_error() {
-                self.write_error(id)
+                tcx.types.err
             } else {
                 // Defer other checks until we're done type checking.
                 let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut();
                 match cast::CastCheck::new(self, e, t_expr, t_cast, t.span, expr.span) {
                     Ok(cast_check) => {
                         deferred_cast_checks.push(cast_check);
-                        self.write_ty(id, t_cast)
+                        t_cast
                     }
                     Err(ErrorReported) => {
-                        self.write_error(id)
+                        tcx.types.err
                     }
                 }
             }
@@ -3579,7 +3558,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
           hir::ExprType(ref e, ref t) => {
             let typ = self.to_ty(&t);
             self.check_expr_eq_type(&e, typ);
-            self.write_ty(id, typ)
+            typ
           }
           hir::ExprVec(ref args) => {
             let uty = expected.to_option(self).and_then(|uty| {
@@ -3611,7 +3590,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     }
                 }
             }
-            self.write_ty(id, tcx.mk_array(unified, args.len()))
+            tcx.mk_array(unified, args.len())
           }
           hir::ExprRepeat(ref element, ref count_expr) => {
             self.check_expr_has_type(&count_expr, tcx.types.usize);
@@ -3647,10 +3626,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             }
 
             if element_ty.references_error() {
-                self.write_error(id)
+                tcx.types.err
             } else {
-                let t = tcx.mk_array(t, count);
-                self.write_ty(id, t)
+                tcx.mk_array(t, count)
             }
           }
           hir::ExprTup(ref elts) => {
@@ -3677,29 +3655,25 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 t
             }).collect();
             if err_field {
-                self.write_error(id)
+                tcx.types.err
             } else {
-                let typ = tcx.mk_tup(elt_ts);
-                self.write_ty(id, typ)
+                tcx.mk_tup(elt_ts)
             }
           }
           hir::ExprStruct(ref path, ref fields, ref base_expr) => {
-            let ty = self.check_expr_struct(expr, path, fields, base_expr);
-            self.write_ty(id, ty)
+            self.check_expr_struct(expr, path, fields, base_expr)
           }
           hir::ExprField(ref base, ref field) => {
-            let ty = self.check_field(expr, lvalue_pref, &base, field);
-            self.write_ty(id, ty)
+            self.check_field(expr, lvalue_pref, &base, field)
           }
           hir::ExprTupField(ref base, idx) => {
-            let ty = self.check_tup_field(expr, lvalue_pref, &base, idx);
-            self.write_ty(id, ty)
+            self.check_tup_field(expr, lvalue_pref, &base, idx)
           }
           hir::ExprIndex(ref base, ref idx) => {
               let base_t = self.check_expr_with_lvalue_pref(&base, lvalue_pref);
               let idx_t = self.check_expr(&idx);
 
-              let ty = if base_t.references_error() {
+              if base_t.references_error() {
                   base_t
               } else if idx_t.references_error() {
                   idx_t
@@ -3747,16 +3721,26 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                           self.tcx().types.err
                       }
                   }
-              };
-              self.write_ty(id, ty)
+              }
            }
         };
+        self.write_ty(id, ty);
 
         debug!("type of expr({}) {} is...", expr.id,
                pprust::expr_to_string(expr));
         debug!("... {:?}, expected is {:?}",
                ty,
                expected);
+
+        // Add adjustments to !-expressions
+        if ty.is_never() {
+            if let Some(hir::map::NodeExpr(_)) = self.tcx.map.find(id) {
+                let adj_ty = self.next_diverging_ty_var();
+                let adj = adjustment::AdjustNeverToAny(adj_ty);
+                self.write_adjustment(id, adj);
+                return adj_ty;
+            }
+        }
         ty
     }
 

From 1c3e8b0a1c15d4cb7315a7067c19901c2cf66e0c Mon Sep 17 00:00:00 2001
From: Andrew Cann 
Date: Fri, 19 Aug 2016 00:24:32 +0800
Subject: [PATCH 174/443] Tidy

---
 src/librustc_typeck/check/_match.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index 838cf36b8853..5e7c499671c3 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -473,7 +473,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 }
             };
         }
-        
+
         result_ty
     }
 }

From f120c71775994e4fb94941cbc5539f6d5ffddced Mon Sep 17 00:00:00 2001
From: Andrew Cann 
Date: Fri, 19 Aug 2016 14:12:37 +0800
Subject: [PATCH 175/443] Tidy. Rename variables.

---
 src/librustc_typeck/check/_match.rs |  6 +++---
 src/librustc_typeck/check/mod.rs    | 26 +++++++++++++-------------
 src/librustc_typeck/check/op.rs     |  3 ++-
 3 files changed, 18 insertions(+), 17 deletions(-)

diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index 5e7c499671c3..763e92b69baf 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -37,11 +37,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 self.write_ty(pat.id, expected);
             }
             PatKind::Lit(ref lt) => {
-                let expr_t = self.check_expr(<);
+                let ty = self.check_expr(<);
 
                 // Byte string patterns behave the same way as array patterns
                 // They can denote both statically and dynamically sized byte arrays
-                let mut pat_ty = expr_t;
+                let mut pat_ty = ty;
                 if let hir::ExprLit(ref lt) = lt.node {
                     if let ast::LitKind::ByteStr(_) = lt.node {
                         let expected_ty = self.structurally_resolved_type(pat.span, expected);
@@ -62,7 +62,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 // relation at all but rather that there exists a LUB (so
                 // that they can be compared). However, in practice,
                 // constants are always scalars or strings.  For scalars
-                // subtyping is irrelevant, and for strings `expr_t` is
+                // subtyping is irrelevant, and for strings `ty` is
                 // type is `&'static str`, so if we say that
                 //
                 //     &'static str <: expected
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 2a12b7055d4e..a8c8a10dc568 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -3241,19 +3241,19 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                          base_expr: &'gcx Option>) -> Ty<'tcx>
     {
         // Find the relevant variant
-        let (variant, expr_t) = if let Some(variant_ty) = self.check_struct_path(path, expr.id,
-                                                                                  expr.span) {
+        let (variant, struct_ty) = if let Some(variant_ty) = self.check_struct_path(path, expr.id,
+                                                                                    expr.span) {
             variant_ty
         } else {
             self.check_struct_fields_on_error(fields, base_expr);
             return self.tcx().types.err;
         };
 
-        self.check_expr_struct_fields(expr_t, path.span, variant, fields,
+        self.check_expr_struct_fields(struct_ty, path.span, variant, fields,
                                       base_expr.is_none());
         if let &Some(ref base_expr) = base_expr {
-            self.check_expr_has_type(base_expr, expr_t);
-            match expr_t.sty {
+            self.check_expr_has_type(base_expr, struct_ty);
+            match struct_ty.sty {
                 ty::TyStruct(adt, substs) => {
                     self.tables.borrow_mut().fru_field_types.insert(
                         expr.id,
@@ -3270,8 +3270,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 }
             }
         }
-        self.require_type_is_sized(expr_t, expr.span, traits::StructInitializerSized);
-        expr_t
+        self.require_type_is_sized(struct_ty, expr.span, traits::StructInitializerSized);
+        struct_ty
     }
 
 
@@ -3881,15 +3881,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
           hir::StmtExpr(ref expr, id) => {
             node_id = id;
             // Check with expected type of ()
-            let expr_t = self.check_expr_has_type(&expr, self.tcx.mk_nil());
-            saw_bot = saw_bot || self.type_var_diverges(expr_t);
-            saw_err = saw_err || expr_t.references_error();
+            let ty = self.check_expr_has_type(&expr, self.tcx.mk_nil());
+            saw_bot = saw_bot || self.type_var_diverges(ty);
+            saw_err = saw_err || ty.references_error();
           }
           hir::StmtSemi(ref expr, id) => {
             node_id = id;
-            let expr_t = self.check_expr(&expr);
-            saw_bot |= self.type_var_diverges(expr_t);
-            saw_err |= expr_t.references_error();
+            let ty = self.check_expr(&expr);
+            saw_bot |= self.type_var_diverges(ty);
+            saw_err |= ty.references_error();
           }
         }
         if saw_bot {
diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs
index af7e12bd48dc..411bd7e7b5ca 100644
--- a/src/librustc_typeck/check/op.rs
+++ b/src/librustc_typeck/check/op.rs
@@ -32,7 +32,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             self.check_overloaded_binop(expr, lhs_expr, lhs_ty, rhs_expr, op, IsAssign::Yes);
         let rhs_ty = self.resolve_type_vars_with_obligations(rhs_ty);
 
-        let ty = if !lhs_ty.is_ty_var() && !rhs_ty.is_ty_var() && is_builtin_binop(lhs_ty, rhs_ty, op) {
+        let ty = if !lhs_ty.is_ty_var() && !rhs_ty.is_ty_var()
+                    && is_builtin_binop(lhs_ty, rhs_ty, op) {
             self.enforce_builtin_binop_types(lhs_expr, lhs_ty, rhs_expr, rhs_ty, op);
             self.tcx.mk_nil()
         } else {

From f54c47d34b0d8c898529c479a270ab034ce36f78 Mon Sep 17 00:00:00 2001
From: Andrew Cann 
Date: Fri, 19 Aug 2016 14:17:00 +0800
Subject: [PATCH 176/443] Move check_expr match block into its own method

---
 src/librustc_typeck/check/mod.rs | 45 ++++++++++++++++++--------------
 1 file changed, 26 insertions(+), 19 deletions(-)

diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index a8c8a10dc568..3fbfd2aedb46 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -3291,10 +3291,35 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                                    lvalue_pref: LvaluePreference) -> Ty<'tcx> {
         debug!(">> typechecking: expr={:?} expected={:?}",
                expr, expected);
+        let ty = self.check_expr_kind(expr, expected, lvalue_pref);
 
+        self.write_ty(expr.id, ty);
+
+        debug!("type of expr({}) {} is...", expr.id,
+               pprust::expr_to_string(expr));
+        debug!("... {:?}, expected is {:?}",
+               ty,
+               expected);
+
+        // Add adjustments to !-expressions
+        if ty.is_never() {
+            if let Some(hir::map::NodeExpr(_)) = self.tcx.map.find(expr.id) {
+                let adj_ty = self.next_diverging_ty_var();
+                let adj = adjustment::AdjustNeverToAny(adj_ty);
+                self.write_adjustment(expr.id, adj);
+                return adj_ty;
+            }
+        }
+        ty
+    }
+
+    fn check_expr_kind(&self,
+                       expr: &'gcx hir::Expr,
+                       expected: Expectation<'tcx>,
+                       lvalue_pref: LvaluePreference) -> Ty<'tcx> {
         let tcx = self.tcx;
         let id = expr.id;
-        let ty = match expr.node {
+        match expr.node {
           hir::ExprBox(ref subexpr) => {
             let expected_inner = expected.to_option(self).map_or(NoExpectation, |ty| {
                 match ty.sty {
@@ -3723,25 +3748,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                   }
               }
            }
-        };
-        self.write_ty(id, ty);
-
-        debug!("type of expr({}) {} is...", expr.id,
-               pprust::expr_to_string(expr));
-        debug!("... {:?}, expected is {:?}",
-               ty,
-               expected);
-
-        // Add adjustments to !-expressions
-        if ty.is_never() {
-            if let Some(hir::map::NodeExpr(_)) = self.tcx.map.find(id) {
-                let adj_ty = self.next_diverging_ty_var();
-                let adj = adjustment::AdjustNeverToAny(adj_ty);
-                self.write_adjustment(id, adj);
-                return adj_ty;
-            }
         }
-        ty
     }
 
     // Finish resolving a path in a struct expression or pattern `S::A { .. }` if necessary.

From 8c6086a0a3f0de3cd31b01eb223d36cd15314d6f Mon Sep 17 00:00:00 2001
From: Andrew Cann 
Date: Fri, 19 Aug 2016 14:41:25 +0800
Subject: [PATCH 177/443] check_block_with_expected returns the checked type

---
 src/librustc_typeck/check/mod.rs | 27 +++++++++++++--------------
 1 file changed, 13 insertions(+), 14 deletions(-)

diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 3fbfd2aedb46..79dd951a5d85 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -2850,8 +2850,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         let cond_ty = self.check_expr_has_type(cond_expr, self.tcx.types.bool);
 
         let expected = expected.adjust_for_branches(self);
-        self.check_block_with_expected(then_blk, expected);
-        let then_ty = self.node_ty(then_blk.id);
+        let then_ty = self.check_block_with_expected(then_blk, expected);
 
         let unit = self.tcx.mk_nil();
         let (origin, expected, found, result) =
@@ -3542,8 +3541,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
               self.check_expr_closure(expr, capture, &decl, &body, expected)
           }
           hir::ExprBlock(ref b) => {
-            self.check_block_with_expected(&b, expected);
-            self.node_ty(b.id)
+            self.check_block_with_expected(&b, expected)
           }
           hir::ExprCall(ref callee, ref args) => {
               self.check_call(expr, &callee, &args[..], expected)
@@ -3911,8 +3909,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     }
 
     pub fn check_block_no_value(&self, blk: &'gcx hir::Block)  {
-        self.check_block_with_expected(blk, ExpectHasType(self.tcx.mk_nil()));
-        let blkty = self.node_ty(blk.id);
+        let blkty = self.check_block_with_expected(blk, ExpectHasType(self.tcx.mk_nil()));
         if blkty.references_error() {
             self.write_error(blk.id);
         } else {
@@ -3923,7 +3920,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
     fn check_block_with_expected(&self,
                                  blk: &'gcx hir::Block,
-                                 expected: Expectation<'tcx>) {
+                                 expected: Expectation<'tcx>) -> Ty<'tcx> {
         let prev = {
             let mut fcx_ps = self.ps.borrow_mut();
             let unsafety_state = fcx_ps.recurse(blk);
@@ -3960,13 +3957,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                            s_ty.is_never();
             any_err = any_err || s_ty.references_error();
         }
-        match blk.expr {
+        let ty = match blk.expr {
             None => if any_err {
-                self.write_error(blk.id);
+                self.tcx.types.err
             } else if any_diverges {
-                self.write_ty(blk.id, self.next_diverging_ty_var());
+                self.next_diverging_ty_var()
             } else {
-                self.write_nil(blk.id);
+                self.tcx.mk_nil()
             },
             Some(ref e) => {
                 if any_diverges && !warned {
@@ -3988,16 +3985,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 };
 
                 if any_err {
-                    self.write_error(blk.id);
+                    self.tcx.types.err
                 } else if any_diverges {
-                    self.write_ty(blk.id, self.next_diverging_ty_var());
+                    self.next_diverging_ty_var()
                 } else {
-                    self.write_ty(blk.id, ety);
+                    ety
                 }
             }
         };
+        self.write_ty(blk.id, ty);
 
         *self.ps.borrow_mut() = prev;
+        ty
     }
 
     // Instantiates the given path, which must refer to an item with the given

From c5ff28cd14bf90b45f97d370538d792693036b27 Mon Sep 17 00:00:00 2001
From: Andrew Cann 
Date: Sat, 27 Aug 2016 20:06:47 +0800
Subject: [PATCH 178/443] Factor write_ty out of pattern-matching functions

---
 src/librustc_typeck/check/_match.rs | 23 ++++++++++-------------
 1 file changed, 10 insertions(+), 13 deletions(-)

diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index 763e92b69baf..35d77e8c2ade 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -54,8 +54,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     }
                 }
 
-                self.write_ty(pat.id, pat_ty);
-
                 // somewhat surprising: in this case, the subtyping
                 // relation goes the opposite way as the other
                 // cases. Actually what we really want is not a subtyping
@@ -69,6 +67,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 //
                 // that's equivalent to there existing a LUB.
                 self.demand_suptype(pat.span, expected, pat_ty);
+                self.write_ty(pat.id, pat_ty);
             }
             PatKind::Range(ref begin, ref end) => {
                 let lhs_ty = self.check_expr(begin);
@@ -101,11 +100,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 // it to type the entire expression.
                 let common_type = self.resolve_type_vars_if_possible(&lhs_ty);
 
-                self.write_ty(pat.id, common_type);
-
                 // subtyping doesn't matter here, as the value is some kind of scalar
                 self.demand_eqtype(pat.span, expected, lhs_ty);
                 self.demand_eqtype(pat.span, expected, rhs_ty);
+                self.write_ty(pat.id, common_type);
             }
             PatKind::Binding(bm, _, ref sub) => {
                 let typ = self.local_ty(pat.span, pat.id);
@@ -132,8 +130,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     }
                 }
 
-                self.write_ty(pat.id, typ);
-
                 // if there are multiple arms, make sure they all agree on
                 // what the type of the binding `x` ought to be
                 match tcx.expect_def(pat.id) {
@@ -150,6 +146,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 if let Some(ref p) = *sub {
                     self.check_pat(&p, expected);
                 }
+
+                self.write_ty(pat.id, typ);
             }
             PatKind::TupleStruct(ref path, ref subpats, ddpos) => {
                 self.check_pat_tuple_struct(pat, path, &subpats, ddpos, expected);
@@ -174,11 +172,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
                 let element_tys: Vec<_> = (0 .. max_len).map(|_| self.next_ty_var()).collect();
                 let pat_ty = tcx.mk_tup(element_tys.clone());
-                self.write_ty(pat.id, pat_ty);
                 self.demand_eqtype(pat.span, expected, pat_ty);
                 for (i, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) {
                     self.check_pat(elem, &element_tys[i]);
                 }
+                self.write_ty(pat.id, pat_ty);
             }
             PatKind::Box(ref inner) => {
                 let inner_ty = self.next_ty_var();
@@ -189,11 +187,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     // think any errors can be introduced by using
                     // `demand::eqtype`.
                     self.demand_eqtype(pat.span, expected, uniq_ty);
-                    self.write_ty(pat.id, uniq_ty);
                     self.check_pat(&inner, inner_ty);
+                    self.write_ty(pat.id, uniq_ty);
                 } else {
-                    self.write_error(pat.id);
                     self.check_pat(&inner, tcx.types.err);
+                    self.write_error(pat.id);
                 }
             }
             PatKind::Ref(ref inner, mutbl) => {
@@ -221,11 +219,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                         }
                     };
 
-                    self.write_ty(pat.id, rptr_ty);
                     self.check_pat(&inner, inner_ty);
+                    self.write_ty(pat.id, rptr_ty);
                 } else {
-                    self.write_error(pat.id);
                     self.check_pat(&inner, tcx.types.err);
+                    self.write_error(pat.id);
                 }
             }
             PatKind::Vec(ref before, ref slice, ref after) => {
@@ -277,8 +275,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     }
                 };
 
-                self.write_ty(pat.id, expected_ty);
-
                 for elt in before {
                     self.check_pat(&elt, inner_ty);
                 }
@@ -288,6 +284,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 for elt in after {
                     self.check_pat(&elt, inner_ty);
                 }
+                self.write_ty(pat.id, expected_ty);
             }
         }
 

From 1749fda9c04fdb051c82904b522eb79697bbf1c0 Mon Sep 17 00:00:00 2001
From: Andrew Cann 
Date: Sat, 27 Aug 2016 20:34:37 +0800
Subject: [PATCH 179/443] Factor write_ty out of more pattern-checking
 functions

---
 src/librustc_typeck/check/_match.rs | 42 ++++++++++++++---------------
 1 file changed, 20 insertions(+), 22 deletions(-)

diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index 35d77e8c2ade..ee66597e72a4 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -150,14 +150,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 self.write_ty(pat.id, typ);
             }
             PatKind::TupleStruct(ref path, ref subpats, ddpos) => {
-                self.check_pat_tuple_struct(pat, path, &subpats, ddpos, expected);
+                let pat_ty = self.check_pat_tuple_struct(pat, path, &subpats, ddpos, expected);
+                write_ty(pat.id, pat_ty);
             }
             PatKind::Path(ref opt_qself, ref path) => {
                 let opt_qself_ty = opt_qself.as_ref().map(|qself| self.to_ty(&qself.ty));
-                self.check_pat_path(pat, opt_qself_ty, path, expected);
+                let pat_ty = self.check_pat_path(pat, opt_qself_ty, path, expected);
+                write_ty(pat.id, pat_ty);
             }
             PatKind::Struct(ref path, ref fields, etc) => {
-                self.check_pat_struct(pat, path, fields, etc, expected);
+                let pat_ty = self.check_pat_struct(pat, path, fields, etc, expected);
+                write_ty(pat.id, pat_ty);
             }
             PatKind::Tuple(ref elements, ddpos) => {
                 let mut expected_len = elements.len();
@@ -481,40 +484,38 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                         path: &hir::Path,
                         fields: &'gcx [Spanned],
                         etc: bool,
-                        expected: Ty<'tcx>)
+                        expected: Ty<'tcx>) -> Ty<'tcx>
     {
         // Resolve the path and check the definition for errors.
         let (variant, pat_ty) = if let Some(variant_ty) = self.check_struct_path(path, pat.id,
                                                                                  pat.span) {
             variant_ty
         } else {
-            self.write_error(pat.id);
             for field in fields {
                 self.check_pat(&field.node.pat, self.tcx.types.err);
             }
-            return;
+            return tcx.types.err;
         };
-        self.write_ty(pat.id, pat_ty);
 
         // Type check the path.
         self.demand_eqtype(pat.span, expected, pat_ty);
 
         // Type check subpatterns.
         self.check_struct_pat_fields(pat_ty, pat.span, variant, fields, etc);
+        pat_ty
     }
 
     fn check_pat_path(&self,
                       pat: &hir::Pat,
                       opt_self_ty: Option>,
                       path: &hir::Path,
-                      expected: Ty<'tcx>)
+                      expected: Ty<'tcx>) -> Ty<'tcx>
     {
         let tcx = self.tcx;
         let report_unexpected_def = || {
             span_err!(tcx.sess, pat.span, E0533,
                       "`{}` does not name a unit variant, unit struct or a constant",
                       pprust::path_to_string(path));
-            self.write_error(pat.id);
         };
 
         // Resolve the path and check the definition for errors.
@@ -523,18 +524,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         match def {
             Def::Err => {
                 self.set_tainted_by_errors();
-                self.write_error(pat.id);
-                return;
+                return tcx.types.err;
             }
             Def::Method(..) => {
                 report_unexpected_def();
-                return;
+                return tcx.types.err;
             }
             Def::Variant(..) | Def::Struct(..) => {
                 let variant = tcx.expect_variant_def(def);
                 if variant.kind != VariantKind::Unit {
                     report_unexpected_def();
-                    return;
+                    return tcx.types.err;
                 }
             }
             Def::Const(..) | Def::AssociatedConst(..) => {} // OK
@@ -543,8 +543,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
         // Type check the path.
         let pat_ty = self.instantiate_value_path(segments, opt_ty, def, pat.span, pat.id);
-        self.write_ty(pat.id, pat_ty);
         self.demand_suptype(pat.span, expected, pat_ty);
+        pat_ty
     }
 
     fn check_pat_tuple_struct(&self,
@@ -552,11 +552,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                               path: &hir::Path,
                               subpats: &'gcx [P],
                               ddpos: Option,
-                              expected: Ty<'tcx>)
+                              expected: Ty<'tcx>) -> Ty<'tcx>
     {
         let tcx = self.tcx;
         let on_error = || {
-            self.write_error(pat.id);
             for pat in subpats {
                 self.check_pat(&pat, tcx.types.err);
             }
@@ -580,11 +579,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             Def::Err => {
                 self.set_tainted_by_errors();
                 on_error();
-                return;
+                return tcx.types.err;
             }
             Def::Const(..) | Def::AssociatedConst(..) | Def::Method(..) => {
                 report_unexpected_def(false);
-                return;
+                return tcx.types.err;
             }
             Def::Variant(..) | Def::Struct(..) => {
                 tcx.expect_variant_def(def)
@@ -597,13 +596,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             report_unexpected_def(true);
         } else if variant.kind != VariantKind::Tuple {
             report_unexpected_def(false);
-            return;
+            return tcx.types.err;
         }
 
         // Type check the path.
         let pat_ty = self.instantiate_value_path(segments, opt_ty, def, pat.span, pat.id);
-        self.write_ty(pat.id, pat_ty);
-
         let pat_ty = if pat_ty.is_fn() {
             // Replace constructor type with constructed type for tuple struct patterns.
             tcx.no_late_bound_regions(&pat_ty.fn_ret()).unwrap()
@@ -611,7 +608,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             // Leave the type as is for unit structs (backward compatibility).
             pat_ty
         };
-        self.write_ty(pat.id, pat_ty);
         self.demand_eqtype(pat.span, expected, pat_ty);
 
         // Type check subpatterns.
@@ -644,7 +640,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                                variant.fields.len(), fields_ending, subpats.len()))
                 .emit();
             on_error();
+            return tcx.types.err;
         }
+        pat_ty
     }
 
     fn check_struct_pat_fields(&self,

From bd661481e79bb5701455b03d8d3b587309e56186 Mon Sep 17 00:00:00 2001
From: Andrew Cann 
Date: Sat, 27 Aug 2016 20:38:06 +0800
Subject: [PATCH 180/443] Move write_ty to the bottom of check_pat

---
 src/librustc_typeck/check/_match.rs | 37 ++++++++++++++---------------
 1 file changed, 18 insertions(+), 19 deletions(-)

diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index ee66597e72a4..c1a0a6f70aa4 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -32,9 +32,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
         debug!("check_pat(pat={:?},expected={:?})", pat, expected);
 
-        match pat.node {
+        let ty = match pat.node {
             PatKind::Wild => {
-                self.write_ty(pat.id, expected);
+                expected
             }
             PatKind::Lit(ref lt) => {
                 let ty = self.check_expr(<);
@@ -67,7 +67,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 //
                 // that's equivalent to there existing a LUB.
                 self.demand_suptype(pat.span, expected, pat_ty);
-                self.write_ty(pat.id, pat_ty);
+                pat_ty
             }
             PatKind::Range(ref begin, ref end) => {
                 let lhs_ty = self.check_expr(begin);
@@ -103,7 +103,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 // subtyping doesn't matter here, as the value is some kind of scalar
                 self.demand_eqtype(pat.span, expected, lhs_ty);
                 self.demand_eqtype(pat.span, expected, rhs_ty);
-                self.write_ty(pat.id, common_type);
+                common_type
             }
             PatKind::Binding(bm, _, ref sub) => {
                 let typ = self.local_ty(pat.span, pat.id);
@@ -147,20 +147,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     self.check_pat(&p, expected);
                 }
 
-                self.write_ty(pat.id, typ);
+                typ
             }
             PatKind::TupleStruct(ref path, ref subpats, ddpos) => {
-                let pat_ty = self.check_pat_tuple_struct(pat, path, &subpats, ddpos, expected);
-                write_ty(pat.id, pat_ty);
+                self.check_pat_tuple_struct(pat, path, &subpats, ddpos, expected)
             }
             PatKind::Path(ref opt_qself, ref path) => {
                 let opt_qself_ty = opt_qself.as_ref().map(|qself| self.to_ty(&qself.ty));
-                let pat_ty = self.check_pat_path(pat, opt_qself_ty, path, expected);
-                write_ty(pat.id, pat_ty);
+                self.check_pat_path(pat, opt_qself_ty, path, expected)
             }
             PatKind::Struct(ref path, ref fields, etc) => {
-                let pat_ty = self.check_pat_struct(pat, path, fields, etc, expected);
-                write_ty(pat.id, pat_ty);
+                self.check_pat_struct(pat, path, fields, etc, expected)
             }
             PatKind::Tuple(ref elements, ddpos) => {
                 let mut expected_len = elements.len();
@@ -179,7 +176,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 for (i, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) {
                     self.check_pat(elem, &element_tys[i]);
                 }
-                self.write_ty(pat.id, pat_ty);
+                pat_ty
             }
             PatKind::Box(ref inner) => {
                 let inner_ty = self.next_ty_var();
@@ -191,10 +188,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     // `demand::eqtype`.
                     self.demand_eqtype(pat.span, expected, uniq_ty);
                     self.check_pat(&inner, inner_ty);
-                    self.write_ty(pat.id, uniq_ty);
+                    uniq_ty
                 } else {
                     self.check_pat(&inner, tcx.types.err);
-                    self.write_error(pat.id);
+                    tcx.types.err
                 }
             }
             PatKind::Ref(ref inner, mutbl) => {
@@ -223,10 +220,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     };
 
                     self.check_pat(&inner, inner_ty);
-                    self.write_ty(pat.id, rptr_ty);
+                    rptr_ty
                 } else {
                     self.check_pat(&inner, tcx.types.err);
-                    self.write_error(pat.id);
+                    tcx.types.err
                 }
             }
             PatKind::Vec(ref before, ref slice, ref after) => {
@@ -287,9 +284,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 for elt in after {
                     self.check_pat(&elt, inner_ty);
                 }
-                self.write_ty(pat.id, expected_ty);
+                expected_ty
             }
-        }
+        };
+
+        self.write_ty(pat.id, ty);
 
         // (*) In most of the cases above (literals and constants being
         // the exception), we relate types using strict equality, evewn
@@ -494,7 +493,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             for field in fields {
                 self.check_pat(&field.node.pat, self.tcx.types.err);
             }
-            return tcx.types.err;
+            return self.tcx.types.err;
         };
 
         // Type check the path.

From 180534f398b18aea5d7740153eab026074396013 Mon Sep 17 00:00:00 2001
From: Andrew Cann 
Date: Sun, 28 Aug 2016 16:17:52 +0800
Subject: [PATCH 181/443] Remove use of expr_ty from coercions code

---
 src/librustc_typeck/check/_match.rs   | 10 +++++++---
 src/librustc_typeck/check/cast.rs     |  4 ++--
 src/librustc_typeck/check/coercion.rs | 22 +++++++++++++---------
 src/librustc_typeck/check/demand.rs   |  6 +++---
 src/librustc_typeck/check/mod.rs      | 21 ++++++++++++---------
 5 files changed, 37 insertions(+), 26 deletions(-)

diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index c1a0a6f70aa4..42769a863640 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -419,11 +419,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             }
             _ => result_ty
         };
+
+        let mut arm_tys = Vec::new();
         for (i, arm) in arms.iter().enumerate() {
             if let Some(ref e) = arm.guard {
                 self.check_expr_has_type(e, tcx.types.bool);
             }
             let arm_ty = self.check_expr_with_expectation(&arm.body, expected);
+            arm_tys.push(arm_ty);
 
             if result_ty.references_error() || arm_ty.references_error() {
                 result_ty = tcx.types.err;
@@ -453,10 +456,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     })
             } else if i == 0 {
                 // Special-case the first arm, as it has no "previous expressions".
-                self.try_coerce(&arm.body, coerce_first)
+                self.try_coerce(&arm.body, arm_ty, coerce_first)
             } else {
-                let prev_arms = || arms[..i].iter().map(|arm| &*arm.body);
-                self.try_find_coercion_lub(origin, prev_arms, result_ty, &arm.body)
+                let prev_arms = || arms[..i].iter().map(|arm| &*arm.body)
+                                            .zip(arm_tys.iter().cloned());
+                self.try_find_coercion_lub(origin, prev_arms, result_ty, &arm.body, arm_ty)
             };
 
             result_ty = match result {
diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs
index 1fda38d8a330..0c9da86563ab 100644
--- a/src/librustc_typeck/check/cast.rs
+++ b/src/librustc_typeck/check/cast.rs
@@ -321,7 +321,7 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
             (None, Some(t_cast)) => {
                 if let ty::TyFnDef(.., f) = self.expr_ty.sty {
                     // Attempt a coercion to a fn pointer type.
-                    let res = fcx.try_coerce(self.expr, fcx.tcx.mk_fn_ptr(f));
+                    let res = fcx.try_coerce(self.expr, self.expr_ty, fcx.tcx.mk_fn_ptr(f));
                     if !res.is_ok() {
                         return Err(CastError::NonScalar);
                     }
@@ -471,7 +471,7 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
     }
 
     fn try_coercion_cast(&self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) -> bool {
-        fcx.try_coerce(self.expr, self.cast_ty).is_ok()
+        fcx.try_coerce(self.expr, self.expr_ty, self.cast_ty).is_ok()
     }
 
 }
diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs
index 60ca9309eea0..263a83389ea9 100644
--- a/src/librustc_typeck/check/coercion.rs
+++ b/src/librustc_typeck/check/coercion.rs
@@ -630,9 +630,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     /// The expressions *must not* have any pre-existing adjustments.
     pub fn try_coerce(&self,
                       expr: &hir::Expr,
+                      expr_ty: Ty<'tcx>,
                       target: Ty<'tcx>)
                       -> RelateResult<'tcx, Ty<'tcx>> {
-        let source = self.resolve_type_vars_with_obligations(self.expr_ty(expr));
+        let source = self.resolve_type_vars_with_obligations(expr_ty);
         debug!("coercion::try({:?}: {:?} -> {:?})", expr, source, target);
 
         let mut coerce = Coerce::new(self, TypeOrigin::ExprAssignable(expr.span));
@@ -658,14 +659,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                            origin: TypeOrigin,
                                            exprs: E,
                                            prev_ty: Ty<'tcx>,
-                                           new: &'b hir::Expr)
+                                           new: &'b hir::Expr,
+                                           new_ty: Ty<'tcx>)
                                            -> RelateResult<'tcx, Ty<'tcx>>
         // FIXME(eddyb) use copyable iterators when that becomes ergonomic.
         where E: Fn() -> I,
-              I: IntoIterator {
+              I: IntoIterator)> {
 
         let prev_ty = self.resolve_type_vars_with_obligations(prev_ty);
-        let new_ty = self.resolve_type_vars_with_obligations(self.expr_ty(new));
+        let new_ty = self.resolve_type_vars_with_obligations(new_ty);
         debug!("coercion::try_find_lub({:?}, {:?})", prev_ty, new_ty);
 
         let trace = TypeTrace::types(origin, true, prev_ty, new_ty);
@@ -701,7 +703,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 }
 
                 // Reify both sides and return the reified fn pointer type.
-                for expr in exprs().into_iter().chain(Some(new)) {
+                for (expr, _) in exprs().into_iter().chain(Some((new, new_ty))) {
                     // No adjustments can produce a fn item, so this should never trip.
                     assert!(!self.tables.borrow().adjustments.contains_key(&expr.id));
                     self.write_adjustment(expr.id, AdjustReifyFnPointer);
@@ -735,13 +737,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         // Then try to coerce the previous expressions to the type of the new one.
         // This requires ensuring there are no coercions applied to *any* of the
         // previous expressions, other than noop reborrows (ignoring lifetimes).
-        for expr in exprs() {
+        for (expr, expr_ty) in exprs() {
             let noop = match self.tables.borrow().adjustments.get(&expr.id) {
                 Some(&AdjustDerefRef(AutoDerefRef {
                     autoderefs: 1,
                     autoref: Some(AutoPtr(_, mutbl_adj)),
                     unsize: None
-                })) => match self.expr_ty(expr).sty {
+                })) => match expr_ty.sty {
                     ty::TyRef(_, mt_orig) => {
                         // Reborrow that we can safely ignore.
                         mutbl_adj == mt_orig.mutbl
@@ -765,7 +767,9 @@ 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(|_| apply(&mut coerce,
+                                          &|| exprs().into_iter().map(|(e, _)| e),
+                                          prev_ty, new_ty)) {
             Err(_) => {
                 // Avoid giving strange errors on failed attempts.
                 if let Some(e) = first_error {
@@ -783,7 +787,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             }
             Ok((ty, adjustment)) => {
                 if !adjustment.is_identity() {
-                    for expr in exprs() {
+                    for (expr, _) in exprs() {
                         let previous = self.tables.borrow().adjustments.get(&expr.id).cloned();
                         if let Some(AdjustNeverToAny(_)) = previous {
                             self.write_adjustment(expr.id, AdjustNeverToAny(ty));
diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs
index 1f3a83ebc1d5..d622bc7f751d 100644
--- a/src/librustc_typeck/check/demand.rs
+++ b/src/librustc_typeck/check/demand.rs
@@ -53,11 +53,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     }
 
     // Checks that the type of `expr` can be coerced to `expected`.
-    pub fn demand_coerce(&self, expr: &hir::Expr, expected: Ty<'tcx>) {
+    pub fn demand_coerce(&self, expr: &hir::Expr, checked_ty: Ty<'tcx>, expected: Ty<'tcx>) {
         let expected = self.resolve_type_vars_with_obligations(expected);
-        if let Err(e) = self.try_coerce(expr, expected) {
+        if let Err(e) = self.try_coerce(expr, checked_ty, expected) {
             let origin = TypeOrigin::Misc(expr.span);
-            let expr_ty = self.resolve_type_vars_with_obligations(self.expr_ty(expr));
+            let expr_ty = self.resolve_type_vars_with_obligations(checked_ty);
             self.report_mismatched_types(origin, expected, expr_ty, e);
         }
     }
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 79dd951a5d85..b12833392135 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -2567,13 +2567,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                         Expectation::rvalue_hint(self, ty)
                     });
 
-                    self.check_expr_with_expectation(&arg,
-                        expected.unwrap_or(ExpectHasType(formal_ty)));
+                    let checked_ty = self.check_expr_with_expectation(&arg,
+                                            expected.unwrap_or(ExpectHasType(formal_ty)));
                     // 2. Coerce to the most detailed type that could be coerced
                     //    to, which is `expected_ty` if `rvalue_hint` returns an
                     //    `ExpectHasType(expected_ty)`, or the `formal_ty` otherwise.
                     let coerce_ty = expected.and_then(|e| e.only_has_type(self));
-                    self.demand_coerce(&arg, coerce_ty.unwrap_or(formal_ty));
+                    self.demand_coerce(&arg, checked_ty, coerce_ty.unwrap_or(formal_ty));
 
                     // 3. Relate the expected type and the formal one,
                     //    if the expected type was used for the coercion.
@@ -2715,7 +2715,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                     expr: &'gcx hir::Expr,
                                     expected: Ty<'tcx>) -> Ty<'tcx> {
         let ty = self.check_expr_with_hint(expr, expected);
-        self.demand_coerce(expr, expected);
+        self.demand_coerce(expr, ty, expected);
         ty
     }
 
@@ -2861,8 +2861,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             // Only try to coerce-unify if we have a then expression
             // to assign coercions to, otherwise it's () or diverging.
             let result = if let Some(ref then) = then_blk.expr {
-                let res = self.try_find_coercion_lub(origin, || Some(&**then),
-                                                     then_ty, else_expr);
+                let res = self.try_find_coercion_lub(origin, || Some((&**then, then_ty)),
+                                                     then_ty, else_expr, else_ty);
 
                 // In case we did perform an adjustment, we have to update
                 // the type of the block, because old trans still uses it.
@@ -3594,16 +3594,19 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             let mut unified = self.next_ty_var();
             let coerce_to = uty.unwrap_or(unified);
 
+            let mut arg_tys = Vec::new();
             for (i, e) in args.iter().enumerate() {
                 let e_ty = self.check_expr_with_hint(e, coerce_to);
+                arg_tys.push(e_ty);
                 let origin = TypeOrigin::Misc(e.span);
 
                 // Special-case the first element, as it has no "previous expressions".
                 let result = if i == 0 {
-                    self.try_coerce(e, coerce_to)
+                    self.try_coerce(e, e_ty, coerce_to)
                 } else {
-                    let prev_elems = || args[..i].iter().map(|e| &**e);
-                    self.try_find_coercion_lub(origin, prev_elems, unified, e)
+                    let prev_elems = || args[..i].iter().map(|e| &**e)
+                                                 .zip(arg_tys.iter().cloned());
+                    self.try_find_coercion_lub(origin, prev_elems, unified, e, e_ty)
                 };
 
                 match result {

From 7c8f5457d26055b26210fdd69c5ded1ecdde144a Mon Sep 17 00:00:00 2001
From: Andrew Cann 
Date: Sun, 28 Aug 2016 17:29:54 +0800
Subject: [PATCH 182/443] Undo unnecessary bookkeeping from last commit

---
 src/librustc_typeck/check/_match.rs   |  5 +----
 src/librustc_typeck/check/coercion.rs | 14 ++++++--------
 src/librustc_typeck/check/mod.rs      |  7 ++-----
 3 files changed, 9 insertions(+), 17 deletions(-)

diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index 42769a863640..c67b98761aa6 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -420,13 +420,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             _ => result_ty
         };
 
-        let mut arm_tys = Vec::new();
         for (i, arm) in arms.iter().enumerate() {
             if let Some(ref e) = arm.guard {
                 self.check_expr_has_type(e, tcx.types.bool);
             }
             let arm_ty = self.check_expr_with_expectation(&arm.body, expected);
-            arm_tys.push(arm_ty);
 
             if result_ty.references_error() || arm_ty.references_error() {
                 result_ty = tcx.types.err;
@@ -458,8 +456,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 // Special-case the first arm, as it has no "previous expressions".
                 self.try_coerce(&arm.body, arm_ty, coerce_first)
             } else {
-                let prev_arms = || arms[..i].iter().map(|arm| &*arm.body)
-                                            .zip(arm_tys.iter().cloned());
+                let prev_arms = || arms[..i].iter().map(|arm| &*arm.body);
                 self.try_find_coercion_lub(origin, prev_arms, result_ty, &arm.body, arm_ty)
             };
 
diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs
index 263a83389ea9..98a05989b140 100644
--- a/src/librustc_typeck/check/coercion.rs
+++ b/src/librustc_typeck/check/coercion.rs
@@ -664,7 +664,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                            -> RelateResult<'tcx, Ty<'tcx>>
         // FIXME(eddyb) use copyable iterators when that becomes ergonomic.
         where E: Fn() -> I,
-              I: IntoIterator)> {
+              I: IntoIterator {
 
         let prev_ty = self.resolve_type_vars_with_obligations(prev_ty);
         let new_ty = self.resolve_type_vars_with_obligations(new_ty);
@@ -703,7 +703,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 }
 
                 // Reify both sides and return the reified fn pointer type.
-                for (expr, _) in exprs().into_iter().chain(Some((new, new_ty))) {
+                for expr in exprs().into_iter().chain(Some(new)) {
                     // No adjustments can produce a fn item, so this should never trip.
                     assert!(!self.tables.borrow().adjustments.contains_key(&expr.id));
                     self.write_adjustment(expr.id, AdjustReifyFnPointer);
@@ -737,13 +737,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         // Then try to coerce the previous expressions to the type of the new one.
         // This requires ensuring there are no coercions applied to *any* of the
         // previous expressions, other than noop reborrows (ignoring lifetimes).
-        for (expr, expr_ty) in exprs() {
+        for expr in exprs() {
             let noop = match self.tables.borrow().adjustments.get(&expr.id) {
                 Some(&AdjustDerefRef(AutoDerefRef {
                     autoderefs: 1,
                     autoref: Some(AutoPtr(_, mutbl_adj)),
                     unsize: None
-                })) => match expr_ty.sty {
+                })) => match self.node_ty(expr.id).sty {
                     ty::TyRef(_, mt_orig) => {
                         // Reborrow that we can safely ignore.
                         mutbl_adj == mt_orig.mutbl
@@ -767,9 +767,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             }
         }
 
-        match self.commit_if_ok(|_| apply(&mut coerce,
-                                          &|| exprs().into_iter().map(|(e, _)| e),
-                                          prev_ty, new_ty)) {
+        match self.commit_if_ok(|_| apply(&mut coerce, &exprs, prev_ty, new_ty)) {
             Err(_) => {
                 // Avoid giving strange errors on failed attempts.
                 if let Some(e) = first_error {
@@ -787,7 +785,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             }
             Ok((ty, adjustment)) => {
                 if !adjustment.is_identity() {
-                    for (expr, _) in exprs() {
+                    for expr in exprs() {
                         let previous = self.tables.borrow().adjustments.get(&expr.id).cloned();
                         if let Some(AdjustNeverToAny(_)) = previous {
                             self.write_adjustment(expr.id, AdjustNeverToAny(ty));
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index b12833392135..1e57cc5d6c84 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -2861,7 +2861,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             // Only try to coerce-unify if we have a then expression
             // to assign coercions to, otherwise it's () or diverging.
             let result = if let Some(ref then) = then_blk.expr {
-                let res = self.try_find_coercion_lub(origin, || Some((&**then, then_ty)),
+                let res = self.try_find_coercion_lub(origin, || Some(&**then),
                                                      then_ty, else_expr, else_ty);
 
                 // In case we did perform an adjustment, we have to update
@@ -3594,18 +3594,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             let mut unified = self.next_ty_var();
             let coerce_to = uty.unwrap_or(unified);
 
-            let mut arg_tys = Vec::new();
             for (i, e) in args.iter().enumerate() {
                 let e_ty = self.check_expr_with_hint(e, coerce_to);
-                arg_tys.push(e_ty);
                 let origin = TypeOrigin::Misc(e.span);
 
                 // Special-case the first element, as it has no "previous expressions".
                 let result = if i == 0 {
                     self.try_coerce(e, e_ty, coerce_to)
                 } else {
-                    let prev_elems = || args[..i].iter().map(|e| &**e)
-                                                 .zip(arg_tys.iter().cloned());
+                    let prev_elems = || args[..i].iter().map(|e| &**e);
                     self.try_find_coercion_lub(origin, prev_elems, unified, e, e_ty)
                 };
 

From c9a340e546ac2c708d6f334a83cfbf6a38810255 Mon Sep 17 00:00:00 2001
From: Andrew Cann 
Date: Sun, 28 Aug 2016 19:37:57 +0800
Subject: [PATCH 183/443] Remove expr_ty method completely

---
 src/librustc_typeck/check/method/confirm.rs |  8 ++++----
 src/librustc_typeck/check/mod.rs            | 13 -------------
 2 files changed, 4 insertions(+), 17 deletions(-)

diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs
index dbf74e371df4..ab59fafb6520 100644
--- a/src/librustc_typeck/check/method/confirm.rs
+++ b/src/librustc_typeck/check/method/confirm.rs
@@ -472,7 +472,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
                    i, expr, autoderef_count);
 
             if autoderef_count > 0 {
-                let mut autoderef = self.autoderef(expr.span, self.expr_ty(expr));
+                let mut autoderef = self.autoderef(expr.span, self.node_ty(expr.id));
                 autoderef.nth(autoderef_count).unwrap_or_else(|| {
                     span_bug!(expr.span, "expr was deref-able {} times but now isn't?",
                               autoderef_count);
@@ -532,7 +532,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
                                 unsize: None
                             }))), false)
                     };
-                    let index_expr_ty = self.expr_ty(&index_expr);
+                    let index_expr_ty = self.node_ty(index_expr.id);
 
                     let result = self.try_index_step(
                         ty::MethodCall::expr(expr.id),
@@ -547,7 +547,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
                     if let Some((input_ty, return_ty)) = result {
                         self.demand_suptype(index_expr.span, input_ty, index_expr_ty);
 
-                        let expr_ty = self.expr_ty(&expr);
+                        let expr_ty = self.node_ty(expr.id);
                         self.demand_suptype(expr.span, expr_ty, return_ty);
                     }
                 }
@@ -558,7 +558,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
                     if self.tables.borrow().method_map.contains_key(&method_call) {
                         let method = self.try_overloaded_deref(expr.span,
                             Some(&base_expr),
-                            self.expr_ty(&base_expr),
+                            self.node_ty(base_expr.id),
                             PreferMutLvalue);
                         let method = method.expect("re-trying deref failed");
                         self.tables.borrow_mut().method_map.insert(method_call, method);
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 1e57cc5d6c84..00fdcd59f7ce 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -1763,19 +1763,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         t
     }
 
-    pub fn expr_ty(&self, ex: &hir::Expr) -> Ty<'tcx> {
-        if let Some(&adjustment::AdjustNeverToAny(ref t))
-                = self.tables.borrow().adjustments.get(&ex.id) {
-            return t;
-        }
-        match self.tables.borrow().node_types.get(&ex.id) {
-            Some(&t) => t,
-            None => {
-                bug!("no type for expr in fcx {}", self.tag());
-            }
-        }
-    }
-
     /// Apply `adjustment` to the type of `expr`
     pub fn adjust_expr_ty(&self,
                           expr: &hir::Expr,

From e1e5c14bad0e8989523cf5974d98a8257badb88d Mon Sep 17 00:00:00 2001
From: Jeffrey Seyfried 
Date: Wed, 31 Aug 2016 09:02:45 +0000
Subject: [PATCH 184/443] In `Parser` and `ExtCtxt`, replace fields `filename`
 and `mod_path_stack` with a single field `directory: PathBuf`.

---
 src/libsyntax/ext/base.rs           |  7 ++---
 src/libsyntax/ext/expand.rs         | 43 ++++++++++++-----------------
 src/libsyntax/ext/tt/macro_rules.rs |  3 +-
 src/libsyntax/parse/parser.rs       | 42 +++++++++++-----------------
 4 files changed, 38 insertions(+), 57 deletions(-)

diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index 3b1c01319c49..b2e4aeabd953 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -30,6 +30,7 @@ use fold::Folder;
 use feature_gate;
 
 use std::collections::{HashMap, HashSet};
+use std::path::PathBuf;
 use std::rc::Rc;
 use tokenstream;
 
@@ -602,8 +603,7 @@ pub struct ExtCtxt<'a> {
     pub derive_modes: HashMap>,
     pub recursion_count: usize,
 
-    pub filename: Option,
-    pub mod_path_stack: Vec,
+    pub directory: PathBuf,
     pub in_block: bool,
 }
 
@@ -626,8 +626,7 @@ impl<'a> ExtCtxt<'a> {
             derive_modes: HashMap::new(),
             recursion_count: 0,
 
-            filename: None,
-            mod_path_stack: Vec::new(),
+            directory: PathBuf::new(),
             in_block: false,
         }
     }
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index d06b77a5b054..5c548533e937 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -28,6 +28,8 @@ use visit;
 use visit::Visitor;
 use std_inject;
 
+use std::path::PathBuf;
+
 // A trait for AST nodes and AST node lists into which macro invocations may expand.
 trait MacroGenerable: Sized {
     // Expand the given MacResult using its appropriate `make_*` method.
@@ -566,7 +568,9 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
 
 impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
     fn fold_crate(&mut self, c: Crate) -> Crate {
-        self.cx.filename = Some(self.cx.parse_sess.codemap().span_to_filename(c.span));
+        let mut directory = PathBuf::from(self.cx.parse_sess.codemap().span_to_filename(c.span));
+        directory.pop();
+        self.cx.directory = directory;
         noop_fold_crate(c, self)
     }
 
@@ -591,18 +595,22 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
         let result;
         if let ast::ItemKind::Mod(ast::Mod { inner, .. }) = item.node {
             if item.span.contains(inner) {
-                self.push_mod_path(item.ident, &item.attrs);
+                let directory = self.cx.directory.clone();
+                self.cx.directory.push(&*{
+                    ::attr::first_attr_value_str_by_name(&item.attrs, "path")
+                        .unwrap_or(item.ident.name.as_str())
+                });
                 result = expand_item(item, self);
-                self.pop_mod_path();
+                self.cx.directory = directory;
             } else {
-                let filename = if inner != syntax_pos::DUMMY_SP {
-                    Some(self.cx.parse_sess.codemap().span_to_filename(inner))
-                } else { None };
-                let orig_filename = replace(&mut self.cx.filename, filename);
-                let orig_mod_path_stack = replace(&mut self.cx.mod_path_stack, Vec::new());
+                let mut directory = match inner {
+                    syntax_pos::DUMMY_SP => PathBuf::new(),
+                    _ => PathBuf::from(self.cx.parse_sess.codemap().span_to_filename(inner)),
+                };
+                directory.pop();
+                let directory = replace(&mut self.cx.directory, directory);
                 result = expand_item(item, self);
-                self.cx.filename = orig_filename;
-                self.cx.mod_path_stack = orig_mod_path_stack;
+                self.cx.directory = directory;
             }
         } else {
             result = expand_item(item, self);
@@ -636,21 +644,6 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
     }
 }
 
-impl<'a, 'b> MacroExpander<'a, 'b> {
-    fn push_mod_path(&mut self, id: Ident, attrs: &[ast::Attribute]) {
-        let default_path = id.name.as_str();
-        let file_path = match ::attr::first_attr_value_str_by_name(attrs, "path") {
-            Some(d) => d,
-            None => default_path,
-        };
-        self.cx.mod_path_stack.push(file_path)
-    }
-
-    fn pop_mod_path(&mut self) {
-        self.cx.mod_path_stack.pop().unwrap();
-    }
-}
-
 pub struct ExpansionConfig<'feat> {
     pub crate_name: String,
     pub features: Option<&'feat Features>,
diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs
index d197741e9a36..a4be84dfbf02 100644
--- a/src/libsyntax/ext/tt/macro_rules.rs
+++ b/src/libsyntax/ext/tt/macro_rules.rs
@@ -211,8 +211,7 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt,
                                            imported_from,
                                            rhs);
                 let mut p = Parser::new(cx.parse_sess(), cx.cfg(), Box::new(trncbr));
-                p.filename = cx.filename.clone();
-                p.mod_path_stack = cx.mod_path_stack.clone();
+                p.directory = cx.directory.clone();
                 p.restrictions = match cx.in_block {
                     true => Restrictions::NO_NONINLINE_MOD,
                     false => Restrictions::empty(),
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index ec9dc1bae5ad..6a0e40edded5 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -264,8 +264,7 @@ pub struct Parser<'a> {
     /// extra detail when the same error is seen twice
     pub obsolete_set: HashSet,
     /// Used to determine the path to externally loaded source files
-    pub filename: Option,
-    pub mod_path_stack: Vec,
+    pub directory: PathBuf,
     /// Stack of open delimiters and their spans. Used for error message.
     pub open_braces: Vec<(token::DelimToken, Span)>,
     /// Flag if this parser "owns" the directory that it is currently parsing
@@ -346,9 +345,11 @@ impl<'a> Parser<'a> {
     {
         let tok0 = rdr.real_token();
         let span = tok0.sp;
-        let filename = if span != syntax_pos::DUMMY_SP {
-            Some(sess.codemap().span_to_filename(span))
-        } else { None };
+        let mut directory = match span {
+            syntax_pos::DUMMY_SP => PathBuf::new(),
+            _ => PathBuf::from(sess.codemap().span_to_filename(span)),
+        };
+        directory.pop();
         let placeholder = TokenAndSpan {
             tok: token::Underscore,
             sp: span,
@@ -377,8 +378,7 @@ impl<'a> Parser<'a> {
             quote_depth: 0,
             parsing_token_tree: false,
             obsolete_set: HashSet::new(),
-            mod_path_stack: Vec::new(),
-            filename: filename,
+            directory: directory,
             open_braces: Vec::new(),
             owns_directory: true,
             root_module_name: None,
@@ -5306,27 +5306,24 @@ impl<'a> Parser<'a> {
             let (m, attrs) = self.eval_src_mod(id, &outer_attrs, id_span)?;
             Ok((id, m, Some(attrs)))
         } else {
-            self.push_mod_path(id, &outer_attrs);
+            let directory = self.directory.clone();
+            self.push_directory(id, &outer_attrs);
             self.expect(&token::OpenDelim(token::Brace))?;
             let mod_inner_lo = self.span.lo;
             let attrs = self.parse_inner_attributes()?;
             let m = self.parse_mod_items(&token::CloseDelim(token::Brace), mod_inner_lo)?;
-            self.pop_mod_path();
+            self.directory = directory;
             Ok((id, ItemKind::Mod(m), Some(attrs)))
         }
     }
 
-    fn push_mod_path(&mut self, id: Ident, attrs: &[Attribute]) {
+    fn push_directory(&mut self, id: Ident, attrs: &[Attribute]) {
         let default_path = self.id_to_interned_str(id);
         let file_path = match ::attr::first_attr_value_str_by_name(attrs, "path") {
             Some(d) => d,
             None => default_path,
         };
-        self.mod_path_stack.push(file_path)
-    }
-
-    fn pop_mod_path(&mut self) {
-        self.mod_path_stack.pop().unwrap();
+        self.directory.push(&*file_path)
     }
 
     pub fn submod_path_from_attr(attrs: &[ast::Attribute], dir_path: &Path) -> Option {
@@ -5374,18 +5371,11 @@ impl<'a> Parser<'a> {
                    id: ast::Ident,
                    outer_attrs: &[ast::Attribute],
                    id_sp: Span) -> PResult<'a, ModulePathSuccess> {
-        let mut prefix = PathBuf::from(self.filename.as_ref().unwrap());
-        prefix.pop();
-        let mut dir_path = prefix;
-        for part in &self.mod_path_stack {
-            dir_path.push(&**part);
-        }
-
-        if let Some(p) = Parser::submod_path_from_attr(outer_attrs, &dir_path) {
+        if let Some(p) = Parser::submod_path_from_attr(outer_attrs, &self.directory) {
             return Ok(ModulePathSuccess { path: p, owns_directory: true });
         }
 
-        let paths = Parser::default_submod_path(id, &dir_path, self.sess.codemap());
+        let paths = Parser::default_submod_path(id, &self.directory, self.sess.codemap());
 
         if self.restrictions.contains(Restrictions::NO_NONINLINE_MOD) {
             let msg =
@@ -5400,8 +5390,8 @@ impl<'a> Parser<'a> {
         } else if !self.owns_directory {
             let mut err = self.diagnostic().struct_span_err(id_sp,
                 "cannot declare a new module at this location");
-            let this_module = match self.mod_path_stack.last() {
-                Some(name) => name.to_string(),
+            let this_module = match self.directory.file_name() {
+                Some(file_name) => file_name.to_str().unwrap().to_owned(),
                 None => self.root_module_name.as_ref().unwrap().clone(),
             };
             err.span_note(id_sp,

From 234d68b7d35687999c36bc39ffd414bca7373a48 Mon Sep 17 00:00:00 2001
From: Jeffrey Seyfried 
Date: Tue, 30 Aug 2016 07:05:25 +0000
Subject: [PATCH 185/443] Improve `expand_type`.

---
 src/libsyntax/ext/expand.rs | 13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)

diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 5c548533e937..6f8af66632f0 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -489,14 +489,17 @@ fn expand_trait_item(ti: ast::TraitItem, fld: &mut MacroExpander)
 }
 
 pub fn expand_type(t: P, fld: &mut MacroExpander) -> P {
-    let t = match t.node.clone() {
+    let t = match t.node {
+        ast::TyKind::Mac(_) => t.unwrap(),
+        _ => return fold::noop_fold_ty(t, fld),
+    };
+
+    match t.node {
         ast::TyKind::Mac(mac) => {
             expand_mac_invoc(mac, None, Vec::new(), t.span, fld)
         }
-        _ => t
-    };
-
-    fold::noop_fold_ty(t, fld)
+        _ => unreachable!(),
+    }
 }
 
 /// A tree-folder that performs macro expansion

From 9b3bc7a9e9e35537823bc2a10fc078c1222ee7fd Mon Sep 17 00:00:00 2001
From: Jeffrey Seyfried 
Date: Wed, 31 Aug 2016 23:39:16 +0000
Subject: [PATCH 186/443] Remove `syntax::config::strip_unconfigured`, add
 `syntax::config::features`.

---
 src/librustc_driver/driver.rs | 20 +++--------
 src/libsyntax/config.rs       | 63 +++++++++++++++++++----------------
 src/libsyntax/ext/expand.rs   |  5 +--
 3 files changed, 41 insertions(+), 47 deletions(-)

diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs
index 065ef9e0ce15..8ed5b579ffc3 100644
--- a/src/librustc_driver/driver.rs
+++ b/src/librustc_driver/driver.rs
@@ -551,7 +551,7 @@ pub struct ExpansionResult<'a> {
 /// Returns `None` if we're aborting after handling -W help.
 pub fn phase_2_configure_and_expand<'a, F>(sess: &Session,
                                            cstore: &CStore,
-                                           mut krate: ast::Crate,
+                                           krate: ast::Crate,
                                            registry: Option,
                                            crate_name: &'a str,
                                            addl_plugins: Option>,
@@ -562,21 +562,9 @@ pub fn phase_2_configure_and_expand<'a, F>(sess: &Session,
 {
     let time_passes = sess.time_passes();
 
-    // strip before anything else because crate metadata may use #[cfg_attr]
-    // and so macros can depend on configuration variables, such as
-    //
-    //   #[macro_use] #[cfg(foo)]
-    //   mod bar { macro_rules! baz!(() => {{}}) }
-    //
-    // baz! should not use this definition unless foo is enabled.
-
-    krate = time(time_passes, "configuration", || {
-        let (krate, features) =
-            syntax::config::strip_unconfigured_items(krate, &sess.parse_sess, sess.opts.test);
-        // these need to be set "early" so that expansion sees `quote` if enabled.
-        *sess.features.borrow_mut() = features;
-        krate
-    });
+    let (mut krate, features) = syntax::config::features(krate, &sess.parse_sess, sess.opts.test);
+    // these need to be set "early" so that expansion sees `quote` if enabled.
+    *sess.features.borrow_mut() = features;
 
     *sess.crate_types.borrow_mut() = collect_crate_types(sess, &krate.attrs);
     *sess.crate_disambiguator.borrow_mut() =
diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs
index 69a979176521..7f6395997abe 100644
--- a/src/libsyntax/config.rs
+++ b/src/libsyntax/config.rs
@@ -10,7 +10,6 @@
 
 use attr::HasAttrs;
 use feature_gate::{emit_feature_err, EXPLAIN_STMT_ATTR_SYNTAX, Features, get_features, GateIssue};
-use fold::Folder;
 use {fold, attr};
 use ast;
 use codemap::{Spanned, respan};
@@ -27,6 +26,40 @@ pub struct StripUnconfigured<'a> {
     pub features: Option<&'a Features>,
 }
 
+// `cfg_attr`-process the crate's attributes and compute the crate's features.
+pub fn features(mut krate: ast::Crate, sess: &ParseSess, should_test: bool)
+                -> (ast::Crate, Features) {
+    let features;
+    {
+        let mut strip_unconfigured = StripUnconfigured {
+            config: &krate.config.clone(),
+            should_test: should_test,
+            sess: sess,
+            features: None,
+        };
+
+        let unconfigured_attrs = krate.attrs.clone();
+        let err_count = sess.span_diagnostic.err_count();
+        if let Some(attrs) = strip_unconfigured.configure(krate.attrs) {
+            krate.attrs = attrs;
+        } else { // the entire crate is unconfigured
+            krate.attrs = Vec::new();
+            krate.module.items = Vec::new();
+            return (krate, Features::new());
+        }
+
+        features = get_features(&sess.span_diagnostic, &krate.attrs);
+
+        // Avoid reconfiguring malformed `cfg_attr`s
+        if err_count == sess.span_diagnostic.err_count() {
+            strip_unconfigured.features = Some(&features);
+            strip_unconfigured.configure(unconfigured_attrs);
+        }
+    }
+
+    (krate, features)
+}
+
 impl<'a> StripUnconfigured<'a> {
     fn configure(&mut self, node: T) -> Option {
         let node = self.process_cfg_attrs(node);
@@ -125,34 +158,6 @@ impl<'a> StripUnconfigured<'a> {
     }
 }
 
-// Support conditional compilation by transforming the AST, stripping out
-// any items that do not belong in the current configuration
-pub fn strip_unconfigured_items(mut krate: ast::Crate, sess: &ParseSess, should_test: bool)
-                                -> (ast::Crate, Features) {
-    let features;
-    {
-        let mut strip_unconfigured = StripUnconfigured {
-            config: &krate.config.clone(),
-            should_test: should_test,
-            sess: sess,
-            features: None,
-        };
-
-        let err_count = sess.span_diagnostic.err_count();
-        let krate_attrs = strip_unconfigured.configure(krate.attrs.clone()).unwrap_or_default();
-        features = get_features(&sess.span_diagnostic, &krate_attrs);
-        if err_count < sess.span_diagnostic.err_count() {
-            krate.attrs = krate_attrs.clone(); // Avoid reconfiguring malformed `cfg_attr`s
-        }
-
-        strip_unconfigured.features = Some(&features);
-        krate = strip_unconfigured.fold_crate(krate);
-        krate.attrs = krate_attrs;
-    }
-
-    (krate, features)
-}
-
 impl<'a> fold::Folder for StripUnconfigured<'a> {
     fn fold_foreign_mod(&mut self, foreign_mod: ast::ForeignMod) -> ast::ForeignMod {
         ast::ForeignMod {
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 6f8af66632f0..92d053fd21b0 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -719,8 +719,9 @@ pub fn expand_crate_with_expander(expander: &mut MacroExpander,
     }
 
     let items = SmallVector::many(c.module.items);
-    expander.load_macros(&items);
-    c.module.items = items.into();
+    let configured = items.fold_with(&mut expander.strip_unconfigured());
+    expander.load_macros(&configured);
+    c.module.items = configured.into();
 
     let err_count = expander.cx.parse_sess.span_diagnostic.err_count();
     let mut ret = expander.fold_crate(c);

From de2e67836e23405e5bdc27cefa510fa562c5298f Mon Sep 17 00:00:00 2001
From: Jeffrey Seyfried 
Date: Sat, 27 Aug 2016 05:27:59 +0000
Subject: [PATCH 187/443] Add `Invocation` and `Expansion`, remove
 `MacroGenerable`.

---
 src/libsyntax/ext/expand.rs | 490 +++++++++++++++++++-----------------
 1 file changed, 259 insertions(+), 231 deletions(-)

diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 92d053fd21b0..485bd3ce10b4 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -30,249 +30,230 @@ use std_inject;
 
 use std::path::PathBuf;
 
-// A trait for AST nodes and AST node lists into which macro invocations may expand.
-trait MacroGenerable: Sized {
-    // Expand the given MacResult using its appropriate `make_*` method.
-    fn make_with<'a>(result: Box) -> Option;
+macro_rules! expansions {
+    ($($kind:ident: $ty:ty, $kind_name:expr, .$make:ident,
+            $(.$fold:ident)*  $(lift .$fold_elt:ident)*,
+            $(.$visit:ident)* $(lift .$visit_elt:ident)*;)*) => {
+        #[derive(Copy, Clone)]
+        enum ExpansionKind { OptExpr, $( $kind, )*  }
+        enum Expansion { OptExpr(Option>), $( $kind($ty), )* }
 
-    // Fold this node or list of nodes using the given folder.
-    fn fold_with(self, folder: &mut F) -> Self;
-    fn visit_with(&self, visitor: &mut V);
+        impl ExpansionKind {
+            fn name(self) -> &'static str {
+                match self {
+                    ExpansionKind::OptExpr => "expression",
+                    $( ExpansionKind::$kind => $kind_name, )*
+                }
+            }
 
-    // The user-friendly name of the node type (e.g. "expression", "item", etc.) for diagnostics.
-    fn kind_name() -> &'static str;
+            fn make_from<'a>(self, result: Box) -> Option {
+                match self {
+                    ExpansionKind::OptExpr => result.make_expr().map(Some).map(Expansion::OptExpr),
+                    $( ExpansionKind::$kind => result.$make().map(Expansion::$kind), )*
+                }
+            }
+        }
 
-    // Return a placeholder expansion to allow compilation to continue after an erroring expansion.
-    fn dummy(span: Span) -> Self {
-        Self::make_with(DummyResult::any(span)).unwrap()
+        impl Expansion {
+            fn make_opt_expr(self) -> Option> {
+                match self {
+                    Expansion::OptExpr(expr) => expr,
+                    _ => panic!("Expansion::make_* called on the wrong kind of expansion"),
+                }
+            }
+            $( fn $make(self) -> $ty {
+                match self {
+                    Expansion::$kind(ast) => ast,
+                    _ => panic!("Expansion::make_* called on the wrong kind of expansion"),
+                }
+            } )*
+
+            fn fold_with(self, folder: &mut F) -> Self {
+                use self::Expansion::*;
+                match self {
+                    OptExpr(expr) => OptExpr(expr.and_then(|expr| folder.fold_opt_expr(expr))),
+                    $($( $kind(ast) => $kind(folder.$fold(ast)), )*)*
+                    $($( $kind(ast) => {
+                        $kind(ast.into_iter().flat_map(|ast| folder.$fold_elt(ast)).collect())
+                    }, )*)*
+                }
+            }
+
+            fn visit_with(&self, visitor: &mut V) {
+                match *self {
+                    Expansion::OptExpr(Some(ref expr)) => visitor.visit_expr(expr),
+                    $($( Expansion::$kind(ref ast) => visitor.$visit(ast), )*)*
+                    $($( Expansion::$kind(ref ast) => for ast in ast.as_slice() {
+                        visitor.$visit_elt(ast);
+                    }, )*)*
+                    _ => {}
+                }
+            }
+        }
     }
 }
 
-macro_rules! impl_macro_generable {
-    ($($ty:ty: $kind_name:expr, .$make:ident,
-               $(.$fold:ident)*  $(lift .$fold_elt:ident)*,
-               $(.$visit:ident)* $(lift .$visit_elt:ident)*;)*) => { $(
-        impl MacroGenerable for $ty {
-            fn kind_name() -> &'static str { $kind_name }
-            fn make_with<'a>(result: Box) -> Option { result.$make() }
-            fn fold_with(self, folder: &mut F) -> Self {
-                $( folder.$fold(self) )*
-                $( self.into_iter().flat_map(|item| folder. $fold_elt (item)).collect() )*
-            }
-            fn visit_with(&self, visitor: &mut V) {
-                $( visitor.$visit(self) )*
-                $( for item in self.as_slice() { visitor. $visit_elt (item) } )*
-            }
-        }
-    )* }
-}
-
-impl_macro_generable! {
-    P: "expression", .make_expr, .fold_expr, .visit_expr;
-    P:  "pattern",    .make_pat,  .fold_pat,  .visit_pat;
-    P:   "type",       .make_ty,   .fold_ty,   .visit_ty;
-    SmallVector: "statement", .make_stmts, lift .fold_stmt, lift .visit_stmt;
-    SmallVector>: "item",   .make_items, lift .fold_item, lift .visit_item;
-    SmallVector:
+expansions! {
+    Expr: P, "expression", .make_expr, .fold_expr, .visit_expr;
+    Pat: P,   "pattern",    .make_pat,  .fold_pat,  .visit_pat;
+    Ty: P,     "type",       .make_ty,   .fold_ty,   .visit_ty;
+    Stmts: SmallVector, "statement", .make_stmts, lift .fold_stmt, lift .visit_stmt;
+    Items: SmallVector>, "item",   .make_items, lift .fold_item, lift .visit_item;
+    TraitItems: SmallVector,
         "trait item", .make_trait_items, lift .fold_trait_item, lift .visit_trait_item;
-    SmallVector:
+    ImplItems: SmallVector,
         "impl item",  .make_impl_items,  lift .fold_impl_item,  lift .visit_impl_item;
 }
 
-impl MacroGenerable for Option> {
-    fn kind_name() -> &'static str { "expression" }
-    fn make_with<'a>(result: Box) -> Option {
-        result.make_expr().map(Some)
-    }
-    fn fold_with(self, folder: &mut F) -> Self {
-        self.and_then(|expr| folder.fold_opt_expr(expr))
-    }
-    fn visit_with(&self, visitor: &mut V) {
-        self.as_ref().map(|expr| visitor.visit_expr(expr));
+impl ExpansionKind {
+    fn dummy(self, span: Span) -> Expansion {
+        self.make_from(DummyResult::any(span)).unwrap()
     }
 }
 
+pub struct Invocation {
+    span: Span,
+    attrs: Vec,
+    mac: ast::Mac,
+    ident: Option,
+    mark: Mark,
+    kind: ExpansionKind,
+}
+
 pub fn expand_expr(expr: ast::Expr, fld: &mut MacroExpander) -> P {
-    match expr.node {
-        // expr_mac should really be expr_ext or something; it's the
-        // entry-point for all syntax extensions.
-        ast::ExprKind::Mac(mac) => {
-            return expand_mac_invoc(mac, None, expr.attrs.into(), expr.span, fld);
-        }
-        _ => P(noop_fold_expr(expr, fld)),
-    }
-}
-
-struct MacroScopePlaceholder;
-impl MacResult for MacroScopePlaceholder {
-    fn make_items(self: Box) -> Option>> {
-        Some(SmallVector::one(P(ast::Item {
-            ident: keywords::Invalid.ident(),
-            attrs: Vec::new(),
-            id: ast::DUMMY_NODE_ID,
-            node: ast::ItemKind::Mac(dummy_spanned(ast::Mac_ {
-                path: ast::Path { span: syntax_pos::DUMMY_SP, global: false, segments: Vec::new() },
-                tts: Vec::new(),
-            })),
-            vis: ast::Visibility::Inherited,
-            span: syntax_pos::DUMMY_SP,
-        })))
+    if let ast::ExprKind::Mac(mac) = expr.node {
+        let invoc = fld.new_invoc(mac, expr.attrs.into(), expr.span, ExpansionKind::Expr);
+        expand_mac_invoc(invoc, fld).make_expr()
+    } else {
+        P(noop_fold_expr(expr, fld))
     }
 }
 
 /// Expand a macro invocation. Returns the result of expansion.
-fn expand_mac_invoc(mac: ast::Mac, ident: Option, attrs: Vec, span: Span,
-                       fld: &mut MacroExpander) -> T
-    where T: MacroGenerable,
-{
-    // It would almost certainly be cleaner to pass the whole macro invocation in,
-    // rather than pulling it apart and marking the tts and the ctxt separately.
+fn expand_mac_invoc(invoc: Invocation, fld: &mut MacroExpander) -> Expansion {
+    let Invocation { span, attrs, mac, ident, mark, kind } = invoc;
     let Mac_ { path, tts, .. } = mac.node;
-    let mark = Mark::fresh();
 
-    fn mac_result<'a>(path: &ast::Path, ident: Option, tts: Vec, mark: Mark,
-                      attrs: Vec, call_site: Span, fld: &'a mut MacroExpander)
-                      -> Option> {
-        // Detect use of feature-gated or invalid attributes on macro invoations
-        // since they will not be detected after macro expansion.
-        for attr in attrs.iter() {
-            feature_gate::check_attribute(&attr, &fld.cx.parse_sess.span_diagnostic,
-                                          &fld.cx.parse_sess.codemap(),
-                                          &fld.cx.ecfg.features.unwrap());
-        }
-
-        if path.segments.len() > 1 || path.global || !path.segments[0].parameters.is_empty() {
-            fld.cx.span_err(path.span, "expected macro name without module separators");
-            return None;
-        }
-
-        let extname = path.segments[0].identifier.name;
-        let extension = if let Some(extension) = fld.cx.syntax_env.find(extname) {
-            extension
-        } else {
-            let mut err = fld.cx.struct_span_err(path.span,
-                                                 &format!("macro undefined: '{}!'", &extname));
-            fld.cx.suggest_macro_name(&extname.as_str(), &mut err);
-            err.emit();
-            return None;
-        };
-
-        let ident = ident.unwrap_or(keywords::Invalid.ident());
-        let marked_tts = mark_tts(&tts, mark);
-        match *extension {
-            NormalTT(ref expandfun, exp_span, allow_internal_unstable) => {
-                if ident.name != keywords::Invalid.name() {
-                    let msg =
-                        format!("macro {}! expects no ident argument, given '{}'", extname, ident);
-                    fld.cx.span_err(path.span, &msg);
-                    return None;
-                }
-
-                fld.cx.bt_push(ExpnInfo {
-                    call_site: call_site,
-                    callee: NameAndSpan {
-                        format: MacroBang(extname),
-                        span: exp_span,
-                        allow_internal_unstable: allow_internal_unstable,
-                    },
-                });
-
-                Some(expandfun.expand(fld.cx, call_site, &marked_tts))
-            }
-
-            IdentTT(ref expander, tt_span, allow_internal_unstable) => {
-                if ident.name == keywords::Invalid.name() {
-                    fld.cx.span_err(path.span,
-                                    &format!("macro {}! expects an ident argument", extname));
-                    return None;
-                };
-
-                fld.cx.bt_push(ExpnInfo {
-                    call_site: call_site,
-                    callee: NameAndSpan {
-                        format: MacroBang(extname),
-                        span: tt_span,
-                        allow_internal_unstable: allow_internal_unstable,
-                    }
-                });
-
-                Some(expander.expand(fld.cx, call_site, ident, marked_tts))
-            }
-
-            MacroRulesTT => {
-                if ident.name == keywords::Invalid.name() {
-                    fld.cx.span_err(path.span,
-                                    &format!("macro {}! expects an ident argument", extname));
-                    return None;
-                };
-
-                fld.cx.bt_push(ExpnInfo {
-                    call_site: call_site,
-                    callee: NameAndSpan {
-                        format: MacroBang(extname),
-                        span: None,
-                        // `macro_rules!` doesn't directly allow unstable
-                        // (this is orthogonal to whether the macro it creates allows it)
-                        allow_internal_unstable: false,
-                    }
-                });
-
-                let def = ast::MacroDef {
-                    ident: ident,
-                    id: ast::DUMMY_NODE_ID,
-                    span: call_site,
-                    imported_from: None,
-                    use_locally: true,
-                    body: marked_tts,
-                    export: attr::contains_name(&attrs, "macro_export"),
-                    allow_internal_unstable: attr::contains_name(&attrs, "allow_internal_unstable"),
-                    attrs: attrs,
-                };
-
-                fld.cx.insert_macro(def.clone());
-
-                // macro_rules! has a side effect, but expands to nothing.
-                // If keep_macs is true, expands to a MacEager::items instead.
-                if fld.keep_macs {
-                    Some(MacEager::items(SmallVector::one(P(ast::Item {
-                        ident: def.ident,
-                        attrs: def.attrs.clone(),
-                        id: ast::DUMMY_NODE_ID,
-                        node: ast::ItemKind::Mac(ast::Mac {
-                            span: def.span,
-                            node: ast::Mac_ {
-                                path: path.clone(),
-                                tts: def.body.clone(),
-                            }
-                        }),
-                        vis: ast::Visibility::Inherited,
-                        span: def.span,
-                    }))))
-                } else {
-                    Some(Box::new(MacroScopePlaceholder))
-                }
-            }
-
-            MultiDecorator(..) | MultiModifier(..) => {
-                fld.cx.span_err(path.span,
-                                &format!("`{}` can only be used in attributes", extname));
-                None
-            }
-        }
+    // Detect use of feature-gated or invalid attributes on macro invoations
+    // since they will not be detected after macro expansion.
+    for attr in attrs.iter() {
+        feature_gate::check_attribute(&attr, &fld.cx.parse_sess.span_diagnostic,
+                                      &fld.cx.parse_sess.codemap(),
+                                      &fld.cx.ecfg.features.unwrap());
     }
 
-    let opt_expanded = T::make_with(match mac_result(&path, ident, tts, mark, attrs, span, fld) {
-        Some(result) => result,
-        None => return T::dummy(span),
-    });
+    if path.segments.len() > 1 || path.global || !path.segments[0].parameters.is_empty() {
+        fld.cx.span_err(path.span, "expected macro name without module separators");
+        return kind.dummy(span);
+    }
+
+    let extname = path.segments[0].identifier.name;
+    let extension = if let Some(extension) = fld.cx.syntax_env.find(extname) {
+        extension
+    } else {
+        let mut err =
+            fld.cx.struct_span_err(path.span, &format!("macro undefined: '{}!'", &extname));
+        fld.cx.suggest_macro_name(&extname.as_str(), &mut err);
+        err.emit();
+        return kind.dummy(span);
+    };
+
+    let ident = ident.unwrap_or(keywords::Invalid.ident());
+    let marked_tts = mark_tts(&tts, mark);
+    let opt_expanded = match *extension {
+        NormalTT(ref expandfun, exp_span, allow_internal_unstable) => {
+            if ident.name != keywords::Invalid.name() {
+                let msg =
+                    format!("macro {}! expects no ident argument, given '{}'", extname, ident);
+                fld.cx.span_err(path.span, &msg);
+                return kind.dummy(span);
+            }
+
+            fld.cx.bt_push(ExpnInfo {
+                call_site: span,
+                callee: NameAndSpan {
+                    format: MacroBang(extname),
+                    span: exp_span,
+                    allow_internal_unstable: allow_internal_unstable,
+                },
+            });
+
+            kind.make_from(expandfun.expand(fld.cx, span, &marked_tts))
+        }
+
+        IdentTT(ref expander, tt_span, allow_internal_unstable) => {
+            if ident.name == keywords::Invalid.name() {
+                fld.cx.span_err(path.span,
+                                &format!("macro {}! expects an ident argument", extname));
+                return kind.dummy(span);
+            };
+
+            fld.cx.bt_push(ExpnInfo {
+                call_site: span,
+                callee: NameAndSpan {
+                    format: MacroBang(extname),
+                    span: tt_span,
+                    allow_internal_unstable: allow_internal_unstable,
+                }
+            });
+
+            kind.make_from(expander.expand(fld.cx, span, ident, marked_tts))
+        }
+
+        MacroRulesTT => {
+            if ident.name == keywords::Invalid.name() {
+                fld.cx.span_err(path.span,
+                                &format!("macro {}! expects an ident argument", extname));
+                return kind.dummy(span);
+            };
+
+            fld.cx.bt_push(ExpnInfo {
+                call_site: span,
+                callee: NameAndSpan {
+                    format: MacroBang(extname),
+                    span: None,
+                    // `macro_rules!` doesn't directly allow unstable
+                    // (this is orthogonal to whether the macro it creates allows it)
+                    allow_internal_unstable: false,
+                }
+            });
+
+            let def = ast::MacroDef {
+                ident: ident,
+                id: ast::DUMMY_NODE_ID,
+                span: span,
+                imported_from: None,
+                use_locally: true,
+                body: marked_tts,
+                export: attr::contains_name(&attrs, "macro_export"),
+                allow_internal_unstable: attr::contains_name(&attrs, "allow_internal_unstable"),
+                attrs: attrs,
+            };
+
+            fld.cx.insert_macro(def.clone());
+
+            // If keep_macs is true, expands to a MacEager::items instead.
+            if fld.keep_macs {
+                Some(reconstruct_macro_rules(&def, &path))
+            } else {
+                Some(macro_scope_placeholder())
+            }
+        }
+
+        MultiDecorator(..) | MultiModifier(..) => {
+            fld.cx.span_err(path.span,
+                            &format!("`{}` can only be used in attributes", extname));
+            return kind.dummy(span);
+        }
+    };
 
     let expanded = if let Some(expanded) = opt_expanded {
         expanded
     } else {
         let msg = format!("non-{kind} macro in {kind} position: {name}",
-                          name = path.segments[0].identifier.name, kind = T::kind_name());
+                          name = path.segments[0].identifier.name, kind = kind.name());
         fld.cx.span_err(path.span, &msg);
-        return T::dummy(span);
+        return kind.dummy(span);
     };
 
     let marked = expanded.fold_with(&mut Marker { mark: mark, expn_id: Some(fld.cx.backtrace()) });
@@ -342,8 +323,8 @@ fn expand_stmt(stmt: Stmt, fld: &mut MacroExpander) -> SmallVector {
         _ => return noop_fold_stmt(stmt, fld)
     };
 
-    let mut fully_expanded: SmallVector =
-        expand_mac_invoc(mac, None, attrs.into(), stmt.span, fld);
+    let invoc = fld.new_invoc(mac, attrs.into(), stmt.span, ExpansionKind::Stmts);
+    let mut fully_expanded = expand_mac_invoc(invoc, fld).make_stmts();
 
     // If this is a macro invocation with a semicolon, then apply that
     // semicolon to the final statement produced by expansion.
@@ -361,11 +342,12 @@ fn expand_pat(p: P, fld: &mut MacroExpander) -> P {
         PatKind::Mac(_) => {}
         _ => return noop_fold_pat(p, fld)
     }
-    p.and_then(|ast::Pat {node, span, ..}| {
-        match node {
-            PatKind::Mac(mac) => expand_mac_invoc(mac, None, Vec::new(), span, fld),
-            _ => unreachable!()
+    p.and_then(|p| match p.node {
+        PatKind::Mac(mac) => {
+            let invoc = fld.new_invoc(mac, Vec::new(), p.span, ExpansionKind::Pat);
+            expand_mac_invoc(invoc, fld).make_pat()
         }
+        _ => unreachable!(),
     })
 }
 
@@ -380,8 +362,11 @@ fn expand_multi_modified(a: Annotatable, fld: &mut MacroExpander) -> SmallVector
                     return SmallVector::one(Annotatable::Item(it));
                 }
                 it.and_then(|it| match it.node {
-                    ItemKind::Mac(mac) =>
-                        expand_mac_invoc(mac, Some(it.ident), it.attrs, it.span, fld),
+                    ItemKind::Mac(mac) => {
+                        let mut invoc = fld.new_invoc(mac, it.attrs, it.span, ExpansionKind::Items);
+                        invoc.ident = Some(it.ident);
+                        expand_mac_invoc(invoc, fld).make_items()
+                    }
                     _ => unreachable!(),
                 })
             }
@@ -472,7 +457,8 @@ fn expand_impl_item(ii: ast::ImplItem, fld: &mut MacroExpander)
                  -> SmallVector {
     match ii.node {
         ast::ImplItemKind::Macro(mac) => {
-            expand_mac_invoc(mac, None, ii.attrs, ii.span, fld)
+            let invoc = fld.new_invoc(mac, ii.attrs, ii.span, ExpansionKind::ImplItems);
+            expand_mac_invoc(invoc, fld).make_impl_items()
         }
         _ => fold::noop_fold_impl_item(ii, fld)
     }
@@ -482,7 +468,8 @@ fn expand_trait_item(ti: ast::TraitItem, fld: &mut MacroExpander)
                      -> SmallVector {
     match ti.node {
         ast::TraitItemKind::Macro(mac) => {
-            expand_mac_invoc(mac, None, ti.attrs, ti.span, fld)
+            let invoc = fld.new_invoc(mac, ti.attrs, ti.span, ExpansionKind::TraitItems);
+            expand_mac_invoc(invoc, fld).make_trait_items()
         }
         _ => fold::noop_fold_trait_item(ti, fld)
     }
@@ -496,7 +483,8 @@ pub fn expand_type(t: P, fld: &mut MacroExpander) -> P {
 
     match t.node {
         ast::TyKind::Mac(mac) => {
-            expand_mac_invoc(mac, None, Vec::new(), t.span, fld)
+            let invoc = fld.new_invoc(mac, Vec::new(), t.span, ExpansionKind::Ty);
+            expand_mac_invoc(invoc, fld).make_ty()
         }
         _ => unreachable!(),
     }
@@ -529,7 +517,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         }
     }
 
-    fn load_macros(&mut self, node: &T) {
+    fn load_macros(&mut self, node: &Expansion) {
         struct MacroLoadingVisitor<'a, 'b: 'a>{
             cx: &'a mut ExtCtxt<'b>,
             at_crate_root: bool,
@@ -567,6 +555,12 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
             cx: self.cx,
         });
     }
+
+    fn new_invoc(&self, mac: ast::Mac, attrs: Vec, span: Span, kind: ExpansionKind)
+                 -> Invocation {
+        let mark = Mark::fresh();
+        Invocation { span: span, attrs: attrs, mac: mac, mark: mark, kind: kind, ident: None }
+    }
 }
 
 impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
@@ -583,8 +577,11 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
 
     fn fold_opt_expr(&mut self, expr: P) -> Option> {
         expr.and_then(|expr| match expr.node {
-            ast::ExprKind::Mac(mac) =>
-                expand_mac_invoc(mac, None, expr.attrs.into(), expr.span, self),
+            ast::ExprKind::Mac(mac) => {
+                let invoc =
+                    self.new_invoc(mac, expr.attrs.into(), expr.span, ExpansionKind::OptExpr);
+                expand_mac_invoc(invoc, self).make_opt_expr()
+            }
             _ => Some(expand_expr(expr, self)),
         })
     }
@@ -647,6 +644,37 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
     }
 }
 
+fn macro_scope_placeholder() -> Expansion {
+    Expansion::Items(SmallVector::one(P(ast::Item {
+        ident: keywords::Invalid.ident(),
+        attrs: Vec::new(),
+        id: ast::DUMMY_NODE_ID,
+        node: ast::ItemKind::Mac(dummy_spanned(ast::Mac_ {
+            path: ast::Path { span: syntax_pos::DUMMY_SP, global: false, segments: Vec::new() },
+            tts: Vec::new(),
+        })),
+        vis: ast::Visibility::Inherited,
+        span: syntax_pos::DUMMY_SP,
+    })))
+}
+
+fn reconstruct_macro_rules(def: &ast::MacroDef, path: &ast::Path) -> Expansion {
+    Expansion::Items(SmallVector::one(P(ast::Item {
+        ident: def.ident,
+        attrs: def.attrs.clone(),
+        id: ast::DUMMY_NODE_ID,
+        node: ast::ItemKind::Mac(ast::Mac {
+            span: def.span,
+            node: ast::Mac_ {
+                path: path.clone(),
+                tts: def.body.clone(),
+            }
+        }),
+        vis: ast::Visibility::Inherited,
+        span: def.span,
+    })))
+}
+
 pub struct ExpansionConfig<'feat> {
     pub crate_name: String,
     pub features: Option<&'feat Features>,
@@ -718,10 +746,10 @@ pub fn expand_crate_with_expander(expander: &mut MacroExpander,
         expander.cx.syntax_env.insert(name, extension);
     }
 
-    let items = SmallVector::many(c.module.items);
+    let items = Expansion::Items(SmallVector::many(c.module.items));
     let configured = items.fold_with(&mut expander.strip_unconfigured());
     expander.load_macros(&configured);
-    c.module.items = configured.into();
+    c.module.items = configured.make_items().into();
 
     let err_count = expander.cx.parse_sess.span_diagnostic.err_count();
     let mut ret = expander.fold_crate(c);

From 3cba93f9933fe96fb77d625a480eb4cdddeed91f Mon Sep 17 00:00:00 2001
From: Jeffrey Seyfried 
Date: Sat, 27 Aug 2016 06:27:35 +0000
Subject: [PATCH 188/443] Refactor `with_exts_frame` from a macro to a
 function.

---
 src/libsyntax/ext/expand.rs | 26 ++++++++++----------------
 1 file changed, 10 insertions(+), 16 deletions(-)

diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 485bd3ce10b4..481278eb2574 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -270,18 +270,6 @@ fn expand_mac_invoc(invoc: Invocation, fld: &mut MacroExpander) -> Expansion {
     fully_expanded
 }
 
-// eval $e with a new exts frame.
-// must be a macro so that $e isn't evaluated too early.
-macro_rules! with_exts_frame {
-    ($extsboxexpr:expr,$macros_escape:expr,$e:expr) =>
-    ({$extsboxexpr.push_frame();
-      $extsboxexpr.info().macros_escape = $macros_escape;
-      let result = $e;
-      $extsboxexpr.pop_frame();
-      result
-     })
-}
-
 // When we enter a module, record it, for the sake of `module!`
 pub fn expand_item(it: P, fld: &mut MacroExpander)
                    -> SmallVector> {
@@ -378,9 +366,7 @@ fn expand_multi_modified(a: Annotatable, fld: &mut MacroExpander) -> SmallVector
                     fld.cx.mod_push(it.ident);
                 }
                 let macro_use = contains_macro_use(fld, &it.attrs);
-                let result = with_exts_frame!(fld.cx.syntax_env,
-                                              macro_use,
-                                              noop_fold_item(it, fld));
+                let result = fld.with_exts_frame(macro_use, |fld| noop_fold_item(it, fld));
                 if valid_ident {
                     fld.cx.mod_pop();
                 }
@@ -561,6 +547,14 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         let mark = Mark::fresh();
         Invocation { span: span, attrs: attrs, mac: mac, mark: mark, kind: kind, ident: None }
     }
+
+    fn with_exts_frame T>(&mut self, macros_escape: bool, f: F) -> T {
+        self.cx.syntax_env.push_frame();
+        self.cx.syntax_env.info().macros_escape = macros_escape;
+        let result = f(self);
+        self.cx.syntax_env.pop_frame();
+        result
+    }
 }
 
 impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
@@ -624,7 +618,7 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
 
     fn fold_block(&mut self, block: P) -> P {
         let was_in_block = ::std::mem::replace(&mut self.cx.in_block, true);
-        let result = with_exts_frame!(self.cx.syntax_env, false, noop_fold_block(block, self));
+        let result = self.with_exts_frame(false, |this| noop_fold_block(block, this));
         self.cx.in_block = was_in_block;
         result
     }

From fca80c983d486632d2fe12aed270af332ce01598 Mon Sep 17 00:00:00 2001
From: Jeffrey Seyfried 
Date: Fri, 2 Sep 2016 06:14:38 +0000
Subject: [PATCH 189/443] Generalize `Invocation` to include
 modifiers/decorators.

---
 src/libsyntax/ext/base.rs   |  10 --
 src/libsyntax/ext/expand.rs | 223 ++++++++++++++++++++++--------------
 2 files changed, 138 insertions(+), 95 deletions(-)

diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index b2e4aeabd953..769a5af0262c 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -91,16 +91,6 @@ impl Annotatable {
             _ => panic!("expected Item")
         }
     }
-
-    pub fn fold_with(self, folder: &mut F) -> SmallVector {
-        match self {
-            Annotatable::Item(item) => folder.fold_item(item).map(Annotatable::Item),
-            Annotatable::ImplItem(item) =>
-                folder.fold_impl_item(item.unwrap()).map(|item| Annotatable::ImplItem(P(item))),
-            Annotatable::TraitItem(item) =>
-                folder.fold_trait_item(item.unwrap()).map(|item| Annotatable::TraitItem(P(item))),
-        }
-    }
 }
 
 // A more flexible ItemDecorator.
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 481278eb2574..66a766a666bb 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -109,29 +109,104 @@ impl ExpansionKind {
     fn dummy(self, span: Span) -> Expansion {
         self.make_from(DummyResult::any(span)).unwrap()
     }
+
+    fn expect_from_annotatables>(self, items: I) -> Expansion {
+        let items = items.into_iter();
+        match self {
+            ExpansionKind::Items =>
+                Expansion::Items(items.map(Annotatable::expect_item).collect()),
+            ExpansionKind::ImplItems =>
+                Expansion::ImplItems(items.map(Annotatable::expect_impl_item).collect()),
+            ExpansionKind::TraitItems =>
+                Expansion::TraitItems(items.map(Annotatable::expect_trait_item).collect()),
+            _ => unreachable!(),
+        }
+    }
 }
 
 pub struct Invocation {
-    span: Span,
-    attrs: Vec,
-    mac: ast::Mac,
-    ident: Option,
+    kind: InvocationKind,
+    expansion_kind: ExpansionKind,
     mark: Mark,
-    kind: ExpansionKind,
+}
+
+enum InvocationKind {
+    Bang {
+        attrs: Vec,
+        mac: ast::Mac,
+        ident: Option,
+        span: Span,
+    },
+    Attr {
+        attr: ast::Attribute,
+        item: Annotatable,
+    },
 }
 
 pub fn expand_expr(expr: ast::Expr, fld: &mut MacroExpander) -> P {
     if let ast::ExprKind::Mac(mac) = expr.node {
-        let invoc = fld.new_invoc(mac, expr.attrs.into(), expr.span, ExpansionKind::Expr);
-        expand_mac_invoc(invoc, fld).make_expr()
+        let invoc = fld.new_bang_invoc(mac, expr.attrs.into(), expr.span, ExpansionKind::Expr);
+        expand_invoc(invoc, fld).make_expr()
     } else {
         P(noop_fold_expr(expr, fld))
     }
 }
 
+fn expand_invoc(invoc: Invocation, fld: &mut MacroExpander) -> Expansion {
+    match invoc.kind {
+        InvocationKind::Bang { .. } => expand_bang_invoc(invoc, fld),
+        InvocationKind::Attr { .. } => expand_attr_invoc(invoc, fld),
+    }
+}
+
+fn expand_attr_invoc(invoc: Invocation, fld: &mut MacroExpander) -> Expansion {
+    let Invocation { expansion_kind: kind, .. } = invoc;
+    let (attr, item) = match invoc.kind {
+        InvocationKind::Attr { attr, item } => (attr, item),
+        _ => unreachable!(),
+    };
+
+    let extension = match fld.cx.syntax_env.find(intern(&attr.name())) {
+        Some(extension) => extension,
+        None => unreachable!(),
+    };
+
+    attr::mark_used(&attr);
+    fld.cx.bt_push(ExpnInfo {
+        call_site: attr.span,
+        callee: NameAndSpan {
+            format: MacroAttribute(intern(&attr.name())),
+            span: Some(attr.span),
+            allow_internal_unstable: false,
+        }
+    });
+
+    let modified = match *extension {
+        MultiModifier(ref mac) => {
+            kind.expect_from_annotatables(mac.expand(fld.cx, attr.span, &attr.node.value, item))
+        }
+        MultiDecorator(ref mac) => {
+            let mut items = Vec::new();
+            mac.expand(fld.cx, attr.span, &attr.node.value, &item, &mut |item| items.push(item));
+            items.push(item);
+            kind.expect_from_annotatables(items)
+        }
+        _ => unreachable!(),
+    };
+
+    fld.cx.bt_pop();
+
+    let configured = modified.fold_with(&mut fld.strip_unconfigured());
+    configured.fold_with(fld)
+}
+
 /// Expand a macro invocation. Returns the result of expansion.
-fn expand_mac_invoc(invoc: Invocation, fld: &mut MacroExpander) -> Expansion {
-    let Invocation { span, attrs, mac, ident, mark, kind } = invoc;
+fn expand_bang_invoc(invoc: Invocation, fld: &mut MacroExpander) -> Expansion {
+    let Invocation { mark, expansion_kind: kind, .. } = invoc;
+    let (attrs, mac, ident, span) = match invoc.kind {
+        InvocationKind::Bang { attrs, mac, ident, span } => (attrs, mac, ident, span),
+        _ => unreachable!(),
+    };
     let Mac_ { path, tts, .. } = mac.node;
 
     // Detect use of feature-gated or invalid attributes on macro invoations
@@ -270,11 +345,8 @@ fn expand_mac_invoc(invoc: Invocation, fld: &mut MacroExpander) -> Expansion {
     fully_expanded
 }
 
-// When we enter a module, record it, for the sake of `module!`
-pub fn expand_item(it: P, fld: &mut MacroExpander)
-                   -> SmallVector> {
-    expand_annotatable(Annotatable::Item(it), fld)
-        .into_iter().map(|i| i.expect_item()).collect()
+pub fn expand_item(it: P, fld: &mut MacroExpander) -> SmallVector> {
+    expand_annotatable(Annotatable::Item(it), fld).make_items()
 }
 
 // does this attribute list contain "macro_use" ?
@@ -311,8 +383,8 @@ fn expand_stmt(stmt: Stmt, fld: &mut MacroExpander) -> SmallVector {
         _ => return noop_fold_stmt(stmt, fld)
     };
 
-    let invoc = fld.new_invoc(mac, attrs.into(), stmt.span, ExpansionKind::Stmts);
-    let mut fully_expanded = expand_mac_invoc(invoc, fld).make_stmts();
+    let invoc = fld.new_bang_invoc(mac, attrs.into(), stmt.span, ExpansionKind::Stmts);
+    let mut fully_expanded = expand_invoc(invoc, fld).make_stmts();
 
     // If this is a macro invocation with a semicolon, then apply that
     // semicolon to the final statement produced by expansion.
@@ -332,14 +404,14 @@ fn expand_pat(p: P, fld: &mut MacroExpander) -> P {
     }
     p.and_then(|p| match p.node {
         PatKind::Mac(mac) => {
-            let invoc = fld.new_invoc(mac, Vec::new(), p.span, ExpansionKind::Pat);
-            expand_mac_invoc(invoc, fld).make_pat()
+            let invoc = fld.new_bang_invoc(mac, Vec::new(), p.span, ExpansionKind::Pat);
+            expand_invoc(invoc, fld).make_pat()
         }
         _ => unreachable!(),
     })
 }
 
-fn expand_multi_modified(a: Annotatable, fld: &mut MacroExpander) -> SmallVector {
+fn expand_multi_modified(a: Annotatable, fld: &mut MacroExpander) -> Expansion {
     match a {
         Annotatable::Item(it) => match it.node {
             ast::ItemKind::Mac(..) => {
@@ -347,13 +419,15 @@ fn expand_multi_modified(a: Annotatable, fld: &mut MacroExpander) -> SmallVector
                     ItemKind::Mac(ref mac) => mac.node.path.segments.is_empty(),
                     _ => unreachable!(),
                 } {
-                    return SmallVector::one(Annotatable::Item(it));
+                    return Expansion::Items(SmallVector::one(it));
                 }
                 it.and_then(|it| match it.node {
                     ItemKind::Mac(mac) => {
-                        let mut invoc = fld.new_invoc(mac, it.attrs, it.span, ExpansionKind::Items);
-                        invoc.ident = Some(it.ident);
-                        expand_mac_invoc(invoc, fld).make_items()
+                        let invoc =
+                            fld.new_invoc(ExpansionKind::Items, InvocationKind::Bang {
+                                mac: mac, attrs: it.attrs, ident: Some(it.ident), span: it.span,
+                            });
+                        expand_invoc(invoc, fld)
                     }
                     _ => unreachable!(),
                 })
@@ -370,31 +444,24 @@ fn expand_multi_modified(a: Annotatable, fld: &mut MacroExpander) -> SmallVector
                 if valid_ident {
                     fld.cx.mod_pop();
                 }
-                result
+                Expansion::Items(result)
             },
-            _ => noop_fold_item(it, fld),
-        }.into_iter().map(|i| Annotatable::Item(i)).collect(),
+            _ => Expansion::Items(noop_fold_item(it, fld)),
+        },
 
-        Annotatable::TraitItem(it) => {
-            expand_trait_item(it.unwrap(), fld).into_iter().
-                map(|it| Annotatable::TraitItem(P(it))).collect()
-        }
-
-        Annotatable::ImplItem(ii) => {
-            expand_impl_item(ii.unwrap(), fld).into_iter().
-                map(|ii| Annotatable::ImplItem(P(ii))).collect()
-        }
+        Annotatable::TraitItem(it) => Expansion::TraitItems(expand_trait_item(it.unwrap(), fld)),
+        Annotatable::ImplItem(ii) => Expansion::ImplItems(expand_impl_item(ii.unwrap(), fld)),
     }
 }
 
-fn expand_annotatable(mut item: Annotatable, fld: &mut MacroExpander) -> SmallVector {
-    let mut multi_modifier = None;
+fn expand_annotatable(mut item: Annotatable, fld: &mut MacroExpander) -> Expansion {
+    let mut attr = None;
     item = item.map_attrs(|mut attrs| {
         for i in 0..attrs.len() {
             if let Some(extension) = fld.cx.syntax_env.find(intern(&attrs[i].name())) {
                 match *extension {
                     MultiModifier(..) | MultiDecorator(..) => {
-                        multi_modifier = Some((attrs.remove(i), extension));
+                        attr = Some(attrs.remove(i));
                         break;
                     }
                     _ => {}
@@ -404,38 +471,16 @@ fn expand_annotatable(mut item: Annotatable, fld: &mut MacroExpander) -> SmallVe
         attrs
     });
 
-    match multi_modifier {
-        None => expand_multi_modified(item, fld),
-        Some((attr, extension)) => {
-            attr::mark_used(&attr);
-            fld.cx.bt_push(ExpnInfo {
-                call_site: attr.span,
-                callee: NameAndSpan {
-                    format: MacroAttribute(intern(&attr.name())),
-                    span: Some(attr.span),
-                    allow_internal_unstable: false,
-                }
-            });
-
-            let modified = match *extension {
-                MultiModifier(ref mac) => mac.expand(fld.cx, attr.span, &attr.node.value, item),
-                MultiDecorator(ref mac) => {
-                    let mut items = Vec::new();
-                    mac.expand(fld.cx, attr.span, &attr.node.value, &item,
-                               &mut |item| items.push(item));
-                    items.push(item);
-                    items
-                }
-                _ => unreachable!(),
-            };
-
-            fld.cx.bt_pop();
-            let configured = modified.into_iter().flat_map(|it| {
-                it.fold_with(&mut fld.strip_unconfigured())
-            }).collect::>();
-
-            configured.into_iter().flat_map(|it| expand_annotatable(it, fld)).collect()
-        }
+    if let Some(attr) = attr {
+        let kind = match item {
+            Annotatable::Item(_) => ExpansionKind::Items,
+            Annotatable::ImplItem(_) => ExpansionKind::ImplItems,
+            Annotatable::TraitItem(_) => ExpansionKind::TraitItems,
+        };
+        let invoc = fld.new_invoc(kind, InvocationKind::Attr { attr: attr, item: item });
+        expand_invoc(invoc, fld)
+    } else {
+        expand_multi_modified(item, fld)
     }
 }
 
@@ -443,8 +488,8 @@ fn expand_impl_item(ii: ast::ImplItem, fld: &mut MacroExpander)
                  -> SmallVector {
     match ii.node {
         ast::ImplItemKind::Macro(mac) => {
-            let invoc = fld.new_invoc(mac, ii.attrs, ii.span, ExpansionKind::ImplItems);
-            expand_mac_invoc(invoc, fld).make_impl_items()
+            let invoc = fld.new_bang_invoc(mac, ii.attrs, ii.span, ExpansionKind::ImplItems);
+            expand_invoc(invoc, fld).make_impl_items()
         }
         _ => fold::noop_fold_impl_item(ii, fld)
     }
@@ -454,8 +499,8 @@ fn expand_trait_item(ti: ast::TraitItem, fld: &mut MacroExpander)
                      -> SmallVector {
     match ti.node {
         ast::TraitItemKind::Macro(mac) => {
-            let invoc = fld.new_invoc(mac, ti.attrs, ti.span, ExpansionKind::TraitItems);
-            expand_mac_invoc(invoc, fld).make_trait_items()
+            let invoc = fld.new_bang_invoc(mac, ti.attrs, ti.span, ExpansionKind::TraitItems);
+            expand_invoc(invoc, fld).make_trait_items()
         }
         _ => fold::noop_fold_trait_item(ti, fld)
     }
@@ -469,8 +514,8 @@ pub fn expand_type(t: P, fld: &mut MacroExpander) -> P {
 
     match t.node {
         ast::TyKind::Mac(mac) => {
-            let invoc = fld.new_invoc(mac, Vec::new(), t.span, ExpansionKind::Ty);
-            expand_mac_invoc(invoc, fld).make_ty()
+            let invoc = fld.new_bang_invoc(mac, Vec::new(), t.span, ExpansionKind::Ty);
+            expand_invoc(invoc, fld).make_ty()
         }
         _ => unreachable!(),
     }
@@ -542,10 +587,20 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         });
     }
 
-    fn new_invoc(&self, mac: ast::Mac, attrs: Vec, span: Span, kind: ExpansionKind)
+    fn new_invoc(&self, expansion_kind: ExpansionKind, kind: InvocationKind)
                  -> Invocation {
-        let mark = Mark::fresh();
-        Invocation { span: span, attrs: attrs, mac: mac, mark: mark, kind: kind, ident: None }
+        Invocation { mark: Mark::fresh(), kind: kind, expansion_kind: expansion_kind }
+    }
+
+    fn new_bang_invoc(
+        &self, mac: ast::Mac, attrs: Vec, span: Span, kind: ExpansionKind,
+    ) -> Invocation {
+        self.new_invoc(kind, InvocationKind::Bang {
+            attrs: attrs,
+            mac: mac,
+            ident: None,
+            span: span,
+        })
     }
 
     fn with_exts_frame T>(&mut self, macros_escape: bool, f: F) -> T {
@@ -573,8 +628,8 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
         expr.and_then(|expr| match expr.node {
             ast::ExprKind::Mac(mac) => {
                 let invoc =
-                    self.new_invoc(mac, expr.attrs.into(), expr.span, ExpansionKind::OptExpr);
-                expand_mac_invoc(invoc, self).make_opt_expr()
+                    self.new_bang_invoc(mac, expr.attrs.into(), expr.span, ExpansionKind::OptExpr);
+                expand_invoc(invoc, self).make_opt_expr()
             }
             _ => Some(expand_expr(expr, self)),
         })
@@ -624,13 +679,11 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
     }
 
     fn fold_trait_item(&mut self, i: ast::TraitItem) -> SmallVector {
-        expand_annotatable(Annotatable::TraitItem(P(i)), self)
-            .into_iter().map(|i| i.expect_trait_item()).collect()
+        expand_annotatable(Annotatable::TraitItem(P(i)), self).make_trait_items()
     }
 
     fn fold_impl_item(&mut self, i: ast::ImplItem) -> SmallVector {
-        expand_annotatable(Annotatable::ImplItem(P(i)), self)
-            .into_iter().map(|i| i.expect_impl_item()).collect()
+        expand_annotatable(Annotatable::ImplItem(P(i)), self).make_impl_items()
     }
 
     fn fold_ty(&mut self, ty: P) -> P {

From 8be8cf854017e3b41324158868e9097fa6cdcc4d Mon Sep 17 00:00:00 2001
From: Jeffrey Seyfried 
Date: Sun, 28 Aug 2016 03:11:33 +0000
Subject: [PATCH 190/443] Refactor away `expand_item`.

---
 src/libsyntax/ext/expand.rs | 10 +++-------
 1 file changed, 3 insertions(+), 7 deletions(-)

diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 66a766a666bb..687c5e2fdfb8 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -345,10 +345,6 @@ fn expand_bang_invoc(invoc: Invocation, fld: &mut MacroExpander) -> Expansion {
     fully_expanded
 }
 
-pub fn expand_item(it: P, fld: &mut MacroExpander) -> SmallVector> {
-    expand_annotatable(Annotatable::Item(it), fld).make_items()
-}
-
 // does this attribute list contain "macro_use" ?
 fn contains_macro_use(fld: &mut MacroExpander, attrs: &[ast::Attribute]) -> bool {
     for attr in attrs {
@@ -649,7 +645,7 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
                     ::attr::first_attr_value_str_by_name(&item.attrs, "path")
                         .unwrap_or(item.ident.name.as_str())
                 });
-                result = expand_item(item, self);
+                result = expand_annotatable(Annotatable::Item(item), self).make_items();
                 self.cx.directory = directory;
             } else {
                 let mut directory = match inner {
@@ -658,11 +654,11 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
                 };
                 directory.pop();
                 let directory = replace(&mut self.cx.directory, directory);
-                result = expand_item(item, self);
+                result = expand_annotatable(Annotatable::Item(item), self).make_items();
                 self.cx.directory = directory;
             }
         } else {
-            result = expand_item(item, self);
+            result = expand_annotatable(Annotatable::Item(item), self).make_items();
         }
         result
     }

From 2a83574c6af52419af9f723bcc9a9427942a6be8 Mon Sep 17 00:00:00 2001
From: Jeffrey Seyfried 
Date: Sun, 28 Aug 2016 03:16:03 +0000
Subject: [PATCH 191/443] Refactor out `expand_item` (with better semantics
 than before).

---
 src/libsyntax/ext/expand.rs | 75 +++++++++++++++++++------------------
 1 file changed, 39 insertions(+), 36 deletions(-)

diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 687c5e2fdfb8..1b9af0aa4677 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -409,42 +409,7 @@ fn expand_pat(p: P, fld: &mut MacroExpander) -> P {
 
 fn expand_multi_modified(a: Annotatable, fld: &mut MacroExpander) -> Expansion {
     match a {
-        Annotatable::Item(it) => match it.node {
-            ast::ItemKind::Mac(..) => {
-                if match it.node {
-                    ItemKind::Mac(ref mac) => mac.node.path.segments.is_empty(),
-                    _ => unreachable!(),
-                } {
-                    return Expansion::Items(SmallVector::one(it));
-                }
-                it.and_then(|it| match it.node {
-                    ItemKind::Mac(mac) => {
-                        let invoc =
-                            fld.new_invoc(ExpansionKind::Items, InvocationKind::Bang {
-                                mac: mac, attrs: it.attrs, ident: Some(it.ident), span: it.span,
-                            });
-                        expand_invoc(invoc, fld)
-                    }
-                    _ => unreachable!(),
-                })
-            }
-            ast::ItemKind::Mod(_) | ast::ItemKind::ForeignMod(_) => {
-                let valid_ident =
-                    it.ident.name != keywords::Invalid.name();
-
-                if valid_ident {
-                    fld.cx.mod_push(it.ident);
-                }
-                let macro_use = contains_macro_use(fld, &it.attrs);
-                let result = fld.with_exts_frame(macro_use, |fld| noop_fold_item(it, fld));
-                if valid_ident {
-                    fld.cx.mod_pop();
-                }
-                Expansion::Items(result)
-            },
-            _ => Expansion::Items(noop_fold_item(it, fld)),
-        },
-
+        Annotatable::Item(it) => Expansion::Items(expand_item(it, fld)),
         Annotatable::TraitItem(it) => Expansion::TraitItems(expand_trait_item(it.unwrap(), fld)),
         Annotatable::ImplItem(ii) => Expansion::ImplItems(expand_impl_item(ii.unwrap(), fld)),
     }
@@ -480,6 +445,44 @@ fn expand_annotatable(mut item: Annotatable, fld: &mut MacroExpander) -> Expansi
     }
 }
 
+fn expand_item(item: P, fld: &mut MacroExpander) -> SmallVector> {
+    match item.node {
+        ast::ItemKind::Mac(..) => {
+            if match item.node {
+                ItemKind::Mac(ref mac) => mac.node.path.segments.is_empty(),
+                _ => unreachable!(),
+            } {
+                return SmallVector::one(item);
+            }
+            item.and_then(|item| match item.node {
+                ItemKind::Mac(mac) => {
+                    let invoc =
+                        fld.new_invoc(ExpansionKind::Items, InvocationKind::Bang {
+                            mac: mac, attrs: item.attrs, ident: Some(item.ident), span: item.span,
+                        });
+                    expand_invoc(invoc, fld).make_items()
+                }
+                _ => unreachable!(),
+            })
+        }
+        ast::ItemKind::Mod(_) | ast::ItemKind::ForeignMod(_) => {
+            let valid_ident =
+                item.ident.name != keywords::Invalid.name();
+
+            if valid_ident {
+                fld.cx.mod_push(item.ident);
+            }
+            let macro_use = contains_macro_use(fld, &item.attrs);
+            let result = fld.with_exts_frame(macro_use, |fld| noop_fold_item(item, fld));
+            if valid_ident {
+                fld.cx.mod_pop();
+            }
+            result
+        },
+        _ => noop_fold_item(item, fld),
+    }
+}
+
 fn expand_impl_item(ii: ast::ImplItem, fld: &mut MacroExpander)
                  -> SmallVector {
     match ii.node {

From 503a10b34a89995ebea6b7a28aa2465038c99627 Mon Sep 17 00:00:00 2001
From: Jeffrey Seyfried 
Date: Sun, 28 Aug 2016 03:49:56 +0000
Subject: [PATCH 192/443] Clean up module processing.

---
 src/libsyntax/ext/expand.rs | 56 ++++++++++++++-----------------------
 1 file changed, 21 insertions(+), 35 deletions(-)

diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 1b9af0aa4677..3e169131ec8d 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -465,18 +465,28 @@ fn expand_item(item: P, fld: &mut MacroExpander) -> SmallVector unreachable!(),
             })
         }
-        ast::ItemKind::Mod(_) | ast::ItemKind::ForeignMod(_) => {
-            let valid_ident =
-                item.ident.name != keywords::Invalid.name();
-
-            if valid_ident {
-                fld.cx.mod_push(item.ident);
-            }
+        ast::ItemKind::Mod(ast::Mod { inner, .. }) => {
+            fld.cx.mod_push(item.ident);
             let macro_use = contains_macro_use(fld, &item.attrs);
-            let result = fld.with_exts_frame(macro_use, |fld| noop_fold_item(item, fld));
-            if valid_ident {
-                fld.cx.mod_pop();
+
+            let directory = fld.cx.directory.clone();
+            if item.span.contains(inner) {
+                fld.cx.directory.push(&*{
+                    ::attr::first_attr_value_str_by_name(&item.attrs, "path")
+                        .unwrap_or(item.ident.name.as_str())
+                });
+            } else {
+                fld.cx.directory = match inner {
+                    syntax_pos::DUMMY_SP => PathBuf::new(),
+                    _ => PathBuf::from(fld.cx.parse_sess.codemap().span_to_filename(inner)),
+                };
+                fld.cx.directory.pop();
             }
+
+            let result = fld.with_exts_frame(macro_use, |fld| noop_fold_item(item, fld));
+            fld.cx.directory = directory;
+
+            fld.cx.mod_pop();
             result
         },
         _ => noop_fold_item(item, fld),
@@ -639,31 +649,7 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
     }
 
     fn fold_item(&mut self, item: P) -> SmallVector> {
-        use std::mem::replace;
-        let result;
-        if let ast::ItemKind::Mod(ast::Mod { inner, .. }) = item.node {
-            if item.span.contains(inner) {
-                let directory = self.cx.directory.clone();
-                self.cx.directory.push(&*{
-                    ::attr::first_attr_value_str_by_name(&item.attrs, "path")
-                        .unwrap_or(item.ident.name.as_str())
-                });
-                result = expand_annotatable(Annotatable::Item(item), self).make_items();
-                self.cx.directory = directory;
-            } else {
-                let mut directory = match inner {
-                    syntax_pos::DUMMY_SP => PathBuf::new(),
-                    _ => PathBuf::from(self.cx.parse_sess.codemap().span_to_filename(inner)),
-                };
-                directory.pop();
-                let directory = replace(&mut self.cx.directory, directory);
-                result = expand_annotatable(Annotatable::Item(item), self).make_items();
-                self.cx.directory = directory;
-            }
-        } else {
-            result = expand_annotatable(Annotatable::Item(item), self).make_items();
-        }
-        result
+        expand_annotatable(Annotatable::Item(item), self).make_items()
     }
 
     fn fold_stmt(&mut self, stmt: ast::Stmt) -> SmallVector {

From 4ed2c0ea7cfc1cc952cc66e78e1b7117367de2c4 Mon Sep 17 00:00:00 2001
From: Jeffrey Seyfried 
Date: Tue, 30 Aug 2016 23:03:52 +0000
Subject: [PATCH 193/443] Refactor `expand_*` into `expander.fold_*`.

---
 src/libsyntax/ext/expand.rs | 408 +++++++++++++++++-------------------
 1 file changed, 194 insertions(+), 214 deletions(-)

diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 3e169131ec8d..d3f8618aace9 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 use ast::{Block, Crate, Ident, Mac_, PatKind};
-use ast::{MacStmtStyle, Stmt, StmtKind, ItemKind};
+use ast::{MacStmtStyle, StmtKind, ItemKind};
 use ast;
 use ext::hygiene::Mark;
 use attr::{self, HasAttrs};
@@ -143,15 +143,6 @@ enum InvocationKind {
     },
 }
 
-pub fn expand_expr(expr: ast::Expr, fld: &mut MacroExpander) -> P {
-    if let ast::ExprKind::Mac(mac) = expr.node {
-        let invoc = fld.new_bang_invoc(mac, expr.attrs.into(), expr.span, ExpansionKind::Expr);
-        expand_invoc(invoc, fld).make_expr()
-    } else {
-        P(noop_fold_expr(expr, fld))
-    }
-}
-
 fn expand_invoc(invoc: Invocation, fld: &mut MacroExpander) -> Expansion {
     match invoc.kind {
         InvocationKind::Bang { .. } => expand_bang_invoc(invoc, fld),
@@ -345,191 +336,6 @@ fn expand_bang_invoc(invoc: Invocation, fld: &mut MacroExpander) -> Expansion {
     fully_expanded
 }
 
-// does this attribute list contain "macro_use" ?
-fn contains_macro_use(fld: &mut MacroExpander, attrs: &[ast::Attribute]) -> bool {
-    for attr in attrs {
-        let mut is_use = attr.check_name("macro_use");
-        if attr.check_name("macro_escape") {
-            let mut err =
-                fld.cx.struct_span_warn(attr.span,
-                                        "macro_escape is a deprecated synonym for macro_use");
-            is_use = true;
-            if let ast::AttrStyle::Inner = attr.node.style {
-                err.help("consider an outer attribute, \
-                          #[macro_use] mod ...").emit();
-            } else {
-                err.emit();
-            }
-        };
-
-        if is_use {
-            if !attr.is_word() {
-              fld.cx.span_err(attr.span, "arguments to macro_use are not allowed here");
-            }
-            return true;
-        }
-    }
-    false
-}
-
-/// Expand a stmt
-fn expand_stmt(stmt: Stmt, fld: &mut MacroExpander) -> SmallVector {
-    let (mac, style, attrs) = match stmt.node {
-        StmtKind::Mac(mac) => mac.unwrap(),
-        _ => return noop_fold_stmt(stmt, fld)
-    };
-
-    let invoc = fld.new_bang_invoc(mac, attrs.into(), stmt.span, ExpansionKind::Stmts);
-    let mut fully_expanded = expand_invoc(invoc, fld).make_stmts();
-
-    // If this is a macro invocation with a semicolon, then apply that
-    // semicolon to the final statement produced by expansion.
-    if style == MacStmtStyle::Semicolon {
-        if let Some(stmt) = fully_expanded.pop() {
-            fully_expanded.push(stmt.add_trailing_semicolon());
-        }
-    }
-
-    fully_expanded
-}
-
-fn expand_pat(p: P, fld: &mut MacroExpander) -> P {
-    match p.node {
-        PatKind::Mac(_) => {}
-        _ => return noop_fold_pat(p, fld)
-    }
-    p.and_then(|p| match p.node {
-        PatKind::Mac(mac) => {
-            let invoc = fld.new_bang_invoc(mac, Vec::new(), p.span, ExpansionKind::Pat);
-            expand_invoc(invoc, fld).make_pat()
-        }
-        _ => unreachable!(),
-    })
-}
-
-fn expand_multi_modified(a: Annotatable, fld: &mut MacroExpander) -> Expansion {
-    match a {
-        Annotatable::Item(it) => Expansion::Items(expand_item(it, fld)),
-        Annotatable::TraitItem(it) => Expansion::TraitItems(expand_trait_item(it.unwrap(), fld)),
-        Annotatable::ImplItem(ii) => Expansion::ImplItems(expand_impl_item(ii.unwrap(), fld)),
-    }
-}
-
-fn expand_annotatable(mut item: Annotatable, fld: &mut MacroExpander) -> Expansion {
-    let mut attr = None;
-    item = item.map_attrs(|mut attrs| {
-        for i in 0..attrs.len() {
-            if let Some(extension) = fld.cx.syntax_env.find(intern(&attrs[i].name())) {
-                match *extension {
-                    MultiModifier(..) | MultiDecorator(..) => {
-                        attr = Some(attrs.remove(i));
-                        break;
-                    }
-                    _ => {}
-                }
-            }
-        }
-        attrs
-    });
-
-    if let Some(attr) = attr {
-        let kind = match item {
-            Annotatable::Item(_) => ExpansionKind::Items,
-            Annotatable::ImplItem(_) => ExpansionKind::ImplItems,
-            Annotatable::TraitItem(_) => ExpansionKind::TraitItems,
-        };
-        let invoc = fld.new_invoc(kind, InvocationKind::Attr { attr: attr, item: item });
-        expand_invoc(invoc, fld)
-    } else {
-        expand_multi_modified(item, fld)
-    }
-}
-
-fn expand_item(item: P, fld: &mut MacroExpander) -> SmallVector> {
-    match item.node {
-        ast::ItemKind::Mac(..) => {
-            if match item.node {
-                ItemKind::Mac(ref mac) => mac.node.path.segments.is_empty(),
-                _ => unreachable!(),
-            } {
-                return SmallVector::one(item);
-            }
-            item.and_then(|item| match item.node {
-                ItemKind::Mac(mac) => {
-                    let invoc =
-                        fld.new_invoc(ExpansionKind::Items, InvocationKind::Bang {
-                            mac: mac, attrs: item.attrs, ident: Some(item.ident), span: item.span,
-                        });
-                    expand_invoc(invoc, fld).make_items()
-                }
-                _ => unreachable!(),
-            })
-        }
-        ast::ItemKind::Mod(ast::Mod { inner, .. }) => {
-            fld.cx.mod_push(item.ident);
-            let macro_use = contains_macro_use(fld, &item.attrs);
-
-            let directory = fld.cx.directory.clone();
-            if item.span.contains(inner) {
-                fld.cx.directory.push(&*{
-                    ::attr::first_attr_value_str_by_name(&item.attrs, "path")
-                        .unwrap_or(item.ident.name.as_str())
-                });
-            } else {
-                fld.cx.directory = match inner {
-                    syntax_pos::DUMMY_SP => PathBuf::new(),
-                    _ => PathBuf::from(fld.cx.parse_sess.codemap().span_to_filename(inner)),
-                };
-                fld.cx.directory.pop();
-            }
-
-            let result = fld.with_exts_frame(macro_use, |fld| noop_fold_item(item, fld));
-            fld.cx.directory = directory;
-
-            fld.cx.mod_pop();
-            result
-        },
-        _ => noop_fold_item(item, fld),
-    }
-}
-
-fn expand_impl_item(ii: ast::ImplItem, fld: &mut MacroExpander)
-                 -> SmallVector {
-    match ii.node {
-        ast::ImplItemKind::Macro(mac) => {
-            let invoc = fld.new_bang_invoc(mac, ii.attrs, ii.span, ExpansionKind::ImplItems);
-            expand_invoc(invoc, fld).make_impl_items()
-        }
-        _ => fold::noop_fold_impl_item(ii, fld)
-    }
-}
-
-fn expand_trait_item(ti: ast::TraitItem, fld: &mut MacroExpander)
-                     -> SmallVector {
-    match ti.node {
-        ast::TraitItemKind::Macro(mac) => {
-            let invoc = fld.new_bang_invoc(mac, ti.attrs, ti.span, ExpansionKind::TraitItems);
-            expand_invoc(invoc, fld).make_trait_items()
-        }
-        _ => fold::noop_fold_trait_item(ti, fld)
-    }
-}
-
-pub fn expand_type(t: P, fld: &mut MacroExpander) -> P {
-    let t = match t.node {
-        ast::TyKind::Mac(_) => t.unwrap(),
-        _ => return fold::noop_fold_ty(t, fld),
-    };
-
-    match t.node {
-        ast::TyKind::Mac(mac) => {
-            let invoc = fld.new_bang_invoc(mac, Vec::new(), t.span, ExpansionKind::Ty);
-            expand_invoc(invoc, fld).make_ty()
-        }
-        _ => unreachable!(),
-    }
-}
-
 /// A tree-folder that performs macro expansion
 pub struct MacroExpander<'a, 'b:'a> {
     pub cx: &'a mut ExtCtxt<'b>,
@@ -612,6 +418,56 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         })
     }
 
+    fn new_attr_invoc(&self, attr: ast::Attribute, item: Annotatable, kind: ExpansionKind)
+                      -> Invocation {
+        self.new_invoc(kind, InvocationKind::Attr { attr: attr, item: item })
+    }
+
+    // If `item` is an attr invocation, remove and return the macro attribute.
+    fn classify_item(&self, mut item: T) -> (T, Option) {
+        let mut attr = None;
+        item = item.map_attrs(|mut attrs| {
+            for i in 0..attrs.len() {
+                if let Some(extension) = self.cx.syntax_env.find(intern(&attrs[i].name())) {
+                    match *extension {
+                        MultiModifier(..) | MultiDecorator(..) => {
+                            attr = Some(attrs.remove(i));
+                            break;
+                        }
+                        _ => {}
+                    }
+                }
+            }
+            attrs
+        });
+        (item, attr)
+    }
+
+    // does this attribute list contain "macro_use" ?
+    fn contains_macro_use(&mut self, attrs: &[ast::Attribute]) -> bool {
+        for attr in attrs {
+            let mut is_use = attr.check_name("macro_use");
+            if attr.check_name("macro_escape") {
+                let msg = "macro_escape is a deprecated synonym for macro_use";
+                let mut err = self.cx.struct_span_warn(attr.span, msg);
+                is_use = true;
+                if let ast::AttrStyle::Inner = attr.node.style {
+                    err.help("consider an outer attribute, #[macro_use] mod ...").emit();
+                } else {
+                    err.emit();
+                }
+            };
+
+            if is_use {
+                if !attr.is_word() {
+                    self.cx.span_err(attr.span, "arguments to macro_use are not allowed here");
+                }
+                return true;
+            }
+        }
+        false
+    }
+
     fn with_exts_frame T>(&mut self, macros_escape: bool, f: F) -> T {
         self.cx.syntax_env.push_frame();
         self.cx.syntax_env.info().macros_escape = macros_escape;
@@ -630,30 +486,59 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
     }
 
     fn fold_expr(&mut self, expr: P) -> P {
-        expr.and_then(|expr| expand_expr(expr, self))
+        let expr = expr.unwrap();
+        if let ast::ExprKind::Mac(mac) = expr.node {
+            let invoc = self.new_bang_invoc(mac, expr.attrs.into(), expr.span, ExpansionKind::Expr);
+            expand_invoc(invoc, self).make_expr()
+        } else {
+            P(noop_fold_expr(expr, self))
+        }
     }
 
     fn fold_opt_expr(&mut self, expr: P) -> Option> {
-        expr.and_then(|expr| match expr.node {
-            ast::ExprKind::Mac(mac) => {
-                let invoc =
-                    self.new_bang_invoc(mac, expr.attrs.into(), expr.span, ExpansionKind::OptExpr);
-                expand_invoc(invoc, self).make_opt_expr()
-            }
-            _ => Some(expand_expr(expr, self)),
-        })
+        let expr = expr.unwrap();
+        if let ast::ExprKind::Mac(mac) = expr.node {
+            let invoc =
+                self.new_bang_invoc(mac, expr.attrs.into(), expr.span, ExpansionKind::OptExpr);
+            expand_invoc(invoc, self).make_opt_expr()
+        } else {
+            Some(P(noop_fold_expr(expr, self)))
+        }
     }
 
     fn fold_pat(&mut self, pat: P) -> P {
-        expand_pat(pat, self)
-    }
+        match pat.node {
+            PatKind::Mac(_) => {}
+            _ => return noop_fold_pat(pat, self)
+        }
 
-    fn fold_item(&mut self, item: P) -> SmallVector> {
-        expand_annotatable(Annotatable::Item(item), self).make_items()
+        pat.and_then(|pat| match pat.node {
+            PatKind::Mac(mac) => {
+                let invoc = self.new_bang_invoc(mac, Vec::new(), pat.span, ExpansionKind::Pat);
+                expand_invoc(invoc, self).make_pat()
+            }
+            _ => unreachable!(),
+        })
     }
 
     fn fold_stmt(&mut self, stmt: ast::Stmt) -> SmallVector {
-        expand_stmt(stmt, self)
+        let (mac, style, attrs) = match stmt.node {
+            StmtKind::Mac(mac) => mac.unwrap(),
+            _ => return noop_fold_stmt(stmt, self)
+        };
+
+        let invoc = self.new_bang_invoc(mac, attrs.into(), stmt.span, ExpansionKind::Stmts);
+        let mut fully_expanded = expand_invoc(invoc, self).make_stmts();
+
+        // If this is a macro invocation with a semicolon, then apply that
+        // semicolon to the final statement produced by expansion.
+        if style == MacStmtStyle::Semicolon {
+            if let Some(stmt) = fully_expanded.pop() {
+                fully_expanded.push(stmt.add_trailing_semicolon());
+            }
+        }
+
+        fully_expanded
     }
 
     fn fold_block(&mut self, block: P) -> P {
@@ -663,16 +548,111 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
         result
     }
 
-    fn fold_trait_item(&mut self, i: ast::TraitItem) -> SmallVector {
-        expand_annotatable(Annotatable::TraitItem(P(i)), self).make_trait_items()
+    fn fold_item(&mut self, item: P) -> SmallVector> {
+        let (item, attr) = self.classify_item(item);
+        if let Some(attr) = attr {
+            let invoc = self.new_attr_invoc(attr, Annotatable::Item(item), ExpansionKind::Items);
+            return expand_invoc(invoc, self).make_items();
+        }
+
+        match item.node {
+            ast::ItemKind::Mac(..) => {
+                if match item.node {
+                    ItemKind::Mac(ref mac) => mac.node.path.segments.is_empty(),
+                    _ => unreachable!(),
+                } {
+                    return SmallVector::one(item);
+                }
+
+                item.and_then(|item| match item.node {
+                    ItemKind::Mac(mac) => {
+                        let invoc = self.new_invoc(ExpansionKind::Items, InvocationKind::Bang {
+                            mac: mac,
+                            attrs: item.attrs,
+                            ident: Some(item.ident),
+                            span: item.span,
+                        });
+                        expand_invoc(invoc, self).make_items()
+                    }
+                    _ => unreachable!(),
+                })
+            }
+            ast::ItemKind::Mod(ast::Mod { inner, .. }) => {
+                self.cx.mod_push(item.ident);
+                let macro_use = self.contains_macro_use(&item.attrs);
+
+                let directory = self.cx.directory.clone();
+                if item.span.contains(inner) {
+                    self.cx.directory.push(&*{
+                        ::attr::first_attr_value_str_by_name(&item.attrs, "path")
+                            .unwrap_or(item.ident.name.as_str())
+                    });
+                } else {
+                    self.cx.directory = match inner {
+                        syntax_pos::DUMMY_SP => PathBuf::new(),
+                        _ => PathBuf::from(self.cx.parse_sess.codemap().span_to_filename(inner)),
+                    };
+                    self.cx.directory.pop();
+                }
+                let result = self.with_exts_frame(macro_use, |this| noop_fold_item(item, this));
+                self.cx.directory = directory;
+
+                self.cx.mod_pop();
+                result
+            },
+            _ => noop_fold_item(item, self),
+        }
     }
 
-    fn fold_impl_item(&mut self, i: ast::ImplItem) -> SmallVector {
-        expand_annotatable(Annotatable::ImplItem(P(i)), self).make_impl_items()
+    fn fold_trait_item(&mut self, item: ast::TraitItem) -> SmallVector {
+        let (item, attr) = self.classify_item(item);
+        if let Some(attr) = attr {
+            let item = Annotatable::TraitItem(P(item));
+            let invoc = self.new_attr_invoc(attr, item, ExpansionKind::TraitItems);
+            return expand_invoc(invoc, self).make_trait_items();
+        }
+
+        match item.node {
+            ast::TraitItemKind::Macro(mac) => {
+                let ast::TraitItem { attrs, span, .. } = item;
+                let invoc = self.new_bang_invoc(mac, attrs, span, ExpansionKind::TraitItems);
+                expand_invoc(invoc, self).make_trait_items()
+            }
+            _ => fold::noop_fold_trait_item(item, self),
+        }
+    }
+
+    fn fold_impl_item(&mut self, item: ast::ImplItem) -> SmallVector {
+        let (item, attr) = self.classify_item(item);
+        if let Some(attr) = attr {
+            let item = Annotatable::ImplItem(P(item));
+            let invoc = self.new_attr_invoc(attr, item, ExpansionKind::ImplItems);
+            return expand_invoc(invoc, self).make_impl_items();
+        }
+
+        match item.node {
+            ast::ImplItemKind::Macro(mac) => {
+                let ast::ImplItem { attrs, span, .. } = item;
+                let invoc = self.new_bang_invoc(mac, attrs, span, ExpansionKind::ImplItems);
+                expand_invoc(invoc, self).make_impl_items()
+            }
+            _ => fold::noop_fold_impl_item(item, self)
+        }
     }
 
     fn fold_ty(&mut self, ty: P) -> P {
-        expand_type(ty, self)
+        let ty = match ty.node {
+            ast::TyKind::Mac(_) => ty.unwrap(),
+            _ => return fold::noop_fold_ty(ty, self),
+        };
+
+        match ty.node {
+            ast::TyKind::Mac(mac) => {
+                let invoc = self.new_bang_invoc(mac, Vec::new(), ty.span, ExpansionKind::Ty);
+                expand_invoc(invoc, self).make_ty()
+            }
+            _ => unreachable!(),
+        }
     }
 }
 

From 79fa9eb643cfbb807813afed6f825f6654ee7662 Mon Sep 17 00:00:00 2001
From: Jeffrey Seyfried 
Date: Thu, 1 Sep 2016 06:44:54 +0000
Subject: [PATCH 194/443] Refactor `SyntaxEnv`.

---
 src/libsyntax/ext/base.rs           | 171 +++++++++++++++-------------
 src/libsyntax/ext/expand.rs         |  64 ++++-------
 src/libsyntax/ext/source_util.rs    |   8 +-
 src/libsyntax/ext/tt/macro_rules.rs |   4 +-
 4 files changed, 120 insertions(+), 127 deletions(-)

diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index 769a5af0262c..fe2806891b85 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -24,6 +24,7 @@ use parse::parser;
 use parse::token;
 use parse::token::{InternedString, intern, str_to_ident};
 use ptr::P;
+use std_inject;
 use util::small_vector::SmallVector;
 use util::lev_distance::find_best_match_for_name;
 use fold::Folder;
@@ -463,19 +464,6 @@ pub enum SyntaxExtension {
 
 pub type NamedSyntaxExtension = (Name, SyntaxExtension);
 
-pub struct BlockInfo {
-    /// Should macros escape from this scope?
-    pub macros_escape: bool,
-}
-
-impl BlockInfo {
-    pub fn new() -> BlockInfo {
-        BlockInfo {
-            macros_escape: false,
-        }
-    }
-}
-
 /// The base map of methods for expanding syntax extension
 /// AST nodes into full ASTs
 fn initial_syntax_expander_table<'feat>(ecfg: &expand::ExpansionConfig<'feat>)
@@ -586,15 +574,11 @@ pub struct ExtCtxt<'a> {
     pub crate_root: Option<&'static str>,
     pub loader: &'a mut MacroLoader,
 
-    pub mod_path: Vec ,
     pub exported_macros: Vec,
 
     pub syntax_env: SyntaxEnv,
     pub derive_modes: HashMap>,
     pub recursion_count: usize,
-
-    pub directory: PathBuf,
-    pub in_block: bool,
 }
 
 impl<'a> ExtCtxt<'a> {
@@ -602,22 +586,17 @@ impl<'a> ExtCtxt<'a> {
                ecfg: expand::ExpansionConfig<'a>,
                loader: &'a mut MacroLoader)
                -> ExtCtxt<'a> {
-        let env = initial_syntax_expander_table(&ecfg);
         ExtCtxt {
+            syntax_env: initial_syntax_expander_table(&ecfg),
             parse_sess: parse_sess,
             cfg: cfg,
             backtrace: NO_EXPANSION,
-            mod_path: Vec::new(),
             ecfg: ecfg,
             crate_root: None,
             exported_macros: Vec::new(),
             loader: loader,
-            syntax_env: env,
             derive_modes: HashMap::new(),
             recursion_count: 0,
-
-            directory: PathBuf::new(),
-            in_block: false,
         }
     }
 
@@ -666,14 +645,6 @@ impl<'a> ExtCtxt<'a> {
         last_macro.expect("missing expansion backtrace")
     }
 
-    pub fn mod_push(&mut self, i: ast::Ident) { self.mod_path.push(i); }
-    pub fn mod_pop(&mut self) { self.mod_path.pop().unwrap(); }
-    pub fn mod_path(&self) -> Vec {
-        let mut v = Vec::new();
-        v.push(token::str_to_ident(&self.ecfg.crate_name));
-        v.extend(self.mod_path.iter().cloned());
-        return v;
-    }
     pub fn bt_push(&mut self, ei: ExpnInfo) {
         self.recursion_count += 1;
         if self.recursion_count > self.ecfg.recursion_limit {
@@ -818,6 +789,30 @@ impl<'a> ExtCtxt<'a> {
             }
         }
     }
+
+    pub fn initialize(&mut self, user_exts: Vec, krate: &ast::Crate) {
+        if std_inject::no_core(&krate) {
+            self.crate_root = None;
+        } else if std_inject::no_std(&krate) {
+            self.crate_root = Some("core");
+        } else {
+            self.crate_root = Some("std");
+        }
+
+        // User extensions must be added before expander.load_macros is called,
+        // so that macros from external crates shadow user defined extensions.
+        for (name, extension) in user_exts {
+            self.syntax_env.insert(name, extension);
+        }
+
+        self.syntax_env.current_module = Module(0);
+        let mut paths = ModulePaths {
+            mod_path: vec![token::str_to_ident(&self.ecfg.crate_name)],
+            directory: PathBuf::from(self.parse_sess.codemap().span_to_filename(krate.span)),
+        };
+        paths.directory.pop();
+        self.syntax_env.module_data[0].paths = Rc::new(paths);
+    }
 }
 
 /// Extract a string literal from the macro expanded version of `expr`,
@@ -904,79 +899,103 @@ pub fn get_exprs_from_tts(cx: &mut ExtCtxt,
 ///
 /// This environment maps Names to SyntaxExtensions.
 pub struct SyntaxEnv {
-    chain: Vec,
+    module_data: Vec,
+    current_module: Module,
+
     /// All bang-style macro/extension names
     /// encountered so far; to be used for diagnostics in resolve
     pub names: HashSet,
 }
 
-// impl question: how to implement it? Initially, the
-// env will contain only macros, so it might be painful
-// to add an empty frame for every context. Let's just
-// get it working, first....
+#[derive(Copy, Clone, PartialEq, Eq)]
+pub struct Module(u32);
 
-// NB! the mutability of the underlying maps means that
-// if expansion is out-of-order, a deeper scope may be
-// able to refer to a macro that was added to an enclosing
-// scope lexically later than the deeper scope.
+struct ModuleData {
+    parent: Module,
+    paths: Rc,
+    macros: HashMap>,
+    macros_escape: bool,
+    in_block: bool,
+}
 
-struct MapChainFrame {
-    info: BlockInfo,
-    map: HashMap>,
+#[derive(Clone)]
+pub struct ModulePaths {
+    pub mod_path: Vec,
+    pub directory: PathBuf,
 }
 
 impl SyntaxEnv {
     fn new() -> SyntaxEnv {
-        let mut map = SyntaxEnv { chain: Vec::new() , names: HashSet::new()};
-        map.push_frame();
-        map
+        let mut env = SyntaxEnv {
+            current_module: Module(0),
+            module_data: Vec::new(),
+            names: HashSet::new(),
+        };
+        let paths = Rc::new(ModulePaths { mod_path: Vec::new(), directory: PathBuf::new() });
+        env.add_module(false, false, paths);
+        env
     }
 
-    pub fn push_frame(&mut self) {
-        self.chain.push(MapChainFrame {
-            info: BlockInfo::new(),
-            map: HashMap::new(),
-        });
+    fn data(&self, module: Module) -> &ModuleData {
+        &self.module_data[module.0 as usize]
     }
 
-    pub fn pop_frame(&mut self) {
-        assert!(self.chain.len() > 1, "too many pops on MapChain!");
-        self.chain.pop();
+    pub fn set_current_module(&mut self, module: Module) -> Module {
+        ::std::mem::replace(&mut self.current_module, module)
     }
 
-    fn find_escape_frame(&mut self) -> &mut MapChainFrame {
-        for (i, frame) in self.chain.iter_mut().enumerate().rev() {
-            if !frame.info.macros_escape || i == 0 {
-                return frame
+    pub fn paths(&self) -> Rc {
+        self.data(self.current_module).paths.clone()
+    }
+
+    pub fn in_block(&self) -> bool {
+        self.data(self.current_module).in_block
+    }
+
+    pub fn add_module(&mut self, macros_escape: bool, in_block: bool, paths: Rc)
+                      -> Module {
+        let data = ModuleData {
+            parent: self.current_module,
+            paths: paths,
+            macros: HashMap::new(),
+            macros_escape: macros_escape,
+            in_block: in_block,
+        };
+
+        self.module_data.push(data);
+        Module(self.module_data.len() as u32 - 1)
+    }
+
+    pub fn find(&self, name: Name) -> Option> {
+        let mut module = self.current_module;
+        let mut module_data;
+        loop {
+            module_data = self.data(module);
+            if let Some(ext) = module_data.macros.get(&name) {
+                return Some(ext.clone());
             }
-        }
-        unreachable!()
-    }
-
-    pub fn find(&self, k: Name) -> Option> {
-        for frame in self.chain.iter().rev() {
-            if let Some(v) = frame.map.get(&k) {
-                return Some(v.clone());
+            if module == module_data.parent {
+                return None;
             }
+            module = module_data.parent;
         }
-        None
     }
 
-    pub fn insert(&mut self, k: Name, v: SyntaxExtension) {
-        if let NormalTT(..) = v {
-            self.names.insert(k);
+    pub fn insert(&mut self, name: Name, ext: SyntaxExtension) {
+        if let NormalTT(..) = ext {
+            self.names.insert(name);
         }
-        self.find_escape_frame().map.insert(k, Rc::new(v));
-    }
 
-    pub fn info(&mut self) -> &mut BlockInfo {
-        let last_chain_index = self.chain.len() - 1;
-        &mut self.chain[last_chain_index].info
+        let mut module = self.current_module;
+        while self.data(module).macros_escape {
+            module = self.data(module).parent;
+        }
+        self.module_data[module.0 as usize].macros.insert(name, Rc::new(ext));
     }
 
     pub fn is_crate_root(&mut self) -> bool {
         // The first frame is pushed in `SyntaxEnv::new()` and the second frame is
         // pushed when folding the crate root pseudo-module (c.f. noop_fold_crate).
-        self.chain.len() <= 2
+        self.current_module.0 <= 1
     }
 }
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index d3f8618aace9..a713196032c8 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -26,9 +26,9 @@ use tokenstream::TokenTree;
 use util::small_vector::SmallVector;
 use visit;
 use visit::Visitor;
-use std_inject;
 
 use std::path::PathBuf;
+use std::rc::Rc;
 
 macro_rules! expansions {
     ($($kind:ident: $ty:ty, $kind_name:expr, .$make:ident,
@@ -467,24 +467,9 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         }
         false
     }
-
-    fn with_exts_frame T>(&mut self, macros_escape: bool, f: F) -> T {
-        self.cx.syntax_env.push_frame();
-        self.cx.syntax_env.info().macros_escape = macros_escape;
-        let result = f(self);
-        self.cx.syntax_env.pop_frame();
-        result
-    }
 }
 
 impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
-    fn fold_crate(&mut self, c: Crate) -> Crate {
-        let mut directory = PathBuf::from(self.cx.parse_sess.codemap().span_to_filename(c.span));
-        directory.pop();
-        self.cx.directory = directory;
-        noop_fold_crate(c, self)
-    }
-
     fn fold_expr(&mut self, expr: P) -> P {
         let expr = expr.unwrap();
         if let ast::ExprKind::Mac(mac) = expr.node {
@@ -542,9 +527,12 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
     }
 
     fn fold_block(&mut self, block: P) -> P {
-        let was_in_block = ::std::mem::replace(&mut self.cx.in_block, true);
-        let result = self.with_exts_frame(false, |this| noop_fold_block(block, this));
-        self.cx.in_block = was_in_block;
+        let paths = self.cx.syntax_env.paths();
+        let module = self.cx.syntax_env.add_module(false, true, paths);
+        let orig_module = self.cx.syntax_env.set_current_module(module);
+
+        let result = noop_fold_block(block, self);
+        self.cx.syntax_env.set_current_module(orig_module);
         result
     }
 
@@ -578,26 +566,27 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
                 })
             }
             ast::ItemKind::Mod(ast::Mod { inner, .. }) => {
-                self.cx.mod_push(item.ident);
-                let macro_use = self.contains_macro_use(&item.attrs);
-
-                let directory = self.cx.directory.clone();
+                let mut paths = (*self.cx.syntax_env.paths()).clone();
+                paths.mod_path.push(item.ident);
                 if item.span.contains(inner) {
-                    self.cx.directory.push(&*{
+                    paths.directory.push(&*{
                         ::attr::first_attr_value_str_by_name(&item.attrs, "path")
                             .unwrap_or(item.ident.name.as_str())
                     });
                 } else {
-                    self.cx.directory = match inner {
+                    paths.directory = match inner {
                         syntax_pos::DUMMY_SP => PathBuf::new(),
                         _ => PathBuf::from(self.cx.parse_sess.codemap().span_to_filename(inner)),
                     };
-                    self.cx.directory.pop();
+                    paths.directory.pop();
                 }
-                let result = self.with_exts_frame(macro_use, |this| noop_fold_item(item, this));
-                self.cx.directory = directory;
 
-                self.cx.mod_pop();
+                let macro_use = self.contains_macro_use(&item.attrs);
+                let in_block = self.cx.syntax_env.in_block();
+                let module = self.cx.syntax_env.add_module(macro_use, in_block, Rc::new(paths));
+                let module = self.cx.syntax_env.set_current_module(module);
+                let result = noop_fold_item(item, self);
+                self.cx.syntax_env.set_current_module(module);
                 result
             },
             _ => noop_fold_item(item, self),
@@ -744,19 +733,7 @@ pub fn expand_crate(cx: &mut ExtCtxt,
 pub fn expand_crate_with_expander(expander: &mut MacroExpander,
                                   user_exts: Vec,
                                   mut c: Crate) -> Crate {
-    if std_inject::no_core(&c) {
-        expander.cx.crate_root = None;
-    } else if std_inject::no_std(&c) {
-        expander.cx.crate_root = Some("core");
-    } else {
-        expander.cx.crate_root = Some("std");
-    }
-
-    // User extensions must be added before expander.load_macros is called,
-    // so that macros from external crates shadow user defined extensions.
-    for (name, extension) in user_exts {
-        expander.cx.syntax_env.insert(name, extension);
-    }
+    expander.cx.initialize(user_exts, &c);
 
     let items = Expansion::Items(SmallVector::many(c.module.items));
     let configured = items.fold_with(&mut expander.strip_unconfigured());
@@ -765,12 +742,11 @@ pub fn expand_crate_with_expander(expander: &mut MacroExpander,
 
     let err_count = expander.cx.parse_sess.span_diagnostic.err_count();
     let mut ret = expander.fold_crate(c);
-    ret.exported_macros = expander.cx.exported_macros.clone();
-
     if expander.cx.parse_sess.span_diagnostic.err_count() > err_count {
         expander.cx.parse_sess.span_diagnostic.abort_if_errors();
     }
 
+    ret.exported_macros = expander.cx.exported_macros.clone();
     ret
 }
 
diff --git a/src/libsyntax/ext/source_util.rs b/src/libsyntax/ext/source_util.rs
index 97cb09991ec4..105b22611173 100644
--- a/src/libsyntax/ext/source_util.rs
+++ b/src/libsyntax/ext/source_util.rs
@@ -74,11 +74,9 @@ pub fn expand_stringify(cx: &mut ExtCtxt, sp: Span, tts: &[tokenstream::TokenTre
 pub fn expand_mod(cx: &mut ExtCtxt, sp: Span, tts: &[tokenstream::TokenTree])
                   -> Box {
     base::check_zero_tts(cx, sp, tts, "module_path!");
-    let string = cx.mod_path()
-                   .iter()
-                   .map(|x| x.to_string())
-                   .collect::>()
-                   .join("::");
+    let paths = cx.syntax_env.paths();
+    let string = paths.mod_path.iter().map(|x| x.to_string()).collect::>().join("::");
+
     base::MacEager::expr(cx.expr_str(
             sp,
             token::intern_and_get_ident(&string[..])))
diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs
index a4be84dfbf02..ed80ec9cbc49 100644
--- a/src/libsyntax/ext/tt/macro_rules.rs
+++ b/src/libsyntax/ext/tt/macro_rules.rs
@@ -211,8 +211,8 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt,
                                            imported_from,
                                            rhs);
                 let mut p = Parser::new(cx.parse_sess(), cx.cfg(), Box::new(trncbr));
-                p.directory = cx.directory.clone();
-                p.restrictions = match cx.in_block {
+                p.directory = cx.syntax_env.paths().directory.clone();
+                p.restrictions = match cx.syntax_env.in_block() {
                     true => Restrictions::NO_NONINLINE_MOD,
                     false => Restrictions::empty(),
                 };

From 7a3ae576fa729e0465719f97aa7bb80c9721b446 Mon Sep 17 00:00:00 2001
From: Jeffrey Seyfried 
Date: Thu, 1 Sep 2016 07:01:45 +0000
Subject: [PATCH 195/443] Refactor `expand_invoc(.., fld)` ->
 `self.expand_invoc(..)`.

---
 src/libsyntax/ext/expand.rs | 419 ++++++++++++++++++------------------
 1 file changed, 212 insertions(+), 207 deletions(-)

diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index a713196032c8..17b2b2d25b99 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -143,199 +143,6 @@ enum InvocationKind {
     },
 }
 
-fn expand_invoc(invoc: Invocation, fld: &mut MacroExpander) -> Expansion {
-    match invoc.kind {
-        InvocationKind::Bang { .. } => expand_bang_invoc(invoc, fld),
-        InvocationKind::Attr { .. } => expand_attr_invoc(invoc, fld),
-    }
-}
-
-fn expand_attr_invoc(invoc: Invocation, fld: &mut MacroExpander) -> Expansion {
-    let Invocation { expansion_kind: kind, .. } = invoc;
-    let (attr, item) = match invoc.kind {
-        InvocationKind::Attr { attr, item } => (attr, item),
-        _ => unreachable!(),
-    };
-
-    let extension = match fld.cx.syntax_env.find(intern(&attr.name())) {
-        Some(extension) => extension,
-        None => unreachable!(),
-    };
-
-    attr::mark_used(&attr);
-    fld.cx.bt_push(ExpnInfo {
-        call_site: attr.span,
-        callee: NameAndSpan {
-            format: MacroAttribute(intern(&attr.name())),
-            span: Some(attr.span),
-            allow_internal_unstable: false,
-        }
-    });
-
-    let modified = match *extension {
-        MultiModifier(ref mac) => {
-            kind.expect_from_annotatables(mac.expand(fld.cx, attr.span, &attr.node.value, item))
-        }
-        MultiDecorator(ref mac) => {
-            let mut items = Vec::new();
-            mac.expand(fld.cx, attr.span, &attr.node.value, &item, &mut |item| items.push(item));
-            items.push(item);
-            kind.expect_from_annotatables(items)
-        }
-        _ => unreachable!(),
-    };
-
-    fld.cx.bt_pop();
-
-    let configured = modified.fold_with(&mut fld.strip_unconfigured());
-    configured.fold_with(fld)
-}
-
-/// Expand a macro invocation. Returns the result of expansion.
-fn expand_bang_invoc(invoc: Invocation, fld: &mut MacroExpander) -> Expansion {
-    let Invocation { mark, expansion_kind: kind, .. } = invoc;
-    let (attrs, mac, ident, span) = match invoc.kind {
-        InvocationKind::Bang { attrs, mac, ident, span } => (attrs, mac, ident, span),
-        _ => unreachable!(),
-    };
-    let Mac_ { path, tts, .. } = mac.node;
-
-    // Detect use of feature-gated or invalid attributes on macro invoations
-    // since they will not be detected after macro expansion.
-    for attr in attrs.iter() {
-        feature_gate::check_attribute(&attr, &fld.cx.parse_sess.span_diagnostic,
-                                      &fld.cx.parse_sess.codemap(),
-                                      &fld.cx.ecfg.features.unwrap());
-    }
-
-    if path.segments.len() > 1 || path.global || !path.segments[0].parameters.is_empty() {
-        fld.cx.span_err(path.span, "expected macro name without module separators");
-        return kind.dummy(span);
-    }
-
-    let extname = path.segments[0].identifier.name;
-    let extension = if let Some(extension) = fld.cx.syntax_env.find(extname) {
-        extension
-    } else {
-        let mut err =
-            fld.cx.struct_span_err(path.span, &format!("macro undefined: '{}!'", &extname));
-        fld.cx.suggest_macro_name(&extname.as_str(), &mut err);
-        err.emit();
-        return kind.dummy(span);
-    };
-
-    let ident = ident.unwrap_or(keywords::Invalid.ident());
-    let marked_tts = mark_tts(&tts, mark);
-    let opt_expanded = match *extension {
-        NormalTT(ref expandfun, exp_span, allow_internal_unstable) => {
-            if ident.name != keywords::Invalid.name() {
-                let msg =
-                    format!("macro {}! expects no ident argument, given '{}'", extname, ident);
-                fld.cx.span_err(path.span, &msg);
-                return kind.dummy(span);
-            }
-
-            fld.cx.bt_push(ExpnInfo {
-                call_site: span,
-                callee: NameAndSpan {
-                    format: MacroBang(extname),
-                    span: exp_span,
-                    allow_internal_unstable: allow_internal_unstable,
-                },
-            });
-
-            kind.make_from(expandfun.expand(fld.cx, span, &marked_tts))
-        }
-
-        IdentTT(ref expander, tt_span, allow_internal_unstable) => {
-            if ident.name == keywords::Invalid.name() {
-                fld.cx.span_err(path.span,
-                                &format!("macro {}! expects an ident argument", extname));
-                return kind.dummy(span);
-            };
-
-            fld.cx.bt_push(ExpnInfo {
-                call_site: span,
-                callee: NameAndSpan {
-                    format: MacroBang(extname),
-                    span: tt_span,
-                    allow_internal_unstable: allow_internal_unstable,
-                }
-            });
-
-            kind.make_from(expander.expand(fld.cx, span, ident, marked_tts))
-        }
-
-        MacroRulesTT => {
-            if ident.name == keywords::Invalid.name() {
-                fld.cx.span_err(path.span,
-                                &format!("macro {}! expects an ident argument", extname));
-                return kind.dummy(span);
-            };
-
-            fld.cx.bt_push(ExpnInfo {
-                call_site: span,
-                callee: NameAndSpan {
-                    format: MacroBang(extname),
-                    span: None,
-                    // `macro_rules!` doesn't directly allow unstable
-                    // (this is orthogonal to whether the macro it creates allows it)
-                    allow_internal_unstable: false,
-                }
-            });
-
-            let def = ast::MacroDef {
-                ident: ident,
-                id: ast::DUMMY_NODE_ID,
-                span: span,
-                imported_from: None,
-                use_locally: true,
-                body: marked_tts,
-                export: attr::contains_name(&attrs, "macro_export"),
-                allow_internal_unstable: attr::contains_name(&attrs, "allow_internal_unstable"),
-                attrs: attrs,
-            };
-
-            fld.cx.insert_macro(def.clone());
-
-            // If keep_macs is true, expands to a MacEager::items instead.
-            if fld.keep_macs {
-                Some(reconstruct_macro_rules(&def, &path))
-            } else {
-                Some(macro_scope_placeholder())
-            }
-        }
-
-        MultiDecorator(..) | MultiModifier(..) => {
-            fld.cx.span_err(path.span,
-                            &format!("`{}` can only be used in attributes", extname));
-            return kind.dummy(span);
-        }
-    };
-
-    let expanded = if let Some(expanded) = opt_expanded {
-        expanded
-    } else {
-        let msg = format!("non-{kind} macro in {kind} position: {name}",
-                          name = path.segments[0].identifier.name, kind = kind.name());
-        fld.cx.span_err(path.span, &msg);
-        return kind.dummy(span);
-    };
-
-    let marked = expanded.fold_with(&mut Marker { mark: mark, expn_id: Some(fld.cx.backtrace()) });
-    let configured = marked.fold_with(&mut fld.strip_unconfigured());
-    fld.load_macros(&configured);
-
-    let fully_expanded = if fld.single_step {
-        configured
-    } else {
-        configured.fold_with(fld)
-    };
-
-    fld.cx.bt_pop();
-    fully_expanded
-}
-
 /// A tree-folder that performs macro expansion
 pub struct MacroExpander<'a, 'b:'a> {
     pub cx: &'a mut ExtCtxt<'b>,
@@ -467,6 +274,204 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         }
         false
     }
+
+    fn expand_invoc(&mut self, invoc: Invocation) -> Expansion {
+        match invoc.kind {
+            InvocationKind::Bang { .. } => self.expand_bang_invoc(invoc),
+            InvocationKind::Attr { .. } => self.expand_attr_invoc(invoc),
+        }
+    }
+
+    fn expand_attr_invoc(&mut self, invoc: Invocation) -> Expansion {
+        let Invocation { expansion_kind: kind, .. } = invoc;
+        let (attr, item) = match invoc.kind {
+            InvocationKind::Attr { attr, item } => (attr, item),
+            _ => unreachable!(),
+        };
+
+        let extension = match self.cx.syntax_env.find(intern(&attr.name())) {
+            Some(extension) => extension,
+            None => unreachable!(),
+        };
+
+        attr::mark_used(&attr);
+        self.cx.bt_push(ExpnInfo {
+            call_site: attr.span,
+            callee: NameAndSpan {
+                format: MacroAttribute(intern(&attr.name())),
+                span: Some(attr.span),
+                allow_internal_unstable: false,
+            }
+        });
+
+        let modified = match *extension {
+            MultiModifier(ref mac) => {
+                let item = mac.expand(self.cx, attr.span, &attr.node.value, item);
+                kind.expect_from_annotatables(item)
+            }
+            MultiDecorator(ref mac) => {
+                let mut items = Vec::new();
+                mac.expand(self.cx, attr.span, &attr.node.value, &item,
+                           &mut |item| items.push(item));
+                items.push(item);
+                kind.expect_from_annotatables(items)
+            }
+            _ => unreachable!(),
+        };
+
+        self.cx.bt_pop();
+
+        let configured = modified.fold_with(&mut self.strip_unconfigured());
+        configured.fold_with(self)
+    }
+
+    /// Expand a macro invocation. Returns the result of expansion.
+    fn expand_bang_invoc(&mut self, invoc: Invocation) -> Expansion {
+        let Invocation { mark, expansion_kind: kind, .. } = invoc;
+        let (attrs, mac, ident, span) = match invoc.kind {
+            InvocationKind::Bang { attrs, mac, ident, span } => (attrs, mac, ident, span),
+            _ => unreachable!(),
+        };
+        let Mac_ { path, tts, .. } = mac.node;
+
+        // Detect use of feature-gated or invalid attributes on macro invoations
+        // since they will not be detected after macro expansion.
+        for attr in attrs.iter() {
+            feature_gate::check_attribute(&attr, &self.cx.parse_sess.span_diagnostic,
+                                          &self.cx.parse_sess.codemap(),
+                                          &self.cx.ecfg.features.unwrap());
+        }
+
+        if path.segments.len() > 1 || path.global || !path.segments[0].parameters.is_empty() {
+            self.cx.span_err(path.span, "expected macro name without module separators");
+            return kind.dummy(span);
+        }
+
+        let extname = path.segments[0].identifier.name;
+        let extension = if let Some(extension) = self.cx.syntax_env.find(extname) {
+            extension
+        } else {
+            let mut err =
+                self.cx.struct_span_err(path.span, &format!("macro undefined: '{}!'", &extname));
+            self.cx.suggest_macro_name(&extname.as_str(), &mut err);
+            err.emit();
+            return kind.dummy(span);
+        };
+
+        let ident = ident.unwrap_or(keywords::Invalid.ident());
+        let marked_tts = mark_tts(&tts, mark);
+        let opt_expanded = match *extension {
+            NormalTT(ref expandfun, exp_span, allow_internal_unstable) => {
+                if ident.name != keywords::Invalid.name() {
+                    let msg =
+                        format!("macro {}! expects no ident argument, given '{}'", extname, ident);
+                    self.cx.span_err(path.span, &msg);
+                    return kind.dummy(span);
+                }
+
+                self.cx.bt_push(ExpnInfo {
+                    call_site: span,
+                    callee: NameAndSpan {
+                        format: MacroBang(extname),
+                        span: exp_span,
+                        allow_internal_unstable: allow_internal_unstable,
+                    },
+                });
+
+                kind.make_from(expandfun.expand(self.cx, span, &marked_tts))
+            }
+
+            IdentTT(ref expander, tt_span, allow_internal_unstable) => {
+                if ident.name == keywords::Invalid.name() {
+                    self.cx.span_err(path.span,
+                                    &format!("macro {}! expects an ident argument", extname));
+                    return kind.dummy(span);
+                };
+
+                self.cx.bt_push(ExpnInfo {
+                    call_site: span,
+                    callee: NameAndSpan {
+                        format: MacroBang(extname),
+                        span: tt_span,
+                        allow_internal_unstable: allow_internal_unstable,
+                    }
+                });
+
+                kind.make_from(expander.expand(self.cx, span, ident, marked_tts))
+            }
+
+            MacroRulesTT => {
+                if ident.name == keywords::Invalid.name() {
+                    self.cx.span_err(path.span,
+                                    &format!("macro {}! expects an ident argument", extname));
+                    return kind.dummy(span);
+                };
+
+                self.cx.bt_push(ExpnInfo {
+                    call_site: span,
+                    callee: NameAndSpan {
+                        format: MacroBang(extname),
+                        span: None,
+                        // `macro_rules!` doesn't directly allow unstable
+                        // (this is orthogonal to whether the macro it creates allows it)
+                        allow_internal_unstable: false,
+                    }
+                });
+
+                let def = ast::MacroDef {
+                    ident: ident,
+                    id: ast::DUMMY_NODE_ID,
+                    span: span,
+                    imported_from: None,
+                    use_locally: true,
+                    body: marked_tts,
+                    export: attr::contains_name(&attrs, "macro_export"),
+                    allow_internal_unstable: attr::contains_name(&attrs, "allow_internal_unstable"),
+                    attrs: attrs,
+                };
+
+                self.cx.insert_macro(def.clone());
+
+                // If keep_macs is true, expands to a MacEager::items instead.
+                if self.keep_macs {
+                    Some(reconstruct_macro_rules(&def, &path))
+                } else {
+                    Some(macro_scope_placeholder())
+                }
+            }
+
+            MultiDecorator(..) | MultiModifier(..) => {
+                self.cx.span_err(path.span,
+                                 &format!("`{}` can only be used in attributes", extname));
+                return kind.dummy(span);
+            }
+        };
+
+        let expanded = if let Some(expanded) = opt_expanded {
+            expanded
+        } else {
+            let msg = format!("non-{kind} macro in {kind} position: {name}",
+                              name = path.segments[0].identifier.name, kind = kind.name());
+            self.cx.span_err(path.span, &msg);
+            return kind.dummy(span);
+        };
+
+        let marked = expanded.fold_with(&mut Marker {
+            mark: mark,
+            expn_id: Some(self.cx.backtrace())
+        });
+        let configured = marked.fold_with(&mut self.strip_unconfigured());
+        self.load_macros(&configured);
+
+        let fully_expanded = if self.single_step {
+            configured
+        } else {
+            configured.fold_with(self)
+        };
+
+        self.cx.bt_pop();
+        fully_expanded
+    }
 }
 
 impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
@@ -474,7 +479,7 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
         let expr = expr.unwrap();
         if let ast::ExprKind::Mac(mac) = expr.node {
             let invoc = self.new_bang_invoc(mac, expr.attrs.into(), expr.span, ExpansionKind::Expr);
-            expand_invoc(invoc, self).make_expr()
+            self.expand_invoc(invoc).make_expr()
         } else {
             P(noop_fold_expr(expr, self))
         }
@@ -485,7 +490,7 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
         if let ast::ExprKind::Mac(mac) = expr.node {
             let invoc =
                 self.new_bang_invoc(mac, expr.attrs.into(), expr.span, ExpansionKind::OptExpr);
-            expand_invoc(invoc, self).make_opt_expr()
+            self.expand_invoc(invoc).make_opt_expr()
         } else {
             Some(P(noop_fold_expr(expr, self)))
         }
@@ -494,13 +499,13 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
     fn fold_pat(&mut self, pat: P) -> P {
         match pat.node {
             PatKind::Mac(_) => {}
-            _ => return noop_fold_pat(pat, self)
+            _ => return noop_fold_pat(pat, self),
         }
 
         pat.and_then(|pat| match pat.node {
             PatKind::Mac(mac) => {
                 let invoc = self.new_bang_invoc(mac, Vec::new(), pat.span, ExpansionKind::Pat);
-                expand_invoc(invoc, self).make_pat()
+                self.expand_invoc(invoc).make_pat()
             }
             _ => unreachable!(),
         })
@@ -509,11 +514,11 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
     fn fold_stmt(&mut self, stmt: ast::Stmt) -> SmallVector {
         let (mac, style, attrs) = match stmt.node {
             StmtKind::Mac(mac) => mac.unwrap(),
-            _ => return noop_fold_stmt(stmt, self)
+            _ => return noop_fold_stmt(stmt, self),
         };
 
         let invoc = self.new_bang_invoc(mac, attrs.into(), stmt.span, ExpansionKind::Stmts);
-        let mut fully_expanded = expand_invoc(invoc, self).make_stmts();
+        let mut fully_expanded = self.expand_invoc(invoc).make_stmts();
 
         // If this is a macro invocation with a semicolon, then apply that
         // semicolon to the final statement produced by expansion.
@@ -540,7 +545,7 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
         let (item, attr) = self.classify_item(item);
         if let Some(attr) = attr {
             let invoc = self.new_attr_invoc(attr, Annotatable::Item(item), ExpansionKind::Items);
-            return expand_invoc(invoc, self).make_items();
+            return self.expand_invoc(invoc).make_items();
         }
 
         match item.node {
@@ -560,7 +565,7 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
                             ident: Some(item.ident),
                             span: item.span,
                         });
-                        expand_invoc(invoc, self).make_items()
+                        self.expand_invoc(invoc).make_items()
                     }
                     _ => unreachable!(),
                 })
@@ -598,14 +603,14 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
         if let Some(attr) = attr {
             let item = Annotatable::TraitItem(P(item));
             let invoc = self.new_attr_invoc(attr, item, ExpansionKind::TraitItems);
-            return expand_invoc(invoc, self).make_trait_items();
+            return self.expand_invoc(invoc).make_trait_items();
         }
 
         match item.node {
             ast::TraitItemKind::Macro(mac) => {
                 let ast::TraitItem { attrs, span, .. } = item;
                 let invoc = self.new_bang_invoc(mac, attrs, span, ExpansionKind::TraitItems);
-                expand_invoc(invoc, self).make_trait_items()
+                self.expand_invoc(invoc).make_trait_items()
             }
             _ => fold::noop_fold_trait_item(item, self),
         }
@@ -616,16 +621,16 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
         if let Some(attr) = attr {
             let item = Annotatable::ImplItem(P(item));
             let invoc = self.new_attr_invoc(attr, item, ExpansionKind::ImplItems);
-            return expand_invoc(invoc, self).make_impl_items();
+            return self.expand_invoc(invoc).make_impl_items();
         }
 
         match item.node {
             ast::ImplItemKind::Macro(mac) => {
                 let ast::ImplItem { attrs, span, .. } = item;
                 let invoc = self.new_bang_invoc(mac, attrs, span, ExpansionKind::ImplItems);
-                expand_invoc(invoc, self).make_impl_items()
+                self.expand_invoc(invoc).make_impl_items()
             }
-            _ => fold::noop_fold_impl_item(item, self)
+            _ => fold::noop_fold_impl_item(item, self),
         }
     }
 
@@ -638,7 +643,7 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
         match ty.node {
             ast::TyKind::Mac(mac) => {
                 let invoc = self.new_bang_invoc(mac, Vec::new(), ty.span, ExpansionKind::Ty);
-                expand_invoc(invoc, self).make_ty()
+                self.expand_invoc(invoc).make_ty()
             }
             _ => unreachable!(),
         }

From c07ff8d26a6d5c8728419ae4e870b3a65940efbc Mon Sep 17 00:00:00 2001
From: Jeffrey Seyfried 
Date: Mon, 29 Aug 2016 05:32:41 +0000
Subject: [PATCH 196/443] Add module `ext::placeholders` with  `placeholder()`
 and `PlaceholderExpander`.

---
 src/libsyntax/ext/expand.rs       |  48 ++-------
 src/libsyntax/ext/placeholders.rs | 172 ++++++++++++++++++++++++++++++
 src/libsyntax/lib.rs              |   1 +
 3 files changed, 182 insertions(+), 39 deletions(-)
 create mode 100644 src/libsyntax/ext/placeholders.rs

diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 17b2b2d25b99..c5fc149bb7e8 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -12,8 +12,9 @@ use ast::{Block, Crate, Ident, Mac_, PatKind};
 use ast::{MacStmtStyle, StmtKind, ItemKind};
 use ast;
 use ext::hygiene::Mark;
+use ext::placeholders;
 use attr::{self, HasAttrs};
-use codemap::{dummy_spanned, ExpnInfo, NameAndSpan, MacroBang, MacroAttribute};
+use codemap::{ExpnInfo, NameAndSpan, MacroBang, MacroAttribute};
 use syntax_pos::{self, Span, ExpnId};
 use config::StripUnconfigured;
 use ext::base::*;
@@ -35,8 +36,8 @@ macro_rules! expansions {
             $(.$fold:ident)*  $(lift .$fold_elt:ident)*,
             $(.$visit:ident)* $(lift .$visit_elt:ident)*;)*) => {
         #[derive(Copy, Clone)]
-        enum ExpansionKind { OptExpr, $( $kind, )*  }
-        enum Expansion { OptExpr(Option>), $( $kind($ty), )* }
+        pub enum ExpansionKind { OptExpr, $( $kind, )*  }
+        pub enum Expansion { OptExpr(Option>), $( $kind($ty), )* }
 
         impl ExpansionKind {
             fn name(self) -> &'static str {
@@ -55,20 +56,20 @@ macro_rules! expansions {
         }
 
         impl Expansion {
-            fn make_opt_expr(self) -> Option> {
+            pub fn make_opt_expr(self) -> Option> {
                 match self {
                     Expansion::OptExpr(expr) => expr,
                     _ => panic!("Expansion::make_* called on the wrong kind of expansion"),
                 }
             }
-            $( fn $make(self) -> $ty {
+            $( pub fn $make(self) -> $ty {
                 match self {
                     Expansion::$kind(ast) => ast,
                     _ => panic!("Expansion::make_* called on the wrong kind of expansion"),
                 }
             } )*
 
-            fn fold_with(self, folder: &mut F) -> Self {
+            pub fn fold_with(self, folder: &mut F) -> Self {
                 use self::Expansion::*;
                 match self {
                     OptExpr(expr) => OptExpr(expr.and_then(|expr| folder.fold_opt_expr(expr))),
@@ -434,9 +435,9 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
 
                 // If keep_macs is true, expands to a MacEager::items instead.
                 if self.keep_macs {
-                    Some(reconstruct_macro_rules(&def, &path))
+                    Some(placeholders::reconstructed_macro_rules(&def, &path))
                 } else {
-                    Some(macro_scope_placeholder())
+                    Some(placeholders::macro_scope_placeholder())
                 }
             }
 
@@ -650,37 +651,6 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
     }
 }
 
-fn macro_scope_placeholder() -> Expansion {
-    Expansion::Items(SmallVector::one(P(ast::Item {
-        ident: keywords::Invalid.ident(),
-        attrs: Vec::new(),
-        id: ast::DUMMY_NODE_ID,
-        node: ast::ItemKind::Mac(dummy_spanned(ast::Mac_ {
-            path: ast::Path { span: syntax_pos::DUMMY_SP, global: false, segments: Vec::new() },
-            tts: Vec::new(),
-        })),
-        vis: ast::Visibility::Inherited,
-        span: syntax_pos::DUMMY_SP,
-    })))
-}
-
-fn reconstruct_macro_rules(def: &ast::MacroDef, path: &ast::Path) -> Expansion {
-    Expansion::Items(SmallVector::one(P(ast::Item {
-        ident: def.ident,
-        attrs: def.attrs.clone(),
-        id: ast::DUMMY_NODE_ID,
-        node: ast::ItemKind::Mac(ast::Mac {
-            span: def.span,
-            node: ast::Mac_ {
-                path: path.clone(),
-                tts: def.body.clone(),
-            }
-        }),
-        vis: ast::Visibility::Inherited,
-        span: def.span,
-    })))
-}
-
 pub struct ExpansionConfig<'feat> {
     pub crate_name: String,
     pub features: Option<&'feat Features>,
diff --git a/src/libsyntax/ext/placeholders.rs b/src/libsyntax/ext/placeholders.rs
new file mode 100644
index 000000000000..f1665bdde751
--- /dev/null
+++ b/src/libsyntax/ext/placeholders.rs
@@ -0,0 +1,172 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0  or the MIT license
+// , at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use ast;
+use codemap::{DUMMY_SP, dummy_spanned};
+use ext::expand::{Expansion, ExpansionKind};
+use fold::*;
+use parse::token::keywords;
+use ptr::P;
+use util::small_vector::SmallVector;
+
+use std::collections::HashMap;
+
+pub fn placeholder(kind: ExpansionKind, id: ast::NodeId) -> Expansion {
+    fn mac_placeholder() -> ast::Mac {
+        dummy_spanned(ast::Mac_ {
+            path: ast::Path { span: DUMMY_SP, global: false, segments: Vec::new() },
+            tts: Vec::new(),
+        })
+    }
+
+    let ident = keywords::Invalid.ident();
+    let attrs = Vec::new();
+    let vis = ast::Visibility::Inherited;
+    let span = DUMMY_SP;
+    let expr_placeholder = || P(ast::Expr {
+        id: id, span: span,
+        attrs: ast::ThinVec::new(),
+        node: ast::ExprKind::Mac(mac_placeholder()),
+    });
+
+    match kind {
+        ExpansionKind::Expr => Expansion::Expr(expr_placeholder()),
+        ExpansionKind::OptExpr => Expansion::OptExpr(Some(expr_placeholder())),
+        ExpansionKind::Items => Expansion::Items(SmallVector::one(P(ast::Item {
+            id: id, span: span, ident: ident, vis: vis, attrs: attrs,
+            node: ast::ItemKind::Mac(mac_placeholder()),
+        }))),
+        ExpansionKind::TraitItems => Expansion::TraitItems(SmallVector::one(ast::TraitItem {
+            id: id, span: span, ident: ident, attrs: attrs,
+            node: ast::TraitItemKind::Macro(mac_placeholder()),
+        })),
+        ExpansionKind::ImplItems => Expansion::ImplItems(SmallVector::one(ast::ImplItem {
+            id: id, span: span, ident: ident, vis: vis, attrs: attrs,
+            node: ast::ImplItemKind::Macro(mac_placeholder()),
+            defaultness: ast::Defaultness::Final,
+        })),
+        ExpansionKind::Pat => Expansion::Pat(P(ast::Pat {
+            id: id, span: span, node: ast::PatKind::Mac(mac_placeholder()),
+        })),
+        ExpansionKind::Ty => Expansion::Ty(P(ast::Ty {
+            id: id, span: span, node: ast::TyKind::Mac(mac_placeholder()),
+        })),
+        ExpansionKind::Stmts => Expansion::Stmts(SmallVector::one({
+            let mac = P((mac_placeholder(), ast::MacStmtStyle::Braces, ast::ThinVec::new()));
+            ast::Stmt { id: id, span: span, node: ast::StmtKind::Mac(mac) }
+        })),
+    }
+}
+
+pub fn macro_scope_placeholder() -> Expansion {
+    placeholder(ExpansionKind::Items, ast::DUMMY_NODE_ID)
+}
+
+pub struct PlaceholderExpander {
+    expansions: HashMap,
+}
+
+impl PlaceholderExpander {
+    pub fn new(expansions: HashMap) -> Self {
+        PlaceholderExpander {
+            expansions: expansions,
+        }
+    }
+
+    pub fn remove(&mut self, id: ast::NodeId) -> Expansion {
+        let expansion = self.expansions.remove(&id).unwrap();
+        expansion.fold_with(self)
+    }
+}
+
+impl Folder for PlaceholderExpander {
+    fn fold_item(&mut self, item: P) -> SmallVector> {
+        match item.node {
+            // Scope placeholder
+            ast::ItemKind::Mac(_) if item.id == ast::DUMMY_NODE_ID => SmallVector::one(item),
+            ast::ItemKind::Mac(_) => self.remove(item.id).make_items(),
+            _ => noop_fold_item(item, self),
+        }
+    }
+
+    fn fold_trait_item(&mut self, item: ast::TraitItem) -> SmallVector {
+        match item.node {
+            ast::TraitItemKind::Macro(_) => self.remove(item.id).make_trait_items(),
+            _ => noop_fold_trait_item(item, self),
+        }
+    }
+
+    fn fold_impl_item(&mut self, item: ast::ImplItem) -> SmallVector {
+        match item.node {
+            ast::ImplItemKind::Macro(_) => self.remove(item.id).make_impl_items(),
+            _ => noop_fold_impl_item(item, self),
+        }
+    }
+
+    fn fold_expr(&mut self, expr: P) -> P {
+        match expr.node {
+            ast::ExprKind::Mac(_) => self.remove(expr.id).make_expr(),
+            _ => expr.map(|expr| noop_fold_expr(expr, self)),
+        }
+    }
+
+    fn fold_opt_expr(&mut self, expr: P) -> Option> {
+        match expr.node {
+            ast::ExprKind::Mac(_) => self.remove(expr.id).make_opt_expr(),
+            _ => noop_fold_opt_expr(expr, self),
+        }
+    }
+
+    fn fold_stmt(&mut self, stmt: ast::Stmt) -> SmallVector {
+        let (style, mut expansion) = match stmt.node {
+            ast::StmtKind::Mac(mac) => (mac.1, self.remove(stmt.id).make_stmts()),
+            _ => return noop_fold_stmt(stmt, self),
+        };
+
+        if style == ast::MacStmtStyle::Semicolon {
+            if let Some(stmt) = expansion.pop() {
+                expansion.push(stmt.add_trailing_semicolon());
+            }
+        }
+
+        expansion
+    }
+
+    fn fold_pat(&mut self, pat: P) -> P {
+        match pat.node {
+            ast::PatKind::Mac(_) => self.remove(pat.id).make_pat(),
+            _ => noop_fold_pat(pat, self),
+        }
+    }
+
+    fn fold_ty(&mut self, ty: P) -> P {
+        match ty.node {
+            ast::TyKind::Mac(_) => self.remove(ty.id).make_ty(),
+            _ => noop_fold_ty(ty, self),
+        }
+    }
+}
+
+pub fn reconstructed_macro_rules(def: &ast::MacroDef, path: &ast::Path) -> Expansion {
+    Expansion::Items(SmallVector::one(P(ast::Item {
+        ident: def.ident,
+        attrs: def.attrs.clone(),
+        id: ast::DUMMY_NODE_ID,
+        node: ast::ItemKind::Mac(ast::Mac {
+            span: def.span,
+            node: ast::Mac_ {
+                path: path.clone(),
+                tts: def.body.clone(),
+            }
+        }),
+        vis: ast::Visibility::Inherited,
+        span: def.span,
+    })))
+}
diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs
index 65bc9f34c906..42201231247a 100644
--- a/src/libsyntax/lib.rs
+++ b/src/libsyntax/lib.rs
@@ -126,6 +126,7 @@ pub mod ext {
     pub mod base;
     pub mod build;
     pub mod expand;
+    pub mod placeholders;
     pub mod hygiene;
     pub mod proc_macro_shim;
     pub mod quote;

From d986bbe674d4fd554342771e7c031b3d22f9a800 Mon Sep 17 00:00:00 2001
From: Jeffrey Seyfried 
Date: Fri, 2 Sep 2016 09:12:47 +0000
Subject: [PATCH 197/443] Implement stackless expansion.

---
 src/libsyntax/ext/base.rs    |  25 +--
 src/libsyntax/ext/expand.rs  | 339 +++++++++++++++++++----------------
 src/libsyntax/ext/hygiene.rs |   4 +
 src/libsyntax/test.rs        |   7 +-
 4 files changed, 194 insertions(+), 181 deletions(-)

diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index fe2806891b85..edd38ea23e2f 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -646,7 +646,6 @@ impl<'a> ExtCtxt<'a> {
     }
 
     pub fn bt_push(&mut self, ei: ExpnInfo) {
-        self.recursion_count += 1;
         if self.recursion_count > self.ecfg.recursion_limit {
             self.span_fatal(ei.call_site,
                             &format!("recursion limit reached while expanding the macro `{}`",
@@ -660,17 +659,7 @@ impl<'a> ExtCtxt<'a> {
             callee: ei.callee
         });
     }
-    pub fn bt_pop(&mut self) {
-        match self.backtrace {
-            NO_EXPANSION => self.bug("tried to pop without a push"),
-            expn_id => {
-                self.recursion_count -= 1;
-                self.backtrace = self.codemap().with_expn_info(expn_id, |expn_info| {
-                    expn_info.map_or(NO_EXPANSION, |ei| ei.call_site.expn_id)
-                });
-            }
-        }
-    }
+    pub fn bt_pop(&mut self) {}
 
     pub fn insert_macro(&mut self, def: ast::MacroDef) {
         if def.export {
@@ -799,8 +788,6 @@ impl<'a> ExtCtxt<'a> {
             self.crate_root = Some("std");
         }
 
-        // User extensions must be added before expander.load_macros is called,
-        // so that macros from external crates shadow user defined extensions.
         for (name, extension) in user_exts {
             self.syntax_env.insert(name, extension);
         }
@@ -900,7 +887,7 @@ pub fn get_exprs_from_tts(cx: &mut ExtCtxt,
 /// This environment maps Names to SyntaxExtensions.
 pub struct SyntaxEnv {
     module_data: Vec,
-    current_module: Module,
+    pub current_module: Module,
 
     /// All bang-style macro/extension names
     /// encountered so far; to be used for diagnostics in resolve
@@ -940,10 +927,6 @@ impl SyntaxEnv {
         &self.module_data[module.0 as usize]
     }
 
-    pub fn set_current_module(&mut self, module: Module) -> Module {
-        ::std::mem::replace(&mut self.current_module, module)
-    }
-
     pub fn paths(&self) -> Rc {
         self.data(self.current_module).paths.clone()
     }
@@ -994,8 +977,6 @@ impl SyntaxEnv {
     }
 
     pub fn is_crate_root(&mut self) -> bool {
-        // The first frame is pushed in `SyntaxEnv::new()` and the second frame is
-        // pushed when folding the crate root pseudo-module (c.f. noop_fold_crate).
-        self.current_module.0 <= 1
+        self.current_module == Module(0)
     }
 }
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index c5fc149bb7e8..5624c2634661 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -12,7 +12,7 @@ use ast::{Block, Crate, Ident, Mac_, PatKind};
 use ast::{MacStmtStyle, StmtKind, ItemKind};
 use ast;
 use ext::hygiene::Mark;
-use ext::placeholders;
+use ext::placeholders::{self, placeholder, PlaceholderExpander};
 use attr::{self, HasAttrs};
 use codemap::{ExpnInfo, NameAndSpan, MacroBang, MacroAttribute};
 use syntax_pos::{self, Span, ExpnId};
@@ -28,11 +28,13 @@ use util::small_vector::SmallVector;
 use visit;
 use visit::Visitor;
 
+use std::collections::HashMap;
+use std::mem;
 use std::path::PathBuf;
 use std::rc::Rc;
 
 macro_rules! expansions {
-    ($($kind:ident: $ty:ty, $kind_name:expr, .$make:ident,
+    ($($kind:ident: $ty:ty [$($vec:ident, $ty_elt:ty)*], $kind_name:expr, .$make:ident,
             $(.$fold:ident)*  $(lift .$fold_elt:ident)*,
             $(.$visit:ident)* $(lift .$visit_elt:ident)*;)*) => {
         #[derive(Copy, Clone)]
@@ -91,18 +93,32 @@ macro_rules! expansions {
                 }
             }
         }
+
+        impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
+            fn fold_opt_expr(&mut self, expr: P) -> Option> {
+                self.expand(Expansion::OptExpr(Some(expr))).make_opt_expr()
+            }
+            $($(fn $fold(&mut self, node: $ty) -> $ty {
+                self.expand(Expansion::$kind(node)).$make()
+            })*)*
+            $($(fn $fold_elt(&mut self, node: $ty_elt) -> $ty {
+                self.expand(Expansion::$kind(SmallVector::one(node))).$make()
+            })*)*
+        }
     }
 }
 
 expansions! {
-    Expr: P, "expression", .make_expr, .fold_expr, .visit_expr;
-    Pat: P,   "pattern",    .make_pat,  .fold_pat,  .visit_pat;
-    Ty: P,     "type",       .make_ty,   .fold_ty,   .visit_ty;
-    Stmts: SmallVector, "statement", .make_stmts, lift .fold_stmt, lift .visit_stmt;
-    Items: SmallVector>, "item",   .make_items, lift .fold_item, lift .visit_item;
-    TraitItems: SmallVector,
+    Expr: P [], "expression", .make_expr, .fold_expr, .visit_expr;
+    Pat: P   [], "pattern",    .make_pat,  .fold_pat,  .visit_pat;
+    Ty: P     [], "type",       .make_ty,   .fold_ty,   .visit_ty;
+    Stmts: SmallVector [SmallVector, ast::Stmt],
+        "statement",  .make_stmts,       lift .fold_stmt,       lift .visit_stmt;
+    Items: SmallVector> [SmallVector, P],
+        "item",       .make_items,       lift .fold_item,       lift .visit_item;
+    TraitItems: SmallVector [SmallVector, ast::TraitItem],
         "trait item", .make_trait_items, lift .fold_trait_item, lift .visit_trait_item;
-    ImplItems: SmallVector,
+    ImplItems: SmallVector [SmallVector, ast::ImplItem],
         "impl item",  .make_impl_items,  lift .fold_impl_item,  lift .visit_impl_item;
 }
 
@@ -129,6 +145,9 @@ pub struct Invocation {
     kind: InvocationKind,
     expansion_kind: ExpansionKind,
     mark: Mark,
+    module: Module,
+    backtrace: ExpnId,
+    depth: usize,
 }
 
 enum InvocationKind {
@@ -144,7 +163,6 @@ enum InvocationKind {
     },
 }
 
-/// A tree-folder that performs macro expansion
 pub struct MacroExpander<'a, 'b:'a> {
     pub cx: &'a mut ExtCtxt<'b>,
     pub single_step: bool,
@@ -162,13 +180,57 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         }
     }
 
-    fn strip_unconfigured(&mut self) -> StripUnconfigured {
-        StripUnconfigured {
+    fn expand_crate(&mut self, mut krate: ast::Crate) -> ast::Crate {
+        let err_count = self.cx.parse_sess.span_diagnostic.err_count();
+
+        let items = Expansion::Items(SmallVector::many(krate.module.items));
+        krate.module.items = self.expand(items).make_items().into();
+        krate.exported_macros = self.cx.exported_macros.clone();
+
+        if self.cx.parse_sess.span_diagnostic.err_count() > err_count {
+            self.cx.parse_sess.span_diagnostic.abort_if_errors();
+        }
+
+        krate
+    }
+
+    // Fully expand all the invocations in `expansion`.
+    fn expand(&mut self, expansion: Expansion) -> Expansion {
+        let (expansion, mut invocations) = self.collect_invocations(expansion);
+        invocations.reverse();
+
+        let mut expansions = HashMap::new();
+        while let Some(invoc) = invocations.pop() {
+            let Invocation { mark, module, depth, backtrace, .. } = invoc;
+            self.cx.syntax_env.current_module = module;
+            self.cx.recursion_count = depth;
+            self.cx.backtrace = backtrace;
+
+            let expansion = self.expand_invoc(invoc);
+
+            self.cx.syntax_env.current_module = module;
+            self.cx.recursion_count = depth + 1;
+            let (expansion, new_invocations) = self.collect_invocations(expansion);
+
+            expansions.insert(mark.as_u32(), expansion);
+            if !self.single_step {
+                invocations.extend(new_invocations.into_iter().rev());
+            }
+        }
+
+        expansion.fold_with(&mut PlaceholderExpander::new(expansions))
+    }
+
+    fn collect_invocations(&mut self, expansion: Expansion) -> (Expansion, Vec) {
+        let expansion = expansion.fold_with(&mut StripUnconfigured {
             config: &self.cx.cfg,
             should_test: self.cx.ecfg.should_test,
             sess: self.cx.parse_sess,
             features: self.cx.ecfg.features,
-        }
+        });
+        self.load_macros(&expansion);
+        let mut collector = InvocationCollector { cx: self.cx, invocations: Vec::new() };
+        (expansion.fold_with(&mut collector), collector.invocations)
     }
 
     fn load_macros(&mut self, node: &Expansion) {
@@ -210,72 +272,6 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         });
     }
 
-    fn new_invoc(&self, expansion_kind: ExpansionKind, kind: InvocationKind)
-                 -> Invocation {
-        Invocation { mark: Mark::fresh(), kind: kind, expansion_kind: expansion_kind }
-    }
-
-    fn new_bang_invoc(
-        &self, mac: ast::Mac, attrs: Vec, span: Span, kind: ExpansionKind,
-    ) -> Invocation {
-        self.new_invoc(kind, InvocationKind::Bang {
-            attrs: attrs,
-            mac: mac,
-            ident: None,
-            span: span,
-        })
-    }
-
-    fn new_attr_invoc(&self, attr: ast::Attribute, item: Annotatable, kind: ExpansionKind)
-                      -> Invocation {
-        self.new_invoc(kind, InvocationKind::Attr { attr: attr, item: item })
-    }
-
-    // If `item` is an attr invocation, remove and return the macro attribute.
-    fn classify_item(&self, mut item: T) -> (T, Option) {
-        let mut attr = None;
-        item = item.map_attrs(|mut attrs| {
-            for i in 0..attrs.len() {
-                if let Some(extension) = self.cx.syntax_env.find(intern(&attrs[i].name())) {
-                    match *extension {
-                        MultiModifier(..) | MultiDecorator(..) => {
-                            attr = Some(attrs.remove(i));
-                            break;
-                        }
-                        _ => {}
-                    }
-                }
-            }
-            attrs
-        });
-        (item, attr)
-    }
-
-    // does this attribute list contain "macro_use" ?
-    fn contains_macro_use(&mut self, attrs: &[ast::Attribute]) -> bool {
-        for attr in attrs {
-            let mut is_use = attr.check_name("macro_use");
-            if attr.check_name("macro_escape") {
-                let msg = "macro_escape is a deprecated synonym for macro_use";
-                let mut err = self.cx.struct_span_warn(attr.span, msg);
-                is_use = true;
-                if let ast::AttrStyle::Inner = attr.node.style {
-                    err.help("consider an outer attribute, #[macro_use] mod ...").emit();
-                } else {
-                    err.emit();
-                }
-            };
-
-            if is_use {
-                if !attr.is_word() {
-                    self.cx.span_err(attr.span, "arguments to macro_use are not allowed here");
-                }
-                return true;
-            }
-        }
-        false
-    }
-
     fn expand_invoc(&mut self, invoc: Invocation) -> Expansion {
         match invoc.kind {
             InvocationKind::Bang { .. } => self.expand_bang_invoc(invoc),
@@ -305,7 +301,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
             }
         });
 
-        let modified = match *extension {
+        match *extension {
             MultiModifier(ref mac) => {
                 let item = mac.expand(self.cx, attr.span, &attr.node.value, item);
                 kind.expect_from_annotatables(item)
@@ -318,12 +314,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                 kind.expect_from_annotatables(items)
             }
             _ => unreachable!(),
-        };
-
-        self.cx.bt_pop();
-
-        let configured = modified.fold_with(&mut self.strip_unconfigured());
-        configured.fold_with(self)
+        }
     }
 
     /// Expand a macro invocation. Returns the result of expansion.
@@ -457,30 +448,94 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
             return kind.dummy(span);
         };
 
-        let marked = expanded.fold_with(&mut Marker {
+        expanded.fold_with(&mut Marker {
             mark: mark,
-            expn_id: Some(self.cx.backtrace())
-        });
-        let configured = marked.fold_with(&mut self.strip_unconfigured());
-        self.load_macros(&configured);
-
-        let fully_expanded = if self.single_step {
-            configured
-        } else {
-            configured.fold_with(self)
-        };
-
-        self.cx.bt_pop();
-        fully_expanded
+            expn_id: Some(self.cx.backtrace()),
+        })
     }
 }
 
-impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
+struct InvocationCollector<'a, 'b: 'a> {
+    cx: &'a mut ExtCtxt<'b>,
+    invocations: Vec,
+}
+
+impl<'a, 'b> InvocationCollector<'a, 'b> {
+    fn collect(&mut self, expansion_kind: ExpansionKind, kind: InvocationKind) -> Expansion {
+        let mark = Mark::fresh();
+        self.invocations.push(Invocation {
+            kind: kind,
+            expansion_kind: expansion_kind,
+            mark: mark,
+            module: self.cx.syntax_env.current_module,
+            backtrace: self.cx.backtrace,
+            depth: self.cx.recursion_count,
+        });
+        placeholder(expansion_kind, mark.as_u32())
+    }
+
+    fn collect_bang(
+        &mut self, mac: ast::Mac, attrs: Vec, span: Span, kind: ExpansionKind,
+    ) -> Expansion {
+        self.collect(kind, InvocationKind::Bang { attrs: attrs, mac: mac, ident: None, span: span })
+    }
+
+    fn collect_attr(&mut self, attr: ast::Attribute, item: Annotatable, kind: ExpansionKind)
+                    -> Expansion {
+        self.collect(kind, InvocationKind::Attr { attr: attr, item: item })
+    }
+
+    // If `item` is an attr invocation, remove and return the macro attribute.
+    fn classify_item(&self, mut item: T) -> (T, Option) {
+        let mut attr = None;
+        item = item.map_attrs(|mut attrs| {
+            for i in 0..attrs.len() {
+                if let Some(extension) = self.cx.syntax_env.find(intern(&attrs[i].name())) {
+                    match *extension {
+                        MultiModifier(..) | MultiDecorator(..) => {
+                            attr = Some(attrs.remove(i));
+                            break;
+                        }
+                        _ => {}
+                    }
+                }
+            }
+            attrs
+        });
+        (item, attr)
+    }
+
+    // does this attribute list contain "macro_use" ?
+    fn contains_macro_use(&mut self, attrs: &[ast::Attribute]) -> bool {
+        for attr in attrs {
+            let mut is_use = attr.check_name("macro_use");
+            if attr.check_name("macro_escape") {
+                let msg = "macro_escape is a deprecated synonym for macro_use";
+                let mut err = self.cx.struct_span_warn(attr.span, msg);
+                is_use = true;
+                if let ast::AttrStyle::Inner = attr.node.style {
+                    err.help("consider an outer attribute, #[macro_use] mod ...").emit();
+                } else {
+                    err.emit();
+                }
+            };
+
+            if is_use {
+                if !attr.is_word() {
+                    self.cx.span_err(attr.span, "arguments to macro_use are not allowed here");
+                }
+                return true;
+            }
+        }
+        false
+    }
+}
+
+impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
     fn fold_expr(&mut self, expr: P) -> P {
         let expr = expr.unwrap();
         if let ast::ExprKind::Mac(mac) = expr.node {
-            let invoc = self.new_bang_invoc(mac, expr.attrs.into(), expr.span, ExpansionKind::Expr);
-            self.expand_invoc(invoc).make_expr()
+            self.collect_bang(mac, expr.attrs.into(), expr.span, ExpansionKind::Expr).make_expr()
         } else {
             P(noop_fold_expr(expr, self))
         }
@@ -489,9 +544,8 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
     fn fold_opt_expr(&mut self, expr: P) -> Option> {
         let expr = expr.unwrap();
         if let ast::ExprKind::Mac(mac) = expr.node {
-            let invoc =
-                self.new_bang_invoc(mac, expr.attrs.into(), expr.span, ExpansionKind::OptExpr);
-            self.expand_invoc(invoc).make_opt_expr()
+            self.collect_bang(mac, expr.attrs.into(), expr.span, ExpansionKind::OptExpr)
+                .make_opt_expr()
         } else {
             Some(P(noop_fold_expr(expr, self)))
         }
@@ -504,10 +558,8 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
         }
 
         pat.and_then(|pat| match pat.node {
-            PatKind::Mac(mac) => {
-                let invoc = self.new_bang_invoc(mac, Vec::new(), pat.span, ExpansionKind::Pat);
-                self.expand_invoc(invoc).make_pat()
-            }
+            PatKind::Mac(mac) =>
+                self.collect_bang(mac, Vec::new(), pat.span, ExpansionKind::Pat).make_pat(),
             _ => unreachable!(),
         })
     }
@@ -518,35 +570,34 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
             _ => return noop_fold_stmt(stmt, self),
         };
 
-        let invoc = self.new_bang_invoc(mac, attrs.into(), stmt.span, ExpansionKind::Stmts);
-        let mut fully_expanded = self.expand_invoc(invoc).make_stmts();
+        let mut placeholder =
+            self.collect_bang(mac, attrs.into(), stmt.span, ExpansionKind::Stmts).make_stmts();
 
         // If this is a macro invocation with a semicolon, then apply that
         // semicolon to the final statement produced by expansion.
         if style == MacStmtStyle::Semicolon {
-            if let Some(stmt) = fully_expanded.pop() {
-                fully_expanded.push(stmt.add_trailing_semicolon());
+            if let Some(stmt) = placeholder.pop() {
+                placeholder.push(stmt.add_trailing_semicolon());
             }
         }
 
-        fully_expanded
+        placeholder
     }
 
     fn fold_block(&mut self, block: P) -> P {
         let paths = self.cx.syntax_env.paths();
         let module = self.cx.syntax_env.add_module(false, true, paths);
-        let orig_module = self.cx.syntax_env.set_current_module(module);
-
+        let orig_module = mem::replace(&mut self.cx.syntax_env.current_module, module);
         let result = noop_fold_block(block, self);
-        self.cx.syntax_env.set_current_module(orig_module);
+        self.cx.syntax_env.current_module = orig_module;
         result
     }
 
     fn fold_item(&mut self, item: P) -> SmallVector> {
         let (item, attr) = self.classify_item(item);
         if let Some(attr) = attr {
-            let invoc = self.new_attr_invoc(attr, Annotatable::Item(item), ExpansionKind::Items);
-            return self.expand_invoc(invoc).make_items();
+            let item = Annotatable::Item(item);
+            return self.collect_attr(attr, item, ExpansionKind::Items).make_items();
         }
 
         match item.node {
@@ -560,13 +611,12 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
 
                 item.and_then(|item| match item.node {
                     ItemKind::Mac(mac) => {
-                        let invoc = self.new_invoc(ExpansionKind::Items, InvocationKind::Bang {
+                        self.collect(ExpansionKind::Items, InvocationKind::Bang {
                             mac: mac,
                             attrs: item.attrs,
                             ident: Some(item.ident),
                             span: item.span,
-                        });
-                        self.expand_invoc(invoc).make_items()
+                        }).make_items()
                     }
                     _ => unreachable!(),
                 })
@@ -590,9 +640,9 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
                 let macro_use = self.contains_macro_use(&item.attrs);
                 let in_block = self.cx.syntax_env.in_block();
                 let module = self.cx.syntax_env.add_module(macro_use, in_block, Rc::new(paths));
-                let module = self.cx.syntax_env.set_current_module(module);
+                let module = mem::replace(&mut self.cx.syntax_env.current_module, module);
                 let result = noop_fold_item(item, self);
-                self.cx.syntax_env.set_current_module(module);
+                self.cx.syntax_env.current_module = module;
                 result
             },
             _ => noop_fold_item(item, self),
@@ -603,15 +653,13 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
         let (item, attr) = self.classify_item(item);
         if let Some(attr) = attr {
             let item = Annotatable::TraitItem(P(item));
-            let invoc = self.new_attr_invoc(attr, item, ExpansionKind::TraitItems);
-            return self.expand_invoc(invoc).make_trait_items();
+            return self.collect_attr(attr, item, ExpansionKind::TraitItems).make_trait_items()
         }
 
         match item.node {
             ast::TraitItemKind::Macro(mac) => {
                 let ast::TraitItem { attrs, span, .. } = item;
-                let invoc = self.new_bang_invoc(mac, attrs, span, ExpansionKind::TraitItems);
-                self.expand_invoc(invoc).make_trait_items()
+                self.collect_bang(mac, attrs, span, ExpansionKind::TraitItems).make_trait_items()
             }
             _ => fold::noop_fold_trait_item(item, self),
         }
@@ -621,15 +669,13 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
         let (item, attr) = self.classify_item(item);
         if let Some(attr) = attr {
             let item = Annotatable::ImplItem(P(item));
-            let invoc = self.new_attr_invoc(attr, item, ExpansionKind::ImplItems);
-            return self.expand_invoc(invoc).make_impl_items();
+            return self.collect_attr(attr, item, ExpansionKind::ImplItems).make_impl_items();
         }
 
         match item.node {
             ast::ImplItemKind::Macro(mac) => {
                 let ast::ImplItem { attrs, span, .. } = item;
-                let invoc = self.new_bang_invoc(mac, attrs, span, ExpansionKind::ImplItems);
-                self.expand_invoc(invoc).make_impl_items()
+                self.collect_bang(mac, attrs, span, ExpansionKind::ImplItems).make_impl_items()
             }
             _ => fold::noop_fold_impl_item(item, self),
         }
@@ -642,10 +688,8 @@ impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
         };
 
         match ty.node {
-            ast::TyKind::Mac(mac) => {
-                let invoc = self.new_bang_invoc(mac, Vec::new(), ty.span, ExpansionKind::Ty);
-                self.expand_invoc(invoc).make_ty()
-            }
+            ast::TyKind::Mac(mac) =>
+                self.collect_bang(mac, Vec::new(), ty.span, ExpansionKind::Ty).make_ty(),
             _ => unreachable!(),
         }
     }
@@ -699,30 +743,17 @@ impl<'feat> ExpansionConfig<'feat> {
 pub fn expand_crate(cx: &mut ExtCtxt,
                     user_exts: Vec,
                     c: Crate) -> Crate {
-    let mut expander = MacroExpander::new(cx, false, false);
-    expand_crate_with_expander(&mut expander, user_exts, c)
+    cx.initialize(user_exts, &c);
+    cx.expander().expand_crate(c)
 }
 
 // Expands crate using supplied MacroExpander - allows for
 // non-standard expansion behaviour (e.g. step-wise).
 pub fn expand_crate_with_expander(expander: &mut MacroExpander,
                                   user_exts: Vec,
-                                  mut c: Crate) -> Crate {
+                                  c: Crate) -> Crate {
     expander.cx.initialize(user_exts, &c);
-
-    let items = Expansion::Items(SmallVector::many(c.module.items));
-    let configured = items.fold_with(&mut expander.strip_unconfigured());
-    expander.load_macros(&configured);
-    c.module.items = configured.make_items().into();
-
-    let err_count = expander.cx.parse_sess.span_diagnostic.err_count();
-    let mut ret = expander.fold_crate(c);
-    if expander.cx.parse_sess.span_diagnostic.err_count() > err_count {
-        expander.cx.parse_sess.span_diagnostic.abort_if_errors();
-    }
-
-    ret.exported_macros = expander.cx.exported_macros.clone();
-    ret
+    expander.expand_crate(c)
 }
 
 // A Marker adds the given mark to the syntax context and
diff --git a/src/libsyntax/ext/hygiene.rs b/src/libsyntax/ext/hygiene.rs
index ade165e0ef9c..27e8eab62e11 100644
--- a/src/libsyntax/ext/hygiene.rs
+++ b/src/libsyntax/ext/hygiene.rs
@@ -40,6 +40,10 @@ impl Mark {
             ::std::mem::replace(&mut data.next_mark, next_mark)
         })
     }
+
+    pub fn as_u32(&self) -> u32 {
+        self.0
+    }
 }
 
 struct HygieneData {
diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs
index 6155ad729a28..3108296e778a 100644
--- a/src/libsyntax/test.rs
+++ b/src/libsyntax/test.rs
@@ -300,14 +300,11 @@ fn generate_test_harness(sess: &ParseSess,
         }
     });
 
-    let mut fold = TestHarnessGenerator {
+    TestHarnessGenerator {
         cx: cx,
         tests: Vec::new(),
         tested_submods: Vec::new(),
-    };
-    let res = fold.fold_crate(krate);
-    fold.cx.ext_cx.bt_pop();
-    return res;
+    }.fold_crate(krate)
 }
 
 /// Craft a span that will be ignored by the stability lint's

From 2c88b4b7908b8451e9c3a3c8d9c8ea43fa78c52a Mon Sep 17 00:00:00 2001
From: Jeffrey Seyfried 
Date: Fri, 2 Sep 2016 02:20:03 +0000
Subject: [PATCH 198/443] Load macros from `extern crate`s in the
 `InvocationCollector` fold.

---
 src/libsyntax/ext/expand.rs | 84 ++++++++++---------------------------
 1 file changed, 22 insertions(+), 62 deletions(-)

diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 5624c2634661..0986d32ff56a 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -25,8 +25,6 @@ use parse::token::{intern, keywords};
 use ptr::P;
 use tokenstream::TokenTree;
 use util::small_vector::SmallVector;
-use visit;
-use visit::Visitor;
 
 use std::collections::HashMap;
 use std::mem;
@@ -35,8 +33,7 @@ use std::rc::Rc;
 
 macro_rules! expansions {
     ($($kind:ident: $ty:ty [$($vec:ident, $ty_elt:ty)*], $kind_name:expr, .$make:ident,
-            $(.$fold:ident)*  $(lift .$fold_elt:ident)*,
-            $(.$visit:ident)* $(lift .$visit_elt:ident)*;)*) => {
+            $(.$fold:ident)*  $(lift .$fold_elt:ident)*;)*) => {
         #[derive(Copy, Clone)]
         pub enum ExpansionKind { OptExpr, $( $kind, )*  }
         pub enum Expansion { OptExpr(Option>), $( $kind($ty), )* }
@@ -81,17 +78,6 @@ macro_rules! expansions {
                     }, )*)*
                 }
             }
-
-            fn visit_with(&self, visitor: &mut V) {
-                match *self {
-                    Expansion::OptExpr(Some(ref expr)) => visitor.visit_expr(expr),
-                    $($( Expansion::$kind(ref ast) => visitor.$visit(ast), )*)*
-                    $($( Expansion::$kind(ref ast) => for ast in ast.as_slice() {
-                        visitor.$visit_elt(ast);
-                    }, )*)*
-                    _ => {}
-                }
-            }
         }
 
         impl<'a, 'b> Folder for MacroExpander<'a, 'b> {
@@ -109,17 +95,17 @@ macro_rules! expansions {
 }
 
 expansions! {
-    Expr: P [], "expression", .make_expr, .fold_expr, .visit_expr;
-    Pat: P   [], "pattern",    .make_pat,  .fold_pat,  .visit_pat;
-    Ty: P     [], "type",       .make_ty,   .fold_ty,   .visit_ty;
+    Expr: P [], "expression", .make_expr, .fold_expr;
+    Pat: P   [], "pattern",    .make_pat,  .fold_pat;
+    Ty: P     [], "type",       .make_ty,   .fold_ty;
     Stmts: SmallVector [SmallVector, ast::Stmt],
-        "statement",  .make_stmts,       lift .fold_stmt,       lift .visit_stmt;
+        "statement",  .make_stmts,       lift .fold_stmt;
     Items: SmallVector> [SmallVector, P],
-        "item",       .make_items,       lift .fold_item,       lift .visit_item;
+        "item",       .make_items,       lift .fold_item;
     TraitItems: SmallVector [SmallVector, ast::TraitItem],
-        "trait item", .make_trait_items, lift .fold_trait_item, lift .visit_trait_item;
+        "trait item", .make_trait_items, lift .fold_trait_item;
     ImplItems: SmallVector [SmallVector, ast::ImplItem],
-        "impl item",  .make_impl_items,  lift .fold_impl_item,  lift .visit_impl_item;
+        "impl item",  .make_impl_items,  lift .fold_impl_item;
 }
 
 impl ExpansionKind {
@@ -228,50 +214,10 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
             sess: self.cx.parse_sess,
             features: self.cx.ecfg.features,
         });
-        self.load_macros(&expansion);
         let mut collector = InvocationCollector { cx: self.cx, invocations: Vec::new() };
         (expansion.fold_with(&mut collector), collector.invocations)
     }
 
-    fn load_macros(&mut self, node: &Expansion) {
-        struct MacroLoadingVisitor<'a, 'b: 'a>{
-            cx: &'a mut ExtCtxt<'b>,
-            at_crate_root: bool,
-        }
-
-        impl<'a, 'b> Visitor for MacroLoadingVisitor<'a, 'b> {
-            fn visit_mac(&mut self, _: &ast::Mac) {}
-            fn visit_item(&mut self, item: &ast::Item) {
-                if let ast::ItemKind::ExternCrate(..) = item.node {
-                    // We need to error on `#[macro_use] extern crate` when it isn't at the
-                    // crate root, because `$crate` won't work properly.
-                    for def in self.cx.loader.load_crate(item, self.at_crate_root) {
-                        match def {
-                            LoadedMacro::Def(def) => self.cx.insert_macro(def),
-                            LoadedMacro::CustomDerive(name, ext) => {
-                                self.cx.insert_custom_derive(&name, ext, item.span);
-                            }
-                        }
-                    }
-                } else {
-                    let at_crate_root = ::std::mem::replace(&mut self.at_crate_root, false);
-                    visit::walk_item(self, item);
-                    self.at_crate_root = at_crate_root;
-                }
-            }
-            fn visit_block(&mut self, block: &ast::Block) {
-                let at_crate_root = ::std::mem::replace(&mut self.at_crate_root, false);
-                visit::walk_block(self, block);
-                self.at_crate_root = at_crate_root;
-            }
-        }
-
-        node.visit_with(&mut MacroLoadingVisitor {
-            at_crate_root: self.cx.syntax_env.is_crate_root(),
-            cx: self.cx,
-        });
-    }
-
     fn expand_invoc(&mut self, invoc: Invocation) -> Expansion {
         match invoc.kind {
             InvocationKind::Bang { .. } => self.expand_bang_invoc(invoc),
@@ -645,6 +591,20 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
                 self.cx.syntax_env.current_module = module;
                 result
             },
+            ast::ItemKind::ExternCrate(..) => {
+                // We need to error on `#[macro_use] extern crate` when it isn't at the
+                // crate root, because `$crate` won't work properly.
+                let is_crate_root = self.cx.syntax_env.is_crate_root();
+                for def in self.cx.loader.load_crate(&*item, is_crate_root) {
+                    match def {
+                        LoadedMacro::Def(def) => self.cx.insert_macro(def),
+                        LoadedMacro::CustomDerive(name, ext) => {
+                            self.cx.insert_custom_derive(&name, ext, item.span);
+                        }
+                    }
+                }
+                SmallVector::one(item)
+            },
             _ => noop_fold_item(item, self),
         }
     }

From 09e6a983805c5f4f7cbb7e244f1fa48c2f91ec95 Mon Sep 17 00:00:00 2001
From: "Felix S. Klock II" 
Date: Mon, 5 Sep 2016 12:56:29 +0200
Subject: [PATCH 199/443] Fix issue #36036.

We were treating an associated type as unsized even when the concrete
instantiation was actually sized. Fix is to normalize before checking
if it is sized.
---
 src/librustc/ty/layout.rs                     |  2 +-
 .../issue-36036-associated-type-layout.rs     | 36 +++++++++++++++++++
 2 files changed, 37 insertions(+), 1 deletion(-)
 create mode 100644 src/test/run-pass/issue-36036-associated-type-layout.rs

diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs
index 9270057b5441..276fc708eed1 100644
--- a/src/librustc/ty/layout.rs
+++ b/src/librustc/ty/layout.rs
@@ -856,10 +856,10 @@ impl<'a, 'gcx, 'tcx> Layout {
             ty::TyRef(_, ty::TypeAndMut { ty: pointee, .. }) |
             ty::TyRawPtr(ty::TypeAndMut { ty: pointee, .. }) => {
                 let non_zero = !ty.is_unsafe_ptr();
+                let pointee = normalize_associated_type(infcx, pointee);
                 if pointee.is_sized(tcx, &infcx.parameter_environment, DUMMY_SP) {
                     Scalar { value: Pointer, non_zero: non_zero }
                 } else {
-                    let pointee = normalize_associated_type(infcx, pointee);
                     let unsized_part = tcx.struct_tail(pointee);
                     let meta = match unsized_part.sty {
                         ty::TySlice(_) | ty::TyStr => {
diff --git a/src/test/run-pass/issue-36036-associated-type-layout.rs b/src/test/run-pass/issue-36036-associated-type-layout.rs
new file mode 100644
index 000000000000..4ee3be0eb7b8
--- /dev/null
+++ b/src/test/run-pass/issue-36036-associated-type-layout.rs
@@ -0,0 +1,36 @@
+// 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.
+
+// Issue 36036: computing the layout of a type composed from another
+// trait's associated type caused compiler to ICE when the associated
+// type was allowed to be unsized, even though the known instantiated
+// type is itself sized.
+
+#![allow(dead_code)]
+
+trait Context {
+    type Container: ?Sized;
+}
+
+impl Context for u16 {
+    type Container = u8;
+}
+
+struct Wrapper {
+    container: &'static C::Container
+}
+
+fn foobar(_: Wrapper) {}
+
+static VALUE: u8 = 0;
+
+fn main() {
+    foobar(Wrapper { container: &VALUE });
+}

From d53ea97bfc149da4cdd0fb1fd1beab08295ae45d Mon Sep 17 00:00:00 2001
From: Gavin Baker 
Date: Tue, 30 Aug 2016 11:04:55 +1000
Subject: [PATCH 200/443] E0516 Update error format #36108 - fixes #36108 -
 part of #35233

---
 src/librustc/hir/check_attr.rs | 18 ++++++++++++------
 src/librustc_typeck/astconv.rs |  7 +++++--
 src/test/compile-fail/E0516.rs |  1 +
 3 files changed, 18 insertions(+), 8 deletions(-)

diff --git a/src/librustc/hir/check_attr.rs b/src/librustc/hir/check_attr.rs
index a2d4239388ac..6997b5d77022 100644
--- a/src/librustc/hir/check_attr.rs
+++ b/src/librustc/hir/check_attr.rs
@@ -56,18 +56,21 @@ impl<'a> CheckAttrVisitor<'a> {
 
         let mut conflicting_reprs = 0;
         for word in words {
+
             let name = match word.name() {
                 Some(word) => word,
                 None => continue,
             };
 
-            let message = match &*name {
+            let word: &str = &word.name();
+            let (message, label) = match word {
                 "C" => {
                     conflicting_reprs += 1;
                     if target != Target::Struct &&
                             target != Target::Union &&
                             target != Target::Enum {
-                        "attribute should be applied to struct, enum or union"
+                                ("attribute should be applied to struct, enum or union",
+                                 "a struct, enum or union")
                     } else {
                         continue
                     }
@@ -85,7 +88,8 @@ impl<'a> CheckAttrVisitor<'a> {
                 "simd" => {
                     conflicting_reprs += 1;
                     if target != Target::Struct {
-                        "attribute should be applied to struct"
+                        ("attribute should be applied to struct",
+                         "a struct")
                     } else {
                         continue
                     }
@@ -95,15 +99,17 @@ impl<'a> CheckAttrVisitor<'a> {
                 "isize" | "usize" => {
                     conflicting_reprs += 1;
                     if target != Target::Enum {
-                        "attribute should be applied to enum"
+                        ("attribute should be applied to enum",
+                         "an enum")
                     } else {
                         continue
                     }
                 }
                 _ => continue,
             };
-
-            span_err!(self.sess, attr.span, E0517, "{}", message);
+            struct_span_err!(self.sess, attr.span, E0517, "{}", message)
+                .span_label(attr.span, &format!("requires {}", label))
+                .emit();
         }
         if conflicting_reprs > 1 {
             span_warn!(self.sess, attr.span, E0566,
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 5925d222b446..334b7a5063a3 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -1769,8 +1769,11 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                 }
             }
             hir::TyTypeof(ref _e) => {
-                span_err!(tcx.sess, ast_ty.span, E0516,
-                      "`typeof` is a reserved keyword but unimplemented");
+                struct_span_err!(tcx.sess, ast_ty.span, E0516,
+                                 "`typeof` is a reserved keyword but unimplemented")
+                    .span_label(ast_ty.span, &format!("reserved keyword"))
+                    .emit();
+
                 tcx.types.err
             }
             hir::TyInfer => {
diff --git a/src/test/compile-fail/E0516.rs b/src/test/compile-fail/E0516.rs
index a5f609de8497..be2b89c5f396 100644
--- a/src/test/compile-fail/E0516.rs
+++ b/src/test/compile-fail/E0516.rs
@@ -10,4 +10,5 @@
 
 fn main() {
     let x: typeof(92) = 92; //~ ERROR E0516
+                            //~| reserved keyword
 }

From 8bcd6a33bebb8177781ae07ea1fc0d4a9a679627 Mon Sep 17 00:00:00 2001
From: Gavin Baker 
Date: Tue, 30 Aug 2016 11:30:46 +1000
Subject: [PATCH 201/443] E0517 Update error format #36109

- Fixes #36109
- Part of #35233
---
 src/librustc/hir/check_attr.rs | 6 +++---
 src/test/compile-fail/E0517.rs | 4 ++++
 2 files changed, 7 insertions(+), 3 deletions(-)

diff --git a/src/librustc/hir/check_attr.rs b/src/librustc/hir/check_attr.rs
index 6997b5d77022..a3ab5f949e7d 100644
--- a/src/librustc/hir/check_attr.rs
+++ b/src/librustc/hir/check_attr.rs
@@ -62,8 +62,7 @@ impl<'a> CheckAttrVisitor<'a> {
                 None => continue,
             };
 
-            let word: &str = &word.name();
-            let (message, label) = match word {
+            let (message, label) = match &*name {
                 "C" => {
                     conflicting_reprs += 1;
                     if target != Target::Struct &&
@@ -80,7 +79,8 @@ impl<'a> CheckAttrVisitor<'a> {
                     // can be used to modify another repr hint
                     if target != Target::Struct &&
                             target != Target::Union {
-                        "attribute should be applied to struct or union"
+                                ("attribute should be applied to struct or union",
+                                 "a struct or union")
                     } else {
                         continue
                     }
diff --git a/src/test/compile-fail/E0517.rs b/src/test/compile-fail/E0517.rs
index be06e809915b..b79cb2c44af3 100644
--- a/src/test/compile-fail/E0517.rs
+++ b/src/test/compile-fail/E0517.rs
@@ -9,15 +9,19 @@
 // except according to those terms.
 
 #[repr(C)] //~ ERROR E0517
+           //~| requires a struct, enum or union
 type Foo = u8;
 
 #[repr(packed)] //~ ERROR E0517
+                //~| requires a struct
 enum Foo2 {Bar, Baz}
 
 #[repr(u8)] //~ ERROR E0517
+            //~| requires an enum
 struct Foo3 {bar: bool, baz: bool}
 
 #[repr(C)] //~ ERROR E0517
+           //~| requires a struct, enum or union
 impl Foo3 {
 }
 

From cd56d47da3a2c2ed2eb2a1e4e54ca471c2c9172a Mon Sep 17 00:00:00 2001
From: Gavin Baker 
Date: Tue, 30 Aug 2016 11:44:25 +1000
Subject: [PATCH 202/443] E0518 Update error format #36111

- Fixes #36111
- Part of #35233
---
 src/librustc/hir/check_attr.rs | 4 +++-
 src/test/compile-fail/E0518.rs | 2 ++
 2 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/src/librustc/hir/check_attr.rs b/src/librustc/hir/check_attr.rs
index a3ab5f949e7d..8ba52cdb64f5 100644
--- a/src/librustc/hir/check_attr.rs
+++ b/src/librustc/hir/check_attr.rs
@@ -42,7 +42,9 @@ struct CheckAttrVisitor<'a> {
 impl<'a> CheckAttrVisitor<'a> {
     fn check_inline(&self, attr: &ast::Attribute, target: Target) {
         if target != Target::Fn {
-            span_err!(self.sess, attr.span, E0518, "attribute should be applied to function");
+            struct_span_err!(self.sess, attr.span, E0518, "attribute should be applied to function")
+                .span_label(attr.span, &format!("requires a function"))
+                .emit();
         }
     }
 
diff --git a/src/test/compile-fail/E0518.rs b/src/test/compile-fail/E0518.rs
index 8518bb4a6be3..f9494e0bcb53 100644
--- a/src/test/compile-fail/E0518.rs
+++ b/src/test/compile-fail/E0518.rs
@@ -9,9 +9,11 @@
 // except according to those terms.
 
 #[inline(always)] //~ ERROR E0518
+                  //~| requires a function
 struct Foo;
 
 #[inline(never)] //~ ERROR E0518
+                 //~| requires a function
 impl Foo {
 }
 

From 046c7f23680f9a8f24209be4097656f91ade0bbb Mon Sep 17 00:00:00 2001
From: Josh Triplett 
Date: Mon, 5 Sep 2016 10:19:00 -0700
Subject: [PATCH 203/443] Add test for unused field in union

---
 .../union/union-lint-dead-code.rs             | 26 +++++++++++++++++++
 1 file changed, 26 insertions(+)
 create mode 100644 src/test/compile-fail/union/union-lint-dead-code.rs

diff --git a/src/test/compile-fail/union/union-lint-dead-code.rs b/src/test/compile-fail/union/union-lint-dead-code.rs
new file mode 100644
index 000000000000..7a552c8f8b76
--- /dev/null
+++ b/src/test/compile-fail/union/union-lint-dead-code.rs
@@ -0,0 +1,26 @@
+// 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.
+
+#![feature(untagged_unions)]
+#![deny(dead_code)]
+
+union Foo {
+    x: usize,
+    b: bool, //~ ERROR: field is never used
+    _unused: u16,
+}
+
+fn field_read(f: Foo) -> usize {
+    unsafe { f.x }
+}
+
+fn main() {
+    let _ = field_read(Foo { x: 2 });
+}

From e8c5dc48063f5290af195f66ae718f78cd6cee9e Mon Sep 17 00:00:00 2001
From: Cobrand 
Date: Tue, 30 Aug 2016 00:33:29 +0200
Subject: [PATCH 204/443] Updated E0527 to new error format

* Closes #36113
---
 src/librustc_typeck/check/_match.rs | 9 ++++++---
 src/test/compile-fail/E0527.rs      | 4 +++-
 2 files changed, 9 insertions(+), 4 deletions(-)

diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index c67b98761aa6..17fb68339198 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -233,9 +233,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                         let min_len = before.len() + after.len();
                         if slice.is_none() {
                             if min_len != size {
-                                span_err!(tcx.sess, pat.span, E0527,
-                                          "pattern requires {} elements but array has {}",
-                                          min_len, size);
+                                struct_span_err!(
+                                    tcx.sess, pat.span, E0527,
+                                    "pattern requires {} elements but array has {}",
+                                    min_len, size)
+                                    .span_label(pat.span, &format!("expected {} elements",size))
+                                    .emit();
                             }
                             (inner_ty, tcx.types.err)
                         } else if let Some(rest) = size.checked_sub(min_len) {
diff --git a/src/test/compile-fail/E0527.rs b/src/test/compile-fail/E0527.rs
index f03f35a57104..0b664094a40d 100644
--- a/src/test/compile-fail/E0527.rs
+++ b/src/test/compile-fail/E0527.rs
@@ -13,7 +13,9 @@
 fn main() {
     let r = &[1, 2, 3, 4];
     match r {
-        &[a, b] => { //~ ERROR E0527
+        &[a, b] => {
+            //~^ ERROR E0527
+            //~| NOTE expected 4 elements
             println!("a={}, b={}", a, b);
         }
     }

From 915bbdac580b26e2d47baa1ca3fd21349c4f4b0b Mon Sep 17 00:00:00 2001
From: Piotr Jawniak 
Date: Sun, 4 Sep 2016 18:35:35 +0200
Subject: [PATCH 205/443] rustdoc: Filter more incorrect methods inherited
 through Deref

Old code filtered out only static methods. This code also excludes
&mut self methods if there is no DerefMut implementation
---
 src/librustdoc/clean/mod.rs       |  6 +++
 src/librustdoc/core.rs            |  2 +
 src/librustdoc/html/render.rs     | 87 +++++++++++++++++++++----------
 src/librustdoc/test.rs            |  1 +
 src/test/rustdoc/issue-35169-2.rs | 45 ++++++++++++++++
 src/test/rustdoc/issue-35169.rs   | 40 ++++++++++++++
 6 files changed, 154 insertions(+), 27 deletions(-)
 create mode 100644 src/test/rustdoc/issue-35169-2.rs
 create mode 100644 src/test/rustdoc/issue-35169.rs

diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index f8ec5a55e7d4..36b03ce8a2da 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -134,6 +134,8 @@ impl<'a, 'tcx> Clean for visit_ast::RustdocVisitor<'a, 'tcx> {
         if let Some(t) = cx.tcx_opt() {
             cx.deref_trait_did.set(t.lang_items.deref_trait());
             cx.renderinfo.borrow_mut().deref_trait_did = cx.deref_trait_did.get();
+            cx.deref_mut_trait_did.set(t.lang_items.deref_mut_trait());
+            cx.renderinfo.borrow_mut().deref_mut_trait_did = cx.deref_mut_trait_did.get();
         }
 
         let mut externs = Vec::new();
@@ -1117,6 +1119,10 @@ impl FnDecl {
     pub fn has_self(&self) -> bool {
         return self.inputs.values.len() > 0 && self.inputs.values[0].name == "self";
     }
+
+    pub fn self_type(&self) -> Option {
+        self.inputs.values.get(0).and_then(|v| v.to_self())
+    }
 }
 
 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index 26f792a1fdf9..8c5bd9fe3e62 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -53,6 +53,7 @@ pub struct DocContext<'a, 'tcx: 'a> {
     pub input: Input,
     pub populated_crate_impls: RefCell>,
     pub deref_trait_did: Cell>,
+    pub deref_mut_trait_did: Cell>,
     // Note that external items for which `doc(hidden)` applies to are shown as
     // non-reachable while local items aren't. This is because we're reusing
     // the access levels from crateanalysis.
@@ -180,6 +181,7 @@ pub fn run_core(search_paths: SearchPaths,
             input: input,
             populated_crate_impls: RefCell::new(FnvHashSet()),
             deref_trait_did: Cell::new(None),
+            deref_mut_trait_did: Cell::new(None),
             access_levels: RefCell::new(access_levels),
             external_traits: RefCell::new(FnvHashMap()),
             renderinfo: RefCell::new(Default::default()),
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index 6f66ce88df7a..c38f0a9584b1 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -64,7 +64,7 @@ use rustc::hir;
 use rustc::util::nodemap::{FnvHashMap, FnvHashSet};
 use rustc_data_structures::flock;
 
-use clean::{self, Attributes, GetDefId};
+use clean::{self, Attributes, GetDefId, SelfTy, Mutability};
 use doctree;
 use fold::DocFolder;
 use html::escape::Escape;
@@ -266,6 +266,7 @@ pub struct Cache {
     seen_mod: bool,
     stripped_mod: bool,
     deref_trait_did: Option,
+    deref_mut_trait_did: Option,
 
     // In rare case where a structure is defined in one module but implemented
     // in another, if the implementing module is parsed before defining module,
@@ -283,6 +284,7 @@ pub struct RenderInfo {
     pub external_paths: ::core::ExternalPaths,
     pub external_typarams: FnvHashMap,
     pub deref_trait_did: Option,
+    pub deref_mut_trait_did: Option,
 }
 
 /// Helper struct to render all source code to HTML pages
@@ -508,6 +510,7 @@ pub fn run(mut krate: clean::Crate,
         external_paths,
         external_typarams,
         deref_trait_did,
+        deref_mut_trait_did,
     } = renderinfo;
 
     let external_paths = external_paths.into_iter()
@@ -532,6 +535,7 @@ pub fn run(mut krate: clean::Crate,
         orphan_methods: Vec::new(),
         traits: mem::replace(&mut krate.external_traits, FnvHashMap()),
         deref_trait_did: deref_trait_did,
+        deref_mut_trait_did: deref_mut_trait_did,
         typarams: external_typarams,
     };
 
@@ -2604,7 +2608,13 @@ impl<'a> AssocItemLink<'a> {
 
 enum AssocItemRender<'a> {
     All,
-    DerefFor { trait_: &'a clean::Type, type_: &'a clean::Type },
+    DerefFor { trait_: &'a clean::Type, type_: &'a clean::Type, deref_mut_: bool }
+}
+
+#[derive(Copy, Clone, PartialEq)]
+enum RenderMode {
+    Normal,
+    ForDeref { mut_: bool },
 }
 
 fn render_assoc_items(w: &mut fmt::Formatter,
@@ -2621,19 +2631,19 @@ fn render_assoc_items(w: &mut fmt::Formatter,
         i.inner_impl().trait_.is_none()
     });
     if !non_trait.is_empty() {
-        let render_header = match what {
+        let render_mode = match what {
             AssocItemRender::All => {
                 write!(w, "

Methods

")?; - true + RenderMode::Normal } - AssocItemRender::DerefFor { trait_, type_ } => { + AssocItemRender::DerefFor { trait_, type_, deref_mut_ } => { write!(w, "

Methods from \ {}<Target={}>

", trait_, type_)?; - false + RenderMode::ForDeref { mut_: deref_mut_ } } }; for i in &non_trait { - render_impl(w, cx, i, AssocItemLink::Anchor(None), render_header, + render_impl(w, cx, i, AssocItemLink::Anchor(None), render_mode, containing_item.stable_since())?; } } @@ -2645,21 +2655,25 @@ fn render_assoc_items(w: &mut fmt::Formatter, t.inner_impl().trait_.def_id() == c.deref_trait_did }); if let Some(impl_) = deref_impl { - render_deref_methods(w, cx, impl_, containing_item)?; + let has_deref_mut = traits.iter().find(|t| { + t.inner_impl().trait_.def_id() == c.deref_mut_trait_did + }).is_some(); + render_deref_methods(w, cx, impl_, containing_item, has_deref_mut)?; } write!(w, "

Trait \ Implementations

")?; for i in &traits { let did = i.trait_did().unwrap(); let assoc_link = AssocItemLink::GotoSource(did, &i.inner_impl().provided_trait_methods); - render_impl(w, cx, i, assoc_link, true, containing_item.stable_since())?; + render_impl(w, cx, i, assoc_link, + RenderMode::Normal, containing_item.stable_since())?; } } Ok(()) } fn render_deref_methods(w: &mut fmt::Formatter, cx: &Context, impl_: &Impl, - container_item: &clean::Item) -> fmt::Result { + container_item: &clean::Item, deref_mut: bool) -> fmt::Result { let deref_type = impl_.inner_impl().trait_.as_ref().unwrap(); let target = impl_.inner_impl().items.iter().filter_map(|item| { match item.inner { @@ -2667,7 +2681,8 @@ fn render_deref_methods(w: &mut fmt::Formatter, cx: &Context, impl_: &Impl, _ => None, } }).next().expect("Expected associated type binding"); - let what = AssocItemRender::DerefFor { trait_: deref_type, type_: target }; + let what = AssocItemRender::DerefFor { trait_: deref_type, type_: target, + deref_mut_: deref_mut }; if let Some(did) = target.def_id() { render_assoc_items(w, cx, container_item, did, what) } else { @@ -2681,12 +2696,9 @@ fn render_deref_methods(w: &mut fmt::Formatter, cx: &Context, impl_: &Impl, } } -// Render_header is false when we are rendering a `Deref` impl and true -// otherwise. If render_header is false, we will avoid rendering static -// methods, since they are not accessible for the type implementing `Deref` fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLink, - render_header: bool, outer_version: Option<&str>) -> fmt::Result { - if render_header { + render_mode: RenderMode, outer_version: Option<&str>) -> fmt::Result { + if render_mode == RenderMode::Normal { write!(w, "

{}", i.inner_impl())?; write!(w, "")?; let since = i.impl_item.stability.as_ref().map(|s| &s.since[..]); @@ -2707,22 +2719,43 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi } fn doc_impl_item(w: &mut fmt::Formatter, cx: &Context, item: &clean::Item, - link: AssocItemLink, render_static: bool, + link: AssocItemLink, render_mode: RenderMode, is_default_item: bool, outer_version: Option<&str>, trait_: Option<&clean::Trait>) -> fmt::Result { let item_type = item_type(item); let name = item.name.as_ref().unwrap(); - let is_static = match item.inner { - clean::MethodItem(ref method) => !method.decl.has_self(), - clean::TyMethodItem(ref method) => !method.decl.has_self(), - _ => false + let render_method_item: bool = match render_mode { + RenderMode::Normal => true, + RenderMode::ForDeref { mut_: deref_mut_ } => { + let self_type_opt = match item.inner { + clean::MethodItem(ref method) => method.decl.self_type(), + clean::TyMethodItem(ref method) => method.decl.self_type(), + _ => None + }; + + if let Some(self_ty) = self_type_opt { + let by_mut_ref = match self_ty { + SelfTy::SelfBorrowed(_lifetime, mutability) => { + mutability == Mutability::Mutable + }, + SelfTy::SelfExplicit(clean::BorrowedRef { mutability, .. }) => { + mutability == Mutability::Mutable + }, + _ => false, + }; + + deref_mut_ || !by_mut_ref + } else { + false + } + }, }; match item.inner { clean::MethodItem(..) | clean::TyMethodItem(..) => { // Only render when the method is not static or we allow static methods - if !is_static || render_static { + if render_method_item { let id = derive_id(format!("{}.{}", item_type, name)); let ns_id = derive_id(format!("{}.{}", name, item_type.name_space())); write!(w, "

", id, item_type)?; @@ -2770,7 +2803,7 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi _ => panic!("can't make docs for trait item with name {:?}", item.name) } - if !is_static || render_static { + if render_method_item || render_mode == RenderMode::Normal { if !is_default_item { if let Some(t) = trait_ { // The trait item may have been stripped so we might not @@ -2803,7 +2836,7 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi write!(w, "
")?; for trait_item in &i.inner_impl().items { - doc_impl_item(w, cx, trait_item, link, render_header, + doc_impl_item(w, cx, trait_item, link, render_mode, false, outer_version, trait_)?; } @@ -2811,7 +2844,7 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi cx: &Context, t: &clean::Trait, i: &clean::Impl, - render_static: bool, + render_mode: RenderMode, outer_version: Option<&str>) -> fmt::Result { for trait_item in &t.items { let n = trait_item.name.clone(); @@ -2821,7 +2854,7 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi let did = i.trait_.as_ref().unwrap().def_id().unwrap(); let assoc_link = AssocItemLink::GotoSource(did, &i.provided_trait_methods); - doc_impl_item(w, cx, trait_item, assoc_link, render_static, true, + doc_impl_item(w, cx, trait_item, assoc_link, render_mode, true, outer_version, None)?; } Ok(()) @@ -2830,7 +2863,7 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi // If we've implemented a trait, then also emit documentation for all // default items which weren't overridden in the implementation block. if let Some(t) = trait_ { - render_default_items(w, cx, t, &i.inner_impl(), render_header, outer_version)?; + render_default_items(w, cx, t, &i.inner_impl(), render_mode, outer_version)?; } write!(w, "
")?; Ok(()) diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index beed1dc9f9e7..73278ad9fac4 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -110,6 +110,7 @@ pub fn run(input: &str, external_traits: RefCell::new(FnvHashMap()), populated_crate_impls: RefCell::new(FnvHashSet()), deref_trait_did: Cell::new(None), + deref_mut_trait_did: Cell::new(None), access_levels: Default::default(), renderinfo: Default::default(), }; diff --git a/src/test/rustdoc/issue-35169-2.rs b/src/test/rustdoc/issue-35169-2.rs new file mode 100644 index 000000000000..d738fb292596 --- /dev/null +++ b/src/test/rustdoc/issue-35169-2.rs @@ -0,0 +1,45 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::ops::Deref; +use std::ops::DerefMut; + +pub struct Foo; +pub struct Bar; + +impl Foo { + pub fn by_ref(&self) {} + pub fn by_explicit_ref(self: &Foo) {} + pub fn by_mut_ref(&mut self) {} + pub fn by_explicit_mut_ref(self: &mut Foo) {} + pub fn static_foo() {} +} + +impl Deref for Bar { + type Target = Foo; + fn deref(&self) -> &Foo { loop {} } +} + +impl DerefMut for Bar { + fn deref_mut(&mut self) -> &mut Foo { loop {} } +} + +// @has issue_35169_2/Bar.t.html +// @has issue_35169_2/struct.Bar.html +// @has - '//*[@id="by_ref.v"]' 'fn by_ref(&self)' +// @has - '//*[@id="method.by_ref"]' 'fn by_ref(&self)' +// @has - '//*[@id="by_explicit_ref.v"]' 'fn by_explicit_ref(self: &Foo)' +// @has - '//*[@id="method.by_explicit_ref"]' 'fn by_explicit_ref(self: &Foo)' +// @has - '//*[@id="by_mut_ref.v"]' 'fn by_mut_ref(&mut self)' +// @has - '//*[@id="method.by_mut_ref"]' 'fn by_mut_ref(&mut self)' +// @has - '//*[@id="by_explicit_mut_ref.v"]' 'fn by_explicit_mut_ref(self: &mut Foo)' +// @has - '//*[@id="method.by_explicit_mut_ref"]' 'fn by_explicit_mut_ref(self: &mut Foo)' +// @!has - '//*[@id="static_foo.v"]' 'fn static_foo()' +// @!has - '//*[@id="method.static_foo"]' 'fn static_foo()' diff --git a/src/test/rustdoc/issue-35169.rs b/src/test/rustdoc/issue-35169.rs new file mode 100644 index 000000000000..8764e4a390f7 --- /dev/null +++ b/src/test/rustdoc/issue-35169.rs @@ -0,0 +1,40 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::ops::Deref; + +pub struct Foo; +pub struct Bar; + +impl Foo { + pub fn by_ref(&self) {} + pub fn by_explicit_ref(self: &Foo) {} + pub fn by_mut_ref(&mut self) {} + pub fn by_explicit_mut_ref(self: &mut Foo) {} + pub fn static_foo() {} +} + +impl Deref for Bar { + type Target = Foo; + fn deref(&self) -> &Foo { loop {} } +} + +// @has issue_35169/Bar.t.html +// @has issue_35169/struct.Bar.html +// @has - '//*[@id="by_ref.v"]' 'fn by_ref(&self)' +// @has - '//*[@id="method.by_ref"]' 'fn by_ref(&self)' +// @has - '//*[@id="by_explicit_ref.v"]' 'fn by_explicit_ref(self: &Foo)' +// @has - '//*[@id="method.by_explicit_ref"]' 'fn by_explicit_ref(self: &Foo)' +// @!has - '//*[@id="by_mut_ref.v"]' 'fn by_mut_ref(&mut self)' +// @!has - '//*[@id="method.by_mut_ref"]' 'fn by_mut_ref(&mut self)' +// @!has - '//*[@id="by_explicit_mut_ref.v"]' 'fn by_explicit_mut_ref(self: &mut Foo)' +// @!has - '//*[@id="method.by_explicit_mut_ref"]' 'fn by_explicit_mut_ref(self: &mut Foo)' +// @!has - '//*[@id="static_foo.v"]' 'fn static_foo()' +// @!has - '//*[@id="method.static_foo"]' 'fn static_foo()' From 92a1848d7725495676d8db1cadca50836787eccd Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Tue, 6 Sep 2016 12:44:26 +1200 Subject: [PATCH 206/443] save-analysis: some refinement to the value string for variables --- src/librustc_save_analysis/dump_visitor.rs | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index a695a0706620..df657cadcbe1 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -982,15 +982,23 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { self.visit_pat(&p); for &(id, ref p, immut, _) in &collector.collected_paths { - let mut value = if immut == ast::Mutability::Immutable { - value.to_string() - } else { - "".to_string() + let mut value = match immut { + ast::Mutability::Immutable => value.to_string(), + _ => String::new(), }; let types = self.tcx.node_types(); - let typ = types.get(&id).map(|t| t.to_string()).unwrap_or(String::new()); - value.push_str(": "); - value.push_str(&typ); + let typ = match types.get(&id) { + Some(typ) => { + let typ = typ.to_string(); + if !value.is_empty() { + value.push_str(": "); + } + value.push_str(&typ); + typ + } + None => String::new(), + }; + // Get the span only for the name of the variable (I hope the path // is only ever a variable name, but who knows?). let sub_span = self.span.span_for_last_ident(p.span); From 41ee2e9124245071dbc890b8617fd6c75391477f Mon Sep 17 00:00:00 2001 From: Andy Russell Date: Mon, 5 Sep 2016 21:48:02 -0400 Subject: [PATCH 207/443] resolve: Suggest `use self` when import resolves Improves errors messages by replacing "Maybe a missing `extern crate`" messages with "Did you mean `self::...`" when the `self` import would succeed. --- src/librustc_resolve/resolve_imports.rs | 16 +++++++++++++++- src/test/compile-fail/unresolved-import.rs | 9 +++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 875d6745f6b2..622d705485ef 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -587,7 +587,21 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { let module = match module_result { Success(module) => module, Indeterminate => return Indeterminate, - Failed(err) => return Failed(err), + Failed(err) => { + let self_module = self.current_module.clone(); + + let resolve_from_self_result = self.resolve_module_path_from_root( + &self_module, &module_path, 0, Some(span)); + + return match resolve_from_self_result { + Success(_) => { + let msg = format!("Did you mean `self::{}`?", + &names_to_string(module_path)); + Failed(Some((span, msg))) + }, + _ => Failed(err), + }; + }, }; let (name, value_result, type_result) = match directive.subclass { diff --git a/src/test/compile-fail/unresolved-import.rs b/src/test/compile-fail/unresolved-import.rs index d1254f3f5241..6421599cacb2 100644 --- a/src/test/compile-fail/unresolved-import.rs +++ b/src/test/compile-fail/unresolved-import.rs @@ -35,3 +35,12 @@ mod food { } } } + +mod m { + enum MyEnum { + MyVariant + } + + use MyEnum::*; //~ ERROR unresolved import `MyEnum::*` [E0432] + //~^ Did you mean `self::MyEnum`? +} From 288e7caf19b415007787f47424c9e00913cb7803 Mon Sep 17 00:00:00 2001 From: Andy Russell Date: Mon, 5 Sep 2016 23:08:21 -0400 Subject: [PATCH 208/443] show `self` suggestion when items are in the block --- src/librustc_resolve/resolve_imports.rs | 14 ++++++-------- src/test/compile-fail/unresolved-import.rs | 11 +++++++++++ 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 622d705485ef..90c17866583a 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -588,18 +588,16 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> { Success(module) => module, Indeterminate => return Indeterminate, Failed(err) => { - let self_module = self.current_module.clone(); + let self_module = self.module_map[&self.current_module.normal_ancestor_id.unwrap()]; let resolve_from_self_result = self.resolve_module_path_from_root( &self_module, &module_path, 0, Some(span)); - return match resolve_from_self_result { - Success(_) => { - let msg = format!("Did you mean `self::{}`?", - &names_to_string(module_path)); - Failed(Some((span, msg))) - }, - _ => Failed(err), + return if let Success(_) = resolve_from_self_result { + let msg = format!("Did you mean `self::{}`?", &names_to_string(module_path)); + Failed(Some((span, msg))) + } else { + Failed(err) }; }, }; diff --git a/src/test/compile-fail/unresolved-import.rs b/src/test/compile-fail/unresolved-import.rs index 6421599cacb2..0a9a43756973 100644 --- a/src/test/compile-fail/unresolved-import.rs +++ b/src/test/compile-fail/unresolved-import.rs @@ -44,3 +44,14 @@ mod m { use MyEnum::*; //~ ERROR unresolved import `MyEnum::*` [E0432] //~^ Did you mean `self::MyEnum`? } + +mod items { + enum Enum { + Variant + } + + use Enum::*; //~ ERROR unresolved import `Enum::*` [E0432] + //~^ Did you mean `self::Enum`? + + fn item() {} +} From 32674b3f1ae0408ca7cb0369eca2efd2f893e908 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Mon, 5 Sep 2016 04:55:12 +0000 Subject: [PATCH 209/443] Avoid false positive unused import warnings. --- src/librustc_resolve/lib.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 0420fa802688..cefa37c9fc3b 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1276,16 +1276,17 @@ impl<'a> Resolver<'a> { self.used_crates.insert(krate); } - if let NameBindingKind::Import { directive, .. } = binding.kind { - self.used_imports.insert((directive.id, ns)); - self.add_to_glob_map(directive.id, name); - } - if binding.ambiguity().is_some() { self.ambiguity_errors.push((span, name, binding)); return true; } + if let NameBindingKind::Import { directive, binding } = binding.kind { + self.used_imports.insert((directive.id, ns)); + self.add_to_glob_map(directive.id, name); + self.record_use(name, ns, binding, span); + } + false } From 07f8cb28dc713b8754ed8b51fd9eb07a2f6325ba Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Mon, 5 Sep 2016 05:10:50 +0000 Subject: [PATCH 210/443] Add regression test. --- src/test/compile-fail/imports/unused.rs | 38 +++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 src/test/compile-fail/imports/unused.rs diff --git a/src/test/compile-fail/imports/unused.rs b/src/test/compile-fail/imports/unused.rs new file mode 100644 index 000000000000..4ec9987df420 --- /dev/null +++ b/src/test/compile-fail/imports/unused.rs @@ -0,0 +1,38 @@ +// 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. + +#![feature(pub_restricted, item_like_imports)] +#![deny(unused)] + +mod foo { + fn f() {} + + mod m1 { + pub(super) use super::f; //~ ERROR unused + } + + mod m2 { + #[allow(unused)] + use super::m1::*; // (despite this glob import) + } + + mod m3 { + pub(super) use super::f; // Check that this is counted as used (c.f. #36249). + } + + pub mod m4 { + use super::m3::*; + pub fn g() { f(); } + } +} + +fn main() { + foo::m4::g(); +} From 888a968139986847623bc40b5a7dc308cf44f988 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Mon, 5 Sep 2016 05:27:58 +0000 Subject: [PATCH 211/443] Add field `used: Cell` to variant `NameBindingKind::Import`. --- src/librustc_resolve/lib.rs | 38 +++++++++++-------------- src/librustc_resolve/resolve_imports.rs | 1 + 2 files changed, 17 insertions(+), 22 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index cefa37c9fc3b..f3044e1847d1 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -871,6 +871,7 @@ enum NameBindingKind<'a> { Import { binding: &'a NameBinding<'a>, directive: &'a ImportDirective<'a>, + used: Cell, }, Ambiguity { b1: &'a NameBinding<'a>, @@ -938,14 +939,6 @@ impl<'a> NameBinding<'a> { _ => true, } } - - fn ambiguity(&self) -> Option<(&'a NameBinding<'a>, &'a NameBinding<'a>)> { - match self.kind { - NameBindingKind::Ambiguity { b1, b2 } => Some((b1, b2)), - NameBindingKind::Import { binding, .. } => binding.ambiguity(), - _ => None, - } - } } /// Interns the names of the primitive types. @@ -1064,7 +1057,7 @@ pub struct Resolver<'a> { pub maybe_unused_trait_imports: NodeSet, privacy_errors: Vec>, - ambiguity_errors: Vec<(Span, Name, &'a NameBinding<'a>)>, + ambiguity_errors: Vec<(Span, Name, &'a NameBinding<'a>, &'a NameBinding<'a>)>, arenas: &'a ResolverArenas<'a>, dummy_binding: &'a NameBinding<'a>, @@ -1276,18 +1269,20 @@ impl<'a> Resolver<'a> { self.used_crates.insert(krate); } - if binding.ambiguity().is_some() { - self.ambiguity_errors.push((span, name, binding)); - return true; + match binding.kind { + NameBindingKind::Import { directive, binding, ref used } if !used.get() => { + used.set(true); + self.used_imports.insert((directive.id, ns)); + self.add_to_glob_map(directive.id, name); + self.record_use(name, ns, binding, span) + } + NameBindingKind::Import { .. } => false, + NameBindingKind::Ambiguity { b1, b2 } => { + self.ambiguity_errors.push((span, name, b1, b2)); + true + } + _ => false } - - if let NameBindingKind::Import { directive, binding } = binding.kind { - self.used_imports.insert((directive.id, ns)); - self.add_to_glob_map(directive.id, name); - self.record_use(name, ns, binding, span); - } - - false } fn add_to_glob_map(&mut self, id: NodeId, name: Name) { @@ -3307,9 +3302,8 @@ impl<'a> Resolver<'a> { fn report_errors(&self) { let mut reported_spans = FnvHashSet(); - for &(span, name, binding) in &self.ambiguity_errors { + for &(span, name, b1, b2) in &self.ambiguity_errors { if !reported_spans.insert(span) { continue } - let (b1, b2) = binding.ambiguity().unwrap(); let msg1 = format!("`{}` could resolve to the name imported here", name); let msg2 = format!("`{}` could also resolve to the name imported here", name); self.session.struct_span_err(span, &format!("`{}` is ambiguous", name)) diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 875d6745f6b2..85c03683c8dc 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -308,6 +308,7 @@ impl<'a> Resolver<'a> { kind: NameBindingKind::Import { binding: binding, directive: directive, + used: Cell::new(false), }, span: directive.span, vis: vis, From ff3a6449512e9e6fd1ea455c64cd02a7fa4cc7e2 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Tue, 6 Sep 2016 03:47:11 +0000 Subject: [PATCH 212/443] Add struct `AmbiguityError`. --- src/librustc_resolve/lib.rs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index f3044e1847d1..c5b505fba38e 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -879,9 +879,15 @@ enum NameBindingKind<'a> { } } -#[derive(Clone, Debug)] struct PrivacyError<'a>(Span, Name, &'a NameBinding<'a>); +struct AmbiguityError<'a> { + span: Span, + name: Name, + b1: &'a NameBinding<'a>, + b2: &'a NameBinding<'a>, +} + impl<'a> NameBinding<'a> { fn module(&self) -> Result, bool /* true if an error has already been reported */> { match self.kind { @@ -1057,7 +1063,7 @@ pub struct Resolver<'a> { pub maybe_unused_trait_imports: NodeSet, privacy_errors: Vec>, - ambiguity_errors: Vec<(Span, Name, &'a NameBinding<'a>, &'a NameBinding<'a>)>, + ambiguity_errors: Vec>, arenas: &'a ResolverArenas<'a>, dummy_binding: &'a NameBinding<'a>, @@ -1278,7 +1284,8 @@ impl<'a> Resolver<'a> { } NameBindingKind::Import { .. } => false, NameBindingKind::Ambiguity { b1, b2 } => { - self.ambiguity_errors.push((span, name, b1, b2)); + let ambiguity_error = AmbiguityError { span: span, name: name, b1: b1, b2: b2 }; + self.ambiguity_errors.push(ambiguity_error); true } _ => false @@ -3302,7 +3309,7 @@ impl<'a> Resolver<'a> { fn report_errors(&self) { let mut reported_spans = FnvHashSet(); - for &(span, name, b1, b2) in &self.ambiguity_errors { + for &AmbiguityError { span, name, b1, b2 } in &self.ambiguity_errors { if !reported_spans.insert(span) { continue } let msg1 = format!("`{}` could resolve to the name imported here", name); let msg2 = format!("`{}` could also resolve to the name imported here", name); From 8df4a768a7e98a594bd7a2d70a7bdcec14bc0518 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 6 Sep 2016 01:04:41 -0500 Subject: [PATCH 213/443] rustbuild: per target musl-root config.toml now accepts a target.$TARGET.musl-root key that lets you override the "build" musl-root value, which is set via the --musl-root flag or via the build.musl-root key. With this change, it's now possible to compile std for several musl targets at once. Here's are the sample commands to do such thing: ``` $ configure \ --enable-rustbuild \ --target=x86_64-unknown-linux-musl,arm-unknown-linux-musleabi \ --musl-root=/musl/x86_64-unknown-linux-musl/ $ edit config.toml && tail config.toml [target.arm-unknown-linux-musleabi] musl-root = "/x-tools/arm-unknown-linux-musleabi/arm-unknown-linux-musleabi/sysroot/usr" $ make ``` --- src/bootstrap/compile.rs | 5 +++-- src/bootstrap/config.rs | 2 ++ src/bootstrap/sanity.rs | 10 ++++++---- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 302ac68460c6..e14317b23b4d 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -59,8 +59,9 @@ pub fn std<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) { cargo.env("JEMALLOC_OVERRIDE", jemalloc); } } - if let Some(ref p) = build.config.musl_root { - if target.contains("musl") { + if target.contains("musl") { + if let Some(p) = build.config.target_config[target].musl_root.as_ref() + .or(build.config.musl_root.as_ref()) { cargo.env("MUSL_ROOT", p); } } diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 682a6f74126a..4a158b42187f 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -76,6 +76,7 @@ pub struct Config { // misc pub channel: String, + // Fallback musl-root for all targets pub musl_root: Option, pub prefix: Option, pub codegen_tests: bool, @@ -89,6 +90,7 @@ pub struct Target { pub cc: Option, pub cxx: Option, pub ndk: Option, + pub musl_root: Option, } /// Structure of the `config.toml` file that configuration is read from. diff --git a/src/bootstrap/sanity.rs b/src/bootstrap/sanity.rs index c0d303c0ea9a..f1d7f869a965 100644 --- a/src/bootstrap/sanity.rs +++ b/src/bootstrap/sanity.rs @@ -111,8 +111,9 @@ pub fn check(build: &mut Build) { // Make sure musl-root is valid if specified if target.contains("musl") && !target.contains("mips") { - match build.config.musl_root { - Some(ref root) => { + match build.config.target_config[target].musl_root.as_ref() + .or(build.config.musl_root.as_ref()) { + Some(root) => { if fs::metadata(root.join("lib/libc.a")).is_err() { panic!("couldn't find libc.a in musl dir: {}", root.join("lib").display()); @@ -123,8 +124,9 @@ pub fn check(build: &mut Build) { } } None => { - panic!("when targeting MUSL the build.musl-root option \ - must be specified in config.toml") + panic!("when targeting MUSL either the build.musl-root \ + option or the target.$TARGET.musl-root one must \ + be specified in config.toml") } } } From 0520698be30eeabd72e66d4b8fa540f727820c33 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Mon, 8 Aug 2016 01:04:51 +0300 Subject: [PATCH 214/443] Count and report time taken by MIR passes --- src/librustc/mir/transform.rs | 17 +++++++++-------- src/librustc_mir/transform/dump_mir.rs | 4 ++-- src/librustc_mir/transform/simplify_branches.rs | 2 +- src/librustc_mir/transform/simplify_cfg.rs | 2 +- 4 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/librustc/mir/transform.rs b/src/librustc/mir/transform.rs index 57601e675043..8cd5f5844d21 100644 --- a/src/librustc/mir/transform.rs +++ b/src/librustc/mir/transform.rs @@ -15,7 +15,9 @@ use mir::mir_map::MirMap; use mir::repr::{Mir, Promoted}; use ty::TyCtxt; use syntax::ast::NodeId; +use util::common::time; +use std::borrow::Cow; use std::fmt; /// Where a specific Mir comes from. @@ -72,12 +74,12 @@ impl<'a, 'tcx> MirSource { /// Various information about pass. pub trait Pass { // fn should_run(Session) to check if pass should run? - fn name(&self) -> &str { + fn name<'a>(&self) -> Cow<'static, str> { let name = unsafe { ::std::intrinsics::type_name::() }; if let Some(tail) = name.rfind(":") { - &name[tail+1..] + Cow::from(&name[tail+1..]) } else { - name + Cow::from(name) } } fn disambiguator<'a>(&'a self) -> Option> { None } @@ -162,11 +164,10 @@ impl<'a, 'tcx> Passes { } pub fn run_passes(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>, map: &mut MirMap<'tcx>) { - for pass in &mut self.plugin_passes { - pass.run_pass(tcx, map, &mut self.pass_hooks); - } - for pass in &mut self.passes { - pass.run_pass(tcx, map, &mut self.pass_hooks); + let Passes { ref mut passes, ref mut plugin_passes, ref mut pass_hooks } = *self; + for pass in plugin_passes.iter_mut().chain(passes.iter_mut()) { + time(tcx.sess.time_passes(), &*pass.name(), + || pass.run_pass(tcx, map, pass_hooks)); } } diff --git a/src/librustc_mir/transform/dump_mir.rs b/src/librustc_mir/transform/dump_mir.rs index 642adeee5cd6..694b017bbd70 100644 --- a/src/librustc_mir/transform/dump_mir.rs +++ b/src/librustc_mir/transform/dump_mir.rs @@ -26,7 +26,7 @@ impl<'b, 'tcx> MirPass<'tcx> for Marker<'b> { } impl<'b> Pass for Marker<'b> { - fn name(&self) -> &str { self.0 } + fn name(&self) -> ::std::borrow::Cow<'static, str> { String::from(self.0).into() } } pub struct Disambiguator<'a> { @@ -58,7 +58,7 @@ impl<'tcx> MirPassHook<'tcx> for DumpMir { { pretty::dump_mir( tcx, - pass.name(), + &*pass.name(), &Disambiguator { pass: pass, is_after: is_after diff --git a/src/librustc_mir/transform/simplify_branches.rs b/src/librustc_mir/transform/simplify_branches.rs index b4960c677a16..407e21616102 100644 --- a/src/librustc_mir/transform/simplify_branches.rs +++ b/src/librustc_mir/transform/simplify_branches.rs @@ -62,5 +62,5 @@ impl<'l> Pass for SimplifyBranches<'l> { } // avoid calling `type_name` - it contains `<'static>` - fn name(&self) -> &str { "SimplifyBranches" } + fn name(&self) -> ::std::borrow::Cow<'static, str> { "SimplifyBranches".into() } } diff --git a/src/librustc_mir/transform/simplify_cfg.rs b/src/librustc_mir/transform/simplify_cfg.rs index c0e7e54050ad..8e1b7b44976f 100644 --- a/src/librustc_mir/transform/simplify_cfg.rs +++ b/src/librustc_mir/transform/simplify_cfg.rs @@ -64,7 +64,7 @@ impl<'l> Pass for SimplifyCfg<'l> { } // avoid calling `type_name` - it contains `<'static>` - fn name(&self) -> &str { "SimplifyCfg" } + fn name(&self) -> ::std::borrow::Cow<'static, str> { "SimplifyCfg".into() } } pub struct CfgSimplifier<'a, 'tcx: 'a> { From dc0e9c0b1222dc9ee0be8040635605e0c21fdbcd Mon Sep 17 00:00:00 2001 From: ggomez Date: Tue, 6 Sep 2016 16:31:18 +0200 Subject: [PATCH 215/443] Add missing urls --- src/libstd/collections/hash/map.rs | 60 +++++++++++++++++++++--------- 1 file changed, 42 insertions(+), 18 deletions(-) diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 14da36ca4834..4eb2c8f06441 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -206,7 +206,7 @@ fn test_resize_policy() { /// require this behavior you can create your own hashing function using /// [BuildHasherDefault](../hash/struct.BuildHasherDefault.html). /// -/// It is required that the keys implement the `Eq` and `Hash` traits, although +/// It is required that the keys implement the [`Eq`] and [`Hash`] traits, although /// this can frequently be achieved by using `#[derive(PartialEq, Eq, Hash)]`. /// If you implement these yourself, it is important that the following /// property holds: @@ -218,9 +218,9 @@ fn test_resize_policy() { /// In other words, if two keys are equal, their hashes must be equal. /// /// It is a logic error for a key to be modified in such a way that the key's -/// hash, as determined by the `Hash` trait, or its equality, as determined by -/// the `Eq` trait, changes while it is in the map. This is normally only -/// possible through `Cell`, `RefCell`, global state, I/O, or unsafe code. +/// hash, as determined by the [`Hash`] trait, or its equality, as determined by +/// the [`Eq`] trait, changes while it is in the map. This is normally only +/// possible through [`Cell`], [`RefCell`], global state, I/O, or unsafe code. /// /// Relevant papers/articles: /// @@ -298,8 +298,14 @@ fn test_resize_policy() { /// *stat += random_stat_buff(); /// ``` /// -/// The easiest way to use `HashMap` with a custom type as key is to derive `Eq` and `Hash`. -/// We must also derive `PartialEq`. +/// The easiest way to use `HashMap` with a custom type as key is to derive [`Eq`] and [`Hash`]. +/// We must also derive [`PartialEq`]. +/// +/// [`Eq`]: ../../std/cmp/trait.Eq.html +/// [`Hash`]: ../../std/hash/trait.Hash.html +/// [`PartialEq`]: ../../std/cmp/trait.PartialEq.html +/// [`RefCell`]: ../../std/cell/struct.RefCell.html +/// [`Cell`]: ../../std/cell/struct.Cell.html /// /// ``` /// use std::collections::HashMap; @@ -525,7 +531,7 @@ impl HashMap } impl HashMap { - /// Creates an empty HashMap. + /// Creates an empty `HashMap`. /// /// # Examples /// @@ -539,7 +545,7 @@ impl HashMap { Default::default() } - /// Creates an empty hash map with the given initial capacity. + /// Creates an empty `HashMap` with the given initial capacity. /// /// # Examples /// @@ -557,7 +563,7 @@ impl HashMap { impl HashMap where K: Eq + Hash, S: BuildHasher { - /// Creates an empty hashmap which will use the given hash builder to hash + /// Creates an empty `HashMap` which will use the given hash builder to hash /// keys. /// /// The created map has the default initial capacity. @@ -587,7 +593,7 @@ impl HashMap } } - /// Creates an empty HashMap with space for at least `capacity` + /// Creates an empty `HashMap` with space for at least `capacity` /// elements, using `hasher` to hash the keys. /// /// Warning: `hasher` is normally randomly generated, and @@ -677,7 +683,7 @@ impl HashMap /// Resizes the internal vectors to a new capacity. It's your responsibility to: /// 1) Make sure the new capacity is enough for all the elements, accounting /// for the load factor. - /// 2) Ensure new_capacity is a power of two or zero. + /// 2) Ensure `new_capacity` is a power of two or zero. fn resize(&mut self, new_capacity: usize) { assert!(self.table.size() <= new_capacity); assert!(new_capacity.is_power_of_two() || new_capacity == 0); @@ -1040,9 +1046,12 @@ impl HashMap /// Returns a reference to the value corresponding to the key. /// /// The key may be any borrowed form of the map's key type, but - /// `Hash` and `Eq` on the borrowed form *must* match those for + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for /// the key type. /// + /// [`Eq`]: ../../std/cmp/trait.Eq.html + /// [`Hash`]: ../../std/hash/trait.Hash.html + /// /// # Examples /// /// ``` @@ -1063,9 +1072,12 @@ impl HashMap /// Returns true if the map contains a value for the specified key. /// /// The key may be any borrowed form of the map's key type, but - /// `Hash` and `Eq` on the borrowed form *must* match those for + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for /// the key type. /// + /// [`Eq`]: ../../std/cmp/trait.Eq.html + /// [`Hash`]: ../../std/hash/trait.Hash.html + /// /// # Examples /// /// ``` @@ -1086,9 +1098,12 @@ impl HashMap /// Returns a mutable reference to the value corresponding to the key. /// /// The key may be any borrowed form of the map's key type, but - /// `Hash` and `Eq` on the borrowed form *must* match those for + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for /// the key type. /// + /// [`Eq`]: ../../std/cmp/trait.Eq.html + /// [`Hash`]: ../../std/hash/trait.Hash.html + /// /// # Examples /// /// ``` @@ -1143,9 +1158,12 @@ impl HashMap /// was previously in the map. /// /// The key may be any borrowed form of the map's key type, but - /// `Hash` and `Eq` on the borrowed form *must* match those for + /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for /// the key type. /// + /// [`Eq`]: ../../std/cmp/trait.Eq.html + /// [`Hash`]: ../../std/hash/trait.Hash.html + /// /// # Examples /// /// ``` @@ -1904,12 +1922,15 @@ impl<'a, K, V, S> Extend<(&'a K, &'a V)> for HashMap } } -/// `RandomState` is the default state for `HashMap` types. +/// `RandomState` is the default state for [`HashMap`] types. /// /// A particular instance `RandomState` will create the same instances of -/// `Hasher`, but the hashers created by two different `RandomState` +/// [`Hasher`], but the hashers created by two different `RandomState` /// instances are unlikely to produce the same result for the same values. /// +/// [`HashMap`]: struct.HashMap.html +/// [`Hasher`]: ../../hash/trait.Hasher.html +/// /// # Examples /// /// ``` @@ -1980,10 +2001,13 @@ impl BuildHasher for RandomState { } } -/// The default `Hasher` used by `RandomState`. +/// The default [`Hasher`] used by [`RandomState`]. /// /// The internal algorithm is not specified, and so it and its hashes should /// not be relied upon over releases. +/// +/// [`RandomState`]: struct.RandomState.html +/// [`Hasher`]: ../../hash/trait.Hasher.html #[unstable(feature = "hashmap_default_hasher", issue = "0")] pub struct DefaultHasher(SipHasher13); From 79644ac3c4fe1b27dc64e0b172d3fca80a88335c Mon Sep 17 00:00:00 2001 From: Jake Goldsborough Date: Tue, 6 Sep 2016 07:41:20 -0700 Subject: [PATCH 216/443] adding a check to sanity to look for the nodejs command --- src/bootstrap/sanity.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/bootstrap/sanity.rs b/src/bootstrap/sanity.rs index c0d303c0ea9a..ae7f2e018f9f 100644 --- a/src/bootstrap/sanity.rs +++ b/src/bootstrap/sanity.rs @@ -75,6 +75,12 @@ pub fn check(build: &mut Build) { need_cmd("python".as_ref()); + // If a manual nodejs was added to the config, + // of if a nodejs install is detected through bootstrap.py, use it. + if build.config.nodejs.is_some() { + need_cmd("nodejs".as_ref()) + } + // We're gonna build some custom C code here and there, host triples // also build some C++ shims for LLVM so we need a C++ compiler. for target in build.config.target.iter() { From 5415b34ca6077b45a241c51ef2a227993a644d26 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 24 Aug 2016 06:49:44 -0400 Subject: [PATCH 217/443] write to inherent_impls during the visitor The goal here is to avoid writing to the `inherent_impls` map from within the general `Coherence` task, and instead write to it as we visit. Writing to it from the Coherence task is actually an information leak; it happened to be safe because Coherence read from `DepNode::Krate`, but that was very coarse. I removed the `Rc` here because, upon manual inspection, nobody clones the data in this table, and it meant that we can accumulate the data in place. That said, the pattern that is used for the inherent impls map is *generally* an anti-pattern (that is, holding the borrow lock for the duration of using the contents), so it'd probably be better to clone (and I doubt that would be expensive -- how many inherent impls does a typical type have?). --- src/librustc/dep_graph/dep_tracking_map.rs | 11 +++++++ src/librustc/ty/maps.rs | 2 +- src/librustc/ty/mod.rs | 2 +- src/librustc_typeck/coherence/mod.rs | 24 ++------------- src/test/incremental/krate-inherent.rs | 34 ++++++++++++++++++++++ 5 files changed, 49 insertions(+), 24 deletions(-) create mode 100644 src/test/incremental/krate-inherent.rs diff --git a/src/librustc/dep_graph/dep_tracking_map.rs b/src/librustc/dep_graph/dep_tracking_map.rs index 88cd1efd3459..51f7890c7a2f 100644 --- a/src/librustc/dep_graph/dep_tracking_map.rs +++ b/src/librustc/dep_graph/dep_tracking_map.rs @@ -80,6 +80,17 @@ impl DepTrackingMap { pub fn keys(&self) -> Vec { self.map.keys().cloned().collect() } + + /// Append `elem` to the vector stored for `k`, creating a new vector if needed. + /// This is considered a write to `k`. + pub fn push(&mut self, k: M::Key, elem: E) + where M: DepTrackingMapConfig> + { + self.write(&k); + self.map.entry(k) + .or_insert(Vec::new()) + .push(elem); + } } impl MemoizationMap for RefCell> { diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index 0e8bea86178f..5772d16c6d43 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -39,7 +39,7 @@ dep_map_ty! { ImplTraitRefs: ItemSignature(DefId) -> Option> dep_map_ty! { TraitDefs: ItemSignature(DefId) -> &'tcx ty::TraitDef<'tcx> } dep_map_ty! { AdtDefs: ItemSignature(DefId) -> ty::AdtDefMaster<'tcx> } dep_map_ty! { ItemVariances: ItemSignature(DefId) -> Rc> } -dep_map_ty! { InherentImpls: InherentImpls(DefId) -> Rc> } +dep_map_ty! { InherentImpls: InherentImpls(DefId) -> Vec } dep_map_ty! { ImplItems: ImplItems(DefId) -> Vec } dep_map_ty! { TraitItems: TraitItems(DefId) -> Rc>> } dep_map_ty! { ReprHints: ReprHints(DefId) -> Rc> } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index dfe24d5627bf..78358ce534d9 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2665,7 +2665,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.impl_items.borrow_mut().insert(impl_def_id, impl_items); } - self.inherent_impls.borrow_mut().insert(type_id, Rc::new(inherent_impls)); + self.inherent_impls.borrow_mut().insert(type_id, inherent_impls); self.populated_external_types.borrow_mut().insert(type_id); } diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index d2b7f07b9ce6..57d3c46af930 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -32,10 +32,7 @@ use rustc::ty::util::CopyImplementationError; use middle::free_region::FreeRegionMap; use CrateCtxt; use rustc::infer::{self, InferCtxt, TypeOrigin}; -use std::cell::RefCell; -use std::rc::Rc; use syntax_pos::Span; -use util::nodemap::{DefIdMap, FnvHashMap}; use rustc::dep_graph::DepNode; use rustc::hir::map as hir_map; use rustc::hir::intravisit; @@ -49,7 +46,6 @@ mod unsafety; struct CoherenceChecker<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { crate_context: &'a CrateCtxt<'a, 'gcx>, inference_context: InferCtxt<'a, 'gcx, 'tcx>, - inherent_impls: RefCell>>>>, } struct CoherenceCheckVisitor<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { @@ -109,15 +105,6 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { DepNode::CoherenceCheckImpl, &mut CoherenceCheckVisitor { cc: self }); - // Copy over the inherent impls we gathered up during the walk into - // the tcx. - let mut tcx_inherent_impls = - self.crate_context.tcx.inherent_impls.borrow_mut(); - for (k, v) in self.inherent_impls.borrow().iter() { - tcx_inherent_impls.insert((*k).clone(), - Rc::new((*v.borrow()).clone())); - } - // Populate the table of destructors. It might seem a bit strange to // do this here, but it's actually the most convenient place, since // the coherence tables contain the trait -> type mappings. @@ -175,14 +162,8 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { } fn add_inherent_impl(&self, base_def_id: DefId, impl_def_id: DefId) { - if let Some(implementation_list) = self.inherent_impls.borrow().get(&base_def_id) { - implementation_list.borrow_mut().push(impl_def_id); - return; - } - - self.inherent_impls.borrow_mut().insert( - base_def_id, - Rc::new(RefCell::new(vec!(impl_def_id)))); + let tcx = self.crate_context.tcx; + tcx.inherent_impls.borrow_mut().push(base_def_id, impl_def_id); } fn add_trait_impl(&self, impl_trait_ref: ty::TraitRef<'gcx>, impl_def_id: DefId) { @@ -556,7 +537,6 @@ pub fn check_coherence(ccx: &CrateCtxt) { CoherenceChecker { crate_context: ccx, inference_context: infcx, - inherent_impls: RefCell::new(FnvHashMap()), }.check(); }); unsafety::check(ccx.tcx); diff --git a/src/test/incremental/krate-inherent.rs b/src/test/incremental/krate-inherent.rs new file mode 100644 index 000000000000..ac6cc3e9826f --- /dev/null +++ b/src/test/incremental/krate-inherent.rs @@ -0,0 +1,34 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// revisions: rpass1 rpass2 +// compile-flags: -Z query-dep-graph + +#![allow(warnings)] +#![feature(rustc_attrs)] +#![rustc_partition_reused(module="krate_inherent-x", cfg="rpass2")] + +fn main() { } + +mod x { + struct Foo; + impl Foo { + fn foo(&self) { } + } + + fn method() { + let x: Foo = Foo; + x.foo(); // inherent methods used to add an edge from Krate + } +} + +#[cfg(rpass1)] +fn bar() { } // remove this unrelated fn in rpass2, which should not affect `x::method` + From c6363b801316c1d8279f55a6be44746d71018ceb Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 24 Aug 2016 07:35:49 -0400 Subject: [PATCH 218/443] ignore dep-graph when loading inlined HIR We touch the krate to adjust the maps, but we don't expose that data widely. --- src/librustc/hir/map/mod.rs | 2 ++ src/test/incremental/krate-inlined.rs | 29 +++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 src/test/incremental/krate-inlined.rs diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index 3ffc95e64f5a..5c302d927a71 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -927,6 +927,8 @@ pub fn map_decoded_item<'ast, F: FoldOps>(map: &Map<'ast>, ii: InlinedItem, fold_ops: F) -> &'ast InlinedItem { + let _ignore = map.forest.dep_graph.in_ignore(); + let mut fld = IdAndSpanUpdater::new(fold_ops); let ii = match ii { II::Item(d, i) => II::Item(fld.fold_ops.new_def_id(d), diff --git a/src/test/incremental/krate-inlined.rs b/src/test/incremental/krate-inlined.rs new file mode 100644 index 000000000000..368065898479 --- /dev/null +++ b/src/test/incremental/krate-inlined.rs @@ -0,0 +1,29 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// revisions: rpass1 rpass2 +// compile-flags: -Z query-dep-graph + +#![allow(warnings)] +#![feature(rustc_attrs)] +#![rustc_partition_reused(module="krate_inlined-x", cfg="rpass2")] + +fn main() { } + +mod x { + fn method() { + // use some methods that require inlining HIR from another crate: + let mut v = vec![]; + v.push(1); + } +} + +#[cfg(rpass1)] +fn bar() { } // remove this unrelated fn in rpass2, which should not affect `x::method` From 753590f0c52c0ca54e7b80c1cc90f72bb8bbc8fb Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 24 Aug 2016 07:36:54 -0400 Subject: [PATCH 219/443] add a debugging mechanism to forbid edges It is useful to track down an errant edge that is being added. This is not a perfect mechanism, since it doesn't consider (e.g.) if we are in an ignored task, but it's helpful enough for now. --- src/librustc/dep_graph/graph.rs | 18 +++++++++++++++++- src/librustc/dep_graph/raii.rs | 18 ++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/src/librustc/dep_graph/graph.rs b/src/librustc/dep_graph/graph.rs index bb027b11b45a..ca441c4bc3ff 100644 --- a/src/librustc/dep_graph/graph.rs +++ b/src/librustc/dep_graph/graph.rs @@ -38,6 +38,10 @@ struct DepGraphData { /// Work-products that we generate in this run. work_products: RefCell, WorkProduct>>, + + /// Tracks nodes that are forbidden to read/write; see + /// `DepGraph::forbid`. Used for debugging only. + forbidden: RefCell>>, } impl DepGraph { @@ -46,7 +50,8 @@ impl DepGraph { data: Rc::new(DepGraphData { thread: DepGraphThreadData::new(enabled), previous_work_products: RefCell::new(FnvHashMap()), - work_products: RefCell::new(FnvHashMap()) + work_products: RefCell::new(FnvHashMap()), + forbidden: RefCell::new(Vec::new()), }) } } @@ -70,6 +75,15 @@ impl DepGraph { raii::DepTask::new(&self.data.thread, key) } + /// Debugging aid -- forbid reads/writes to `key` while the return + /// value is in scope. Note that this is only available when debug + /// assertions are enabled -- you should not check in code that + /// invokes this function. + #[cfg(debug_assertions)] + pub fn forbid<'graph>(&'graph self, key: DepNode) -> raii::Forbid<'graph> { + raii::Forbid::new(&self.data.forbidden, key) + } + pub fn with_ignore(&self, op: OP) -> R where OP: FnOnce() -> R { @@ -85,10 +99,12 @@ impl DepGraph { } pub fn read(&self, v: DepNode) { + debug_assert!(!self.data.forbidden.borrow().contains(&v)); self.data.thread.enqueue(DepMessage::Read(v)); } pub fn write(&self, v: DepNode) { + debug_assert!(!self.data.forbidden.borrow().contains(&v)); self.data.thread.enqueue(DepMessage::Write(v)); } diff --git a/src/librustc/dep_graph/raii.rs b/src/librustc/dep_graph/raii.rs index c43d493d1767..b344eb486240 100644 --- a/src/librustc/dep_graph/raii.rs +++ b/src/librustc/dep_graph/raii.rs @@ -9,6 +9,7 @@ // except according to those terms. use hir::def_id::DefId; +use std::cell::RefCell; use super::DepNode; use super::thread::{DepGraphThreadData, DepMessage}; @@ -47,3 +48,20 @@ impl<'graph> Drop for IgnoreTask<'graph> { self.data.enqueue(DepMessage::PopIgnore); } } + +pub struct Forbid<'graph> { + forbidden: &'graph RefCell>> +} + +impl<'graph> Forbid<'graph> { + pub fn new(forbidden: &'graph RefCell>>, node: DepNode) -> Self { + forbidden.borrow_mut().push(node); + Forbid { forbidden: forbidden } + } +} + +impl<'graph> Drop for Forbid<'graph> { + fn drop(&mut self) { + self.forbidden.borrow_mut().pop(); + } +} From 2a84449169b3c882e101a68eb156800fe8ff24c3 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 24 Aug 2016 11:00:55 -0400 Subject: [PATCH 220/443] allow testing DepNode::Krate edges directly --- src/librustc_incremental/assert_dep_graph.rs | 158 +++++++++---------- src/test/incremental/krate-inlined.rs | 12 +- 2 files changed, 78 insertions(+), 92 deletions(-) diff --git a/src/librustc_incremental/assert_dep_graph.rs b/src/librustc_incremental/assert_dep_graph.rs index bd96ae69ffbc..b28454cddb24 100644 --- a/src/librustc_incremental/assert_dep_graph.rs +++ b/src/librustc_incremental/assert_dep_graph.rs @@ -26,19 +26,20 @@ //! used to check when paths exist or do not. //! //! The full form of the `rustc_if_this_changed` annotation is -//! `#[rustc_if_this_changed(id)]`. The `"id"` is optional and -//! defaults to `"id"` if omitted. +//! `#[rustc_if_this_changed("foo")]`, which will report a +//! source node of `foo(def_id)`. The `"foo"` is optional and +//! defaults to `"Hir"` if omitted. //! //! Example: //! //! ``` -//! #[rustc_if_this_changed] +//! #[rustc_if_this_changed(Hir)] //! fn foo() { } //! -//! #[rustc_then_this_would_need("trans")] //~ ERROR no path from `foo` +//! #[rustc_then_this_would_need(trans)] //~ ERROR no path from `foo` //! fn bar() { } //! -//! #[rustc_then_this_would_need("trans")] //~ ERROR OK +//! #[rustc_then_this_would_need(trans)] //~ ERROR OK //! fn baz() { foo(); } //! ``` @@ -47,7 +48,7 @@ use rustc::dep_graph::{DepGraphQuery, DepNode}; use rustc::dep_graph::debug::{DepNodeFilter, EdgeFilter}; use rustc::hir::def_id::DefId; use rustc::ty::TyCtxt; -use rustc_data_structures::fnv::{FnvHashMap, FnvHashSet}; +use rustc_data_structures::fnv::FnvHashSet; use rustc_data_structures::graph::{Direction, INCOMING, OUTGOING, NodeIndex}; use rustc::hir; use rustc::hir::intravisit::Visitor; @@ -61,7 +62,6 @@ use syntax_pos::Span; const IF_THIS_CHANGED: &'static str = "rustc_if_this_changed"; const THEN_THIS_WOULD_NEED: &'static str = "rustc_then_this_would_need"; -const ID: &'static str = "id"; pub fn assert_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { let _ignore = tcx.dep_graph.in_ignore(); @@ -80,8 +80,9 @@ pub fn assert_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { // Find annotations supplied by user (if any). let (if_this_changed, then_this_would_need) = { let mut visitor = IfThisChanged { tcx: tcx, - if_this_changed: FnvHashMap(), - then_this_would_need: FnvHashMap() }; + if_this_changed: vec![], + then_this_would_need: vec![] }; + visitor.process_attrs(ast::CRATE_NODE_ID, &tcx.map.krate().attrs); tcx.map.krate().visit_all_items(&mut visitor); (visitor.if_this_changed, visitor.then_this_would_need) }; @@ -97,58 +98,51 @@ pub fn assert_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { check_paths(tcx, &if_this_changed, &then_this_would_need); } -type SourceHashMap = - FnvHashMap)>>; -type TargetHashMap = - FnvHashMap)>>; +type Sources = Vec<(Span, DefId, DepNode)>; +type Targets = Vec<(Span, InternedString, ast::NodeId, DepNode)>; struct IfThisChanged<'a, 'tcx:'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, - if_this_changed: SourceHashMap, - then_this_would_need: TargetHashMap, + if_this_changed: Sources, + then_this_would_need: Targets, } impl<'a, 'tcx> IfThisChanged<'a, 'tcx> { - fn process_attrs(&mut self, node_id: ast::NodeId, def_id: DefId) { - for attr in self.tcx.get_attrs(def_id).iter() { + fn argument(&self, attr: &ast::Attribute) -> Option { + let mut value = None; + for list_item in attr.meta_item_list().unwrap_or_default() { + match list_item.word() { + Some(word) if value.is_none() => + value = Some(word.name().clone()), + _ => + // FIXME better-encapsulate meta_item (don't directly access `node`) + span_bug!(list_item.span(), "unexpected meta-item {:?}", list_item.node), + } + } + value + } + + fn process_attrs(&mut self, node_id: ast::NodeId, attrs: &[ast::Attribute]) { + let def_id = self.tcx.map.local_def_id(node_id); + for attr in attrs { if attr.check_name(IF_THIS_CHANGED) { - let mut id = None; - for list_item in attr.meta_item_list().unwrap_or_default() { - match list_item.word() { - Some(word) if id.is_none() => { - id = Some(word.name().clone()) - }, - _ => { - // FIXME better-encapsulate meta_item (don't directly access `node`) - span_bug!(list_item.span(), "unexpected list-item {:?}", list_item.node) + let dep_node_interned = self.argument(attr); + let dep_node = match dep_node_interned { + None => DepNode::Hir(def_id), + Some(ref n) => { + match DepNode::from_label_string(&n[..], def_id) { + Ok(n) => n, + Err(()) => { + self.tcx.sess.span_fatal( + attr.span, + &format!("unrecognized DepNode variant {:?}", n)); + } } } - } - - let id = id.unwrap_or(InternedString::new(ID)); - self.if_this_changed.entry(id) - .or_insert(FnvHashSet()) - .insert((attr.span, def_id, DepNode::Hir(def_id))); + }; + self.if_this_changed.push((attr.span, def_id, dep_node)); } else if attr.check_name(THEN_THIS_WOULD_NEED) { - let mut dep_node_interned = None; - let mut id = None; - for list_item in attr.meta_item_list().unwrap_or_default() { - match list_item.word() { - Some(word) if dep_node_interned.is_none() => { - dep_node_interned = Some(word.name().clone()); - }, - Some(word) if id.is_none() => { - id = Some(word.name().clone()) - }, - _ => { - // FIXME better-encapsulate meta_item (don't directly access `node`) - span_bug!(list_item.span(), "unexpected meta-item {:?}", list_item.node) - } - } - } - + let dep_node_interned = self.argument(attr); let dep_node = match dep_node_interned { Some(ref n) => { match DepNode::from_label_string(&n[..], def_id) { @@ -166,11 +160,10 @@ impl<'a, 'tcx> IfThisChanged<'a, 'tcx> { &format!("missing DepNode variant")); } }; - let id = id.unwrap_or(InternedString::new(ID)); - self.then_this_would_need - .entry(id) - .or_insert(FnvHashSet()) - .insert((attr.span, dep_node_interned.clone().unwrap(), node_id, dep_node)); + self.then_this_would_need.push((attr.span, + dep_node_interned.clone().unwrap(), + node_id, + dep_node)); } } } @@ -178,47 +171,38 @@ impl<'a, 'tcx> IfThisChanged<'a, 'tcx> { impl<'a, 'tcx> Visitor<'tcx> for IfThisChanged<'a, 'tcx> { fn visit_item(&mut self, item: &'tcx hir::Item) { - let def_id = self.tcx.map.local_def_id(item.id); - self.process_attrs(item.id, def_id); + self.process_attrs(item.id, &item.attrs); } } fn check_paths<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - if_this_changed: &SourceHashMap, - then_this_would_need: &TargetHashMap) + if_this_changed: &Sources, + then_this_would_need: &Targets) { // Return early here so as not to construct the query, which is not cheap. if if_this_changed.is_empty() { + for &(target_span, _, _, _) in then_this_would_need { + tcx.sess.span_err( + target_span, + &format!("no #[rustc_if_this_changed] annotation detected")); + + } return; } let query = tcx.dep_graph.query(); - for (id, sources) in if_this_changed { - let targets = match then_this_would_need.get(id) { - Some(targets) => targets, - None => { - for &(source_span, ..) in sources.iter().take(1) { - tcx.sess.span_err( - source_span, - &format!("no targets for id `{}`", id)); - } - continue; - } - }; - - for &(_, source_def_id, ref source_dep_node) in sources { - let dependents = query.transitive_successors(source_dep_node); - for &(target_span, ref target_pass, _, ref target_dep_node) in targets { - if !dependents.contains(&target_dep_node) { - tcx.sess.span_err( - target_span, - &format!("no path from `{}` to `{}`", - tcx.item_path_str(source_def_id), - target_pass)); - } else { - tcx.sess.span_err( - target_span, - &format!("OK")); - } + for &(_, source_def_id, ref source_dep_node) in if_this_changed { + let dependents = query.transitive_successors(source_dep_node); + for &(target_span, ref target_pass, _, ref target_dep_node) in then_this_would_need { + if !dependents.contains(&target_dep_node) { + tcx.sess.span_err( + target_span, + &format!("no path from `{}` to `{}`", + tcx.item_path_str(source_def_id), + target_pass)); + } else { + tcx.sess.span_err( + target_span, + &format!("OK")); } } } diff --git a/src/test/incremental/krate-inlined.rs b/src/test/incremental/krate-inlined.rs index 368065898479..ba32b41983fc 100644 --- a/src/test/incremental/krate-inlined.rs +++ b/src/test/incremental/krate-inlined.rs @@ -8,22 +8,24 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// revisions: rpass1 rpass2 +// Regr. test that using HIR inlined from another krate does *not* add +// a dependency from the local Krate node. + +// revisions: cfail1 // compile-flags: -Z query-dep-graph #![allow(warnings)] #![feature(rustc_attrs)] -#![rustc_partition_reused(module="krate_inlined-x", cfg="rpass2")] + +#![rustc_if_this_changed(Krate)] fn main() { } mod x { + #[rustc_then_this_would_need(TransCrateItem)] //[cfail1]~ ERROR no path fn method() { // use some methods that require inlining HIR from another crate: let mut v = vec![]; v.push(1); } } - -#[cfg(rpass1)] -fn bar() { } // remove this unrelated fn in rpass2, which should not affect `x::method` From 4c2f3ff44263b813d4211150613edff0c5c92c30 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 24 Aug 2016 11:01:12 -0400 Subject: [PATCH 221/443] remove the "misc-items" from meta-data It was duplicating information available elsewhere. --- src/librustc_metadata/common.rs | 4 ++-- src/librustc_metadata/decoder.rs | 11 ++-------- src/librustc_metadata/encoder.rs | 35 +++++--------------------------- 3 files changed, 9 insertions(+), 41 deletions(-) diff --git a/src/librustc_metadata/common.rs b/src/librustc_metadata/common.rs index 1e6c74bef8da..29b9cc0d1d92 100644 --- a/src/librustc_metadata/common.rs +++ b/src/librustc_metadata/common.rs @@ -149,9 +149,9 @@ pub const tag_items_data_item_visibility: usize = 0x78; pub const tag_items_data_item_inherent_impl: usize = 0x79; // GAP 0x7a pub const tag_mod_child: usize = 0x7b; -pub const tag_misc_info: usize = 0x108; // top-level only -pub const tag_misc_info_crate_items: usize = 0x7c; +// GAP 0x7c +// GAP 0x108 pub const tag_impls: usize = 0x109; // top-level only pub const tag_impls_trait: usize = 0x7d; pub const tag_impls_trait_impl: usize = 0x7e; diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 6b48b4dfabcf..d75d5a3b3544 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -23,6 +23,7 @@ use index; use tls_context; use tydecode::TyDecoder; +use rustc::hir::def_id::CRATE_DEF_INDEX; use rustc::hir::svh::Svh; use rustc::hir::map as hir_map; use rustc::hir::map::DefKey; @@ -732,15 +733,7 @@ pub fn each_top_level_item_of_crate(cdata: Cmd, get_crate_data: G, callbac where F: FnMut(DefLike, ast::Name, ty::Visibility), G: FnMut(ast::CrateNum) -> Rc, { - let root_doc = rbml::Doc::new(cdata.data()); - let misc_info_doc = reader::get_doc(root_doc, tag_misc_info); - let crate_items_doc = reader::get_doc(misc_info_doc, - tag_misc_info_crate_items); - - each_child_of_item_or_crate(cdata, - crate_items_doc, - get_crate_data, - callback) + each_child_of_item(cdata, CRATE_DEF_INDEX, get_crate_data, callback) } pub fn get_item_name(cdata: Cmd, id: DefIndex) -> ast::Name { diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 23398a0400c5..603b7a483b90 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -1693,30 +1693,6 @@ fn encode_impls<'a>(ecx: &'a EncodeContext, rbml_w.end_tag(); } -fn encode_misc_info(ecx: &EncodeContext, - krate: &hir::Crate, - rbml_w: &mut Encoder) { - rbml_w.start_tag(tag_misc_info); - rbml_w.start_tag(tag_misc_info_crate_items); - for item_id in &krate.module.item_ids { - rbml_w.wr_tagged_u64(tag_mod_child, - def_to_u64(ecx.tcx.map.local_def_id(item_id.id))); - - let item = ecx.tcx.map.expect_item(item_id.id); - each_auxiliary_node_id(item, |auxiliary_node_id| { - rbml_w.wr_tagged_u64(tag_mod_child, - def_to_u64(ecx.tcx.map.local_def_id(auxiliary_node_id))); - true - }); - } - - // Encode reexports for the root module. - encode_reexports(ecx, rbml_w, 0); - - rbml_w.end_tag(); - rbml_w.end_tag(); -} - // Encodes all reachable symbols in this crate into the metadata. // // This pass is seeded off the reachability list calculated in the @@ -1861,7 +1837,7 @@ fn encode_metadata_inner(rbml_w: &mut Encoder, codemap_bytes: u64, macro_defs_bytes: u64, impl_bytes: u64, - misc_bytes: u64, + reachable_bytes: u64, item_bytes: u64, index_bytes: u64, xref_bytes: u64, @@ -1877,7 +1853,7 @@ fn encode_metadata_inner(rbml_w: &mut Encoder, codemap_bytes: 0, macro_defs_bytes: 0, impl_bytes: 0, - misc_bytes: 0, + reachable_bytes: 0, item_bytes: 0, index_bytes: 0, xref_bytes: 0, @@ -1931,11 +1907,10 @@ fn encode_metadata_inner(rbml_w: &mut Encoder, encode_impls(&ecx, krate, rbml_w); stats.impl_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i; - // Encode miscellaneous info. + // Encode reachability info. i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap(); - encode_misc_info(&ecx, krate, rbml_w); encode_reachable(&ecx, rbml_w); - stats.misc_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i; + stats.reachable_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i; // Encode and index the items. rbml_w.start_tag(tag_items); @@ -1972,7 +1947,7 @@ fn encode_metadata_inner(rbml_w: &mut Encoder, println!(" codemap bytes: {}", stats.codemap_bytes); println!(" macro def bytes: {}", stats.macro_defs_bytes); println!(" impl bytes: {}", stats.impl_bytes); - println!(" misc bytes: {}", stats.misc_bytes); + println!(" reachable bytes: {}", stats.reachable_bytes); println!(" item bytes: {}", stats.item_bytes); println!(" index bytes: {}", stats.index_bytes); println!(" xref bytes: {}", stats.xref_bytes); From 2f91ba05fd930e003bb17b763a32382cfe4392a8 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 2 Sep 2016 07:50:18 -0400 Subject: [PATCH 222/443] implement a debugging "shadow graph" The shadow graph supercedes the existing code that checked for reads/writes without an active task and now adds the ability to filter for specific edges. --- src/librustc/dep_graph/README.md | 31 ++++++++ src/librustc/dep_graph/debug.rs | 7 ++ src/librustc/dep_graph/mod.rs | 1 + src/librustc/dep_graph/shadow.rs | 123 +++++++++++++++++++++++++++++++ src/librustc/dep_graph/thread.rs | 41 ++++------- src/librustc/lib.rs | 1 + 6 files changed, 176 insertions(+), 28 deletions(-) create mode 100644 src/librustc/dep_graph/shadow.rs diff --git a/src/librustc/dep_graph/README.md b/src/librustc/dep_graph/README.md index f16a9b386bb8..48f5b7ea2595 100644 --- a/src/librustc/dep_graph/README.md +++ b/src/librustc/dep_graph/README.md @@ -341,6 +341,8 @@ path is found (as demonstrated above). ### Debugging the dependency graph +#### Dumping the graph + The compiler is also capable of dumping the dependency graph for your debugging pleasure. To do so, pass the `-Z dump-dep-graph` flag. The graph will be dumped to `dep_graph.{txt,dot}` in the current @@ -392,6 +394,35 @@ This will dump out all the nodes that lead from `Hir(foo)` to `TypeckItemBody(bar)`, from which you can (hopefully) see the source of the erroneous edge. +#### Tracking down incorrect edges + +Sometimes, after you dump the dependency graph, you will find some +path that should not exist, but you will not be quite sure how it came +to be. **When the compiler is built with debug assertions,** it can +help you track that down. Simply set the `RUST_FORBID_DEP_GRAPH_EDGE` +environment variable to a filter. Every edge created in the dep-graph +will be tested against that filter -- if it matches, a `bug!` is +reported, so you can easily see the backtrace (`RUST_BACKTRACE=1`). + +The syntax for these filters is the same as described in the previous +section. However, note that this filter is applied to every **edge** +and doesn't handle longer paths in the graph, unlike the previous +section. + +Example: + +You find that there is a path from the `Hir` of `foo` to the type +check of `bar` and you don't think there should be. You dump the +dep-graph as described in the previous section and open `dep-graph.txt` +to see something like: + + Hir(foo) -> Collect(bar) + Collect(bar) -> TypeckItemBody(bar) + +That first edge looks suspicious to you. So you set +`RUST_FORBID_DEP_GRAPH_EDGE` to `Hir&foo -> Collect&bar`, re-run, and +then observe the backtrace. Voila, bug fixed! + ### Inlining of HIR nodes For the time being, at least, we still sometimes "inline" HIR nodes diff --git a/src/librustc/dep_graph/debug.rs b/src/librustc/dep_graph/debug.rs index 15b0380374c6..5b15c5e67174 100644 --- a/src/librustc/dep_graph/debug.rs +++ b/src/librustc/dep_graph/debug.rs @@ -66,4 +66,11 @@ impl EdgeFilter { }) } } + + pub fn test(&self, + source: &DepNode, + target: &DepNode) + -> bool { + self.source.test(source) && self.target.test(target) + } } diff --git a/src/librustc/dep_graph/mod.rs b/src/librustc/dep_graph/mod.rs index a499cb10f232..9c00e95c17e0 100644 --- a/src/librustc/dep_graph/mod.rs +++ b/src/librustc/dep_graph/mod.rs @@ -15,6 +15,7 @@ mod edges; mod graph; mod query; mod raii; +mod shadow; mod thread; mod visit; diff --git a/src/librustc/dep_graph/shadow.rs b/src/librustc/dep_graph/shadow.rs new file mode 100644 index 000000000000..e038997e0ad4 --- /dev/null +++ b/src/librustc/dep_graph/shadow.rs @@ -0,0 +1,123 @@ +//! The "Shadow Graph" is maintained on the main thread and which +//! tracks each message relating to the dep-graph and applies some +//! sanity checks as they go by. If an error results, it means you get +//! a nice stack-trace telling you precisely what caused the error. +//! +//! NOTE: This is a debugging facility which can potentially have non-trivial +//! runtime impact. Therefore, it is largely compiled out if +//! debug-assertions are not enabled. +//! +//! The basic sanity check, always enabled, is that there is always a +//! task (or ignore) on the stack when you do read/write. +//! +//! Optionally, if you specify RUST_FORBID_DEP_GRAPH_EDGE, you can +//! specify an edge filter to be applied to each edge as it is +//! created. See `./README.md` for details. + +use hir::def_id::DefId; +use std::cell::{BorrowState, RefCell}; +use std::env; + +use super::DepNode; +use super::thread::DepMessage; +use super::debug::EdgeFilter; + +pub struct ShadowGraph { + // if you push None onto the stack, that corresponds to an Ignore + stack: RefCell>>>, + forbidden_edge: Option, +} + +const ENABLED: bool = cfg!(debug_assertions); + +impl ShadowGraph { + pub fn new() -> Self { + let forbidden_edge = if !ENABLED { + None + } else { + match env::var("RUST_FORBID_DEP_GRAPH_EDGE") { + Ok(s) => { + match EdgeFilter::new(&s) { + Ok(f) => Some(f), + Err(err) => bug!("RUST_FORBID_DEP_GRAPH_EDGE invalid: {}", err), + } + } + Err(_) => None, + } + }; + + ShadowGraph { + stack: RefCell::new(vec![]), + forbidden_edge: forbidden_edge, + } + } + + pub fn enqueue(&self, message: &DepMessage) { + if ENABLED { + match self.stack.borrow_state() { + BorrowState::Unused => {} + _ => { + // When we apply edge filters, that invokes the + // Debug trait on DefIds, which in turn reads from + // various bits of state and creates reads! Ignore + // those recursive reads. + return; + } + } + + let mut stack = self.stack.borrow_mut(); + match *message { + DepMessage::Read(ref n) => self.check_edge(Some(Some(n)), top(&stack)), + DepMessage::Write(ref n) => self.check_edge(top(&stack), Some(Some(n))), + DepMessage::PushTask(ref n) => stack.push(Some(n.clone())), + DepMessage::PushIgnore => stack.push(None), + DepMessage::PopTask(_) | + DepMessage::PopIgnore => { + // we could easily check that the stack is + // well-formed here, but since we use closures and + // RAII accessors, this bug basically never + // happens, so it seems not worth the overhead + stack.pop(); + } + DepMessage::Query => (), + } + } + } + + fn check_edge(&self, + source: Option>>, + target: Option>>) { + assert!(ENABLED); + match (source, target) { + // cannot happen, one side is always Some(Some(_)) + (None, None) => unreachable!(), + + // nothing on top of the stack + (None, Some(n)) | (Some(n), None) => bug!("read/write of {:?} but no current task", n), + + // this corresponds to an Ignore being top of the stack + (Some(None), _) | (_, Some(None)) => (), + + // a task is on top of the stack + (Some(Some(source)), Some(Some(target))) => { + if let Some(ref forbidden_edge) = self.forbidden_edge { + if forbidden_edge.test(source, target) { + bug!("forbidden edge {:?} -> {:?} created", source, target) + } + } + } + } + } +} + +// Do a little juggling: we get back a reference to an option at the +// top of the stack, convert it to an optional reference. +fn top<'s>(stack: &'s Vec>>) -> Option>> { + stack.last() + .map(|n: &'s Option>| -> Option<&'s DepNode> { + // (*) + // (*) type annotation just there to clarify what would + // otherwise be some *really* obscure code + n.as_ref() + }) +} diff --git a/src/librustc/dep_graph/thread.rs b/src/librustc/dep_graph/thread.rs index 4e16fae18707..90c42d66b7ad 100644 --- a/src/librustc/dep_graph/thread.rs +++ b/src/librustc/dep_graph/thread.rs @@ -20,13 +20,13 @@ use hir::def_id::DefId; use rustc_data_structures::veccell::VecCell; -use std::cell::Cell; use std::sync::mpsc::{self, Sender, Receiver}; use std::thread; use super::DepGraphQuery; use super::DepNode; use super::edges::DepGraphEdges; +use super::shadow::ShadowGraph; #[derive(Debug)] pub enum DepMessage { @@ -42,12 +42,16 @@ pub enum DepMessage { pub struct DepGraphThreadData { enabled: bool, - // Local counter that just tracks how many tasks are pushed onto the - // stack, so that we still get an error in the case where one is - // missing. If dep-graph construction is enabled, we'd get the same - // error when processing tasks later on, but that's annoying because - // it lacks precision about the source of the error. - tasks_pushed: Cell, + // The "shadow graph" is a debugging aid. We give it each message + // in real time as it arrives and it checks for various errors + // (for example, a read/write when there is no current task; it + // can also apply user-defined filters; see `shadow` module for + // details). This only occurs if debug-assertions are enabled. + // + // Note that in some cases the same errors will occur when the + // data is processed off the main thread, but that's annoying + // because it lacks precision about the source of the error. + shadow_graph: ShadowGraph, // current buffer, where we accumulate messages messages: VecCell, @@ -76,7 +80,7 @@ impl DepGraphThreadData { DepGraphThreadData { enabled: enabled, - tasks_pushed: Cell::new(0), + shadow_graph: ShadowGraph::new(), messages: VecCell::with_capacity(INITIAL_CAPACITY), swap_in: rx2, swap_out: tx1, @@ -118,21 +122,7 @@ impl DepGraphThreadData { /// the buffer is full, this may swap.) #[inline] pub fn enqueue(&self, message: DepMessage) { - // Regardless of whether dep graph construction is enabled, we - // still want to check that we always have a valid task on the - // stack when a read/write/etc event occurs. - match message { - DepMessage::Read(_) | DepMessage::Write(_) => - if self.tasks_pushed.get() == 0 { - self.invalid_message("read/write but no current task") - }, - DepMessage::PushTask(_) | DepMessage::PushIgnore => - self.tasks_pushed.set(self.tasks_pushed.get() + 1), - DepMessage::PopTask(_) | DepMessage::PopIgnore => - self.tasks_pushed.set(self.tasks_pushed.get() - 1), - DepMessage::Query => - (), - } + self.shadow_graph.enqueue(&message); if self.enabled { self.enqueue_enabled(message); @@ -147,11 +137,6 @@ impl DepGraphThreadData { self.swap(); } } - - // Outline this too. - fn invalid_message(&self, string: &str) { - bug!("{}; see src/librustc/dep_graph/README.md for more information", string) - } } /// Definition of the depgraph thread. diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index f70349d0ee08..d2a2f8a972d9 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -24,6 +24,7 @@ #![cfg_attr(not(stage0), deny(warnings))] #![feature(associated_consts)] +#![feature(borrow_state)] #![feature(box_patterns)] #![feature(box_syntax)] #![feature(collections)] From fe6557eb62c1f8856ed95c6998083d09e6ec470b Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 2 Sep 2016 08:26:36 -0400 Subject: [PATCH 223/443] expanding a def-id is not a read Across crates only, converting a def-id into its def-key or def-path was considered a read. This caused spurious reads when computing the symbol name for some item. --- src/librustc_metadata/csearch.rs | 12 ++++++-- .../auxiliary/a.rs | 18 ++++++++++++ .../remove-private-item-cross-crate/main.rs | 28 +++++++++++++++++++ 3 files changed, 56 insertions(+), 2 deletions(-) create mode 100644 src/test/incremental/remove-private-item-cross-crate/auxiliary/a.rs create mode 100644 src/test/incremental/remove-private-item-cross-crate/main.rs diff --git a/src/librustc_metadata/csearch.rs b/src/librustc_metadata/csearch.rs index 0fd7b683067b..5e5cc7e1e610 100644 --- a/src/librustc_metadata/csearch.rs +++ b/src/librustc_metadata/csearch.rs @@ -425,13 +425,21 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { /// parent `DefId` as well as some idea of what kind of data the /// `DefId` refers to. fn def_key(&self, def: DefId) -> hir_map::DefKey { - self.dep_graph.read(DepNode::MetaData(def)); + // Note: loading the def-key (or def-path) for a def-id is not + // a *read* of its metadata. This is because the def-id is + // really just an interned shorthand for a def-path, which is the + // canonical name for an item. + // + // self.dep_graph.read(DepNode::MetaData(def)); let cdata = self.get_crate_data(def.krate); decoder::def_key(&cdata, def.index) } fn relative_def_path(&self, def: DefId) -> hir_map::DefPath { - self.dep_graph.read(DepNode::MetaData(def)); + // See `Note` above in `def_key()` for why this read is + // commented out: + // + // self.dep_graph.read(DepNode::MetaData(def)); let cdata = self.get_crate_data(def.krate); decoder::def_path(&cdata, def.index) } diff --git a/src/test/incremental/remove-private-item-cross-crate/auxiliary/a.rs b/src/test/incremental/remove-private-item-cross-crate/auxiliary/a.rs new file mode 100644 index 000000000000..4d84e844dedb --- /dev/null +++ b/src/test/incremental/remove-private-item-cross-crate/auxiliary/a.rs @@ -0,0 +1,18 @@ +// 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. + +#![allow(warnings)] +#![crate_name = "a"] +#![crate_type = "rlib"] + +pub fn foo(b: u8) -> u32 { b as u32 } + +#[cfg(rpass1)] +fn bar() { } diff --git a/src/test/incremental/remove-private-item-cross-crate/main.rs b/src/test/incremental/remove-private-item-cross-crate/main.rs new file mode 100644 index 000000000000..582ee905d7ca --- /dev/null +++ b/src/test/incremental/remove-private-item-cross-crate/main.rs @@ -0,0 +1,28 @@ +// 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. + +// Test that we are able to reuse `main` even though a private +// item was removed from the root module of crate`a`. + +// revisions:rpass1 rpass2 +// aux-build:a.rs + +#![feature(rustc_attrs)] +#![crate_type = "bin"] +#![rustc_partition_reused(module="main", cfg="rpass2")] + +extern crate a; + +pub fn main() { + let vec: Vec = vec![0, 1, 2, 3]; + for &b in &vec { + println!("{}", a::foo(b)); + } +} From 07df8125e6a32796a14ac253aa0df2a0847098b6 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 2 Sep 2016 11:55:32 -0400 Subject: [PATCH 224/443] kill the forbidden code supplanted by RUST_FORBID_DEP_GRAPH_EDGE --- src/librustc/dep_graph/graph.rs | 16 ---------------- src/librustc/dep_graph/raii.rs | 16 ---------------- 2 files changed, 32 deletions(-) diff --git a/src/librustc/dep_graph/graph.rs b/src/librustc/dep_graph/graph.rs index ca441c4bc3ff..c42eeead69ec 100644 --- a/src/librustc/dep_graph/graph.rs +++ b/src/librustc/dep_graph/graph.rs @@ -38,10 +38,6 @@ struct DepGraphData { /// Work-products that we generate in this run. work_products: RefCell, WorkProduct>>, - - /// Tracks nodes that are forbidden to read/write; see - /// `DepGraph::forbid`. Used for debugging only. - forbidden: RefCell>>, } impl DepGraph { @@ -51,7 +47,6 @@ impl DepGraph { thread: DepGraphThreadData::new(enabled), previous_work_products: RefCell::new(FnvHashMap()), work_products: RefCell::new(FnvHashMap()), - forbidden: RefCell::new(Vec::new()), }) } } @@ -75,15 +70,6 @@ impl DepGraph { raii::DepTask::new(&self.data.thread, key) } - /// Debugging aid -- forbid reads/writes to `key` while the return - /// value is in scope. Note that this is only available when debug - /// assertions are enabled -- you should not check in code that - /// invokes this function. - #[cfg(debug_assertions)] - pub fn forbid<'graph>(&'graph self, key: DepNode) -> raii::Forbid<'graph> { - raii::Forbid::new(&self.data.forbidden, key) - } - pub fn with_ignore(&self, op: OP) -> R where OP: FnOnce() -> R { @@ -99,12 +85,10 @@ impl DepGraph { } pub fn read(&self, v: DepNode) { - debug_assert!(!self.data.forbidden.borrow().contains(&v)); self.data.thread.enqueue(DepMessage::Read(v)); } pub fn write(&self, v: DepNode) { - debug_assert!(!self.data.forbidden.borrow().contains(&v)); self.data.thread.enqueue(DepMessage::Write(v)); } diff --git a/src/librustc/dep_graph/raii.rs b/src/librustc/dep_graph/raii.rs index b344eb486240..4445a02785b5 100644 --- a/src/librustc/dep_graph/raii.rs +++ b/src/librustc/dep_graph/raii.rs @@ -49,19 +49,3 @@ impl<'graph> Drop for IgnoreTask<'graph> { } } -pub struct Forbid<'graph> { - forbidden: &'graph RefCell>> -} - -impl<'graph> Forbid<'graph> { - pub fn new(forbidden: &'graph RefCell>>, node: DepNode) -> Self { - forbidden.borrow_mut().push(node); - Forbid { forbidden: forbidden } - } -} - -impl<'graph> Drop for Forbid<'graph> { - fn drop(&mut self) { - self.forbidden.borrow_mut().pop(); - } -} From 2446e258fcc0f5554f91e54d2f849da4dd69a026 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 2 Sep 2016 14:26:16 -0400 Subject: [PATCH 225/443] kill extra `use` --- src/librustc/dep_graph/raii.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/librustc/dep_graph/raii.rs b/src/librustc/dep_graph/raii.rs index 4445a02785b5..e4f572902f9e 100644 --- a/src/librustc/dep_graph/raii.rs +++ b/src/librustc/dep_graph/raii.rs @@ -9,7 +9,6 @@ // except according to those terms. use hir::def_id::DefId; -use std::cell::RefCell; use super::DepNode; use super::thread::{DepGraphThreadData, DepMessage}; From dadce2521e332a6d8f8704ce440637b8a4df7c66 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 2 Sep 2016 18:38:54 -0400 Subject: [PATCH 226/443] always print def-path in Debug impl for DefId I also added an `opt_def_path` so that we can deal with DefIds that are missing a `DefPath` entry. --- src/librustc/hir/def_id.rs | 19 ++++++---------- src/librustc/middle/cstore.rs | 4 ++-- src/librustc/ty/mod.rs | 37 ++++++++++++++++++++++++++++---- src/librustc_metadata/csearch.rs | 2 +- src/librustc_metadata/decoder.rs | 13 ++++++++--- 5 files changed, 53 insertions(+), 22 deletions(-) diff --git a/src/librustc/hir/def_id.rs b/src/librustc/hir/def_id.rs index a3b83ec5be4b..16afa705e391 100644 --- a/src/librustc/hir/def_id.rs +++ b/src/librustc/hir/def_id.rs @@ -58,19 +58,14 @@ impl fmt::Debug for DefId { write!(f, "DefId {{ krate: {:?}, node: {:?}", self.krate, self.index)?; - // Unfortunately, there seems to be no way to attempt to print - // a path for a def-id, so I'll just make a best effort for now - // and otherwise fallback to just printing the crate/node pair - if self.is_local() { // (1) - // (1) side-step fact that not all external things have paths at - // the moment, such as type parameters - ty::tls::with_opt(|opt_tcx| { - if let Some(tcx) = opt_tcx { - write!(f, " => {}", tcx.item_path_str(*self))?; + ty::tls::with_opt(|opt_tcx| { + if let Some(tcx) = opt_tcx { + if let Some(def_path) = tcx.opt_def_path(*self) { + write!(f, " => {}", def_path.to_string(tcx))?; } - Ok(()) - })?; - } + } + Ok(()) + })?; write!(f, " }}") } diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index b33bc520fe21..52645883a8be 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -233,7 +233,7 @@ pub trait CrateStore<'tcx> { def: DefKey) -> Option; fn def_key(&self, def: DefId) -> hir_map::DefKey; - fn relative_def_path(&self, def: DefId) -> hir_map::DefPath; + fn relative_def_path(&self, def: DefId) -> Option; fn variant_kind(&self, def_id: DefId) -> Option; fn struct_ctor_def_id(&self, struct_def_id: DefId) -> Option; fn tuple_struct_definition_if_ctor(&self, did: DefId) -> Option; @@ -430,7 +430,7 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { // resolve fn def_key(&self, def: DefId) -> hir_map::DefKey { bug!("def_key") } - fn relative_def_path(&self, def: DefId) -> hir_map::DefPath { bug!("relative_def_path") } + fn relative_def_path(&self, def: DefId) -> Option { bug!("relative_def_path") } fn variant_kind(&self, def_id: DefId) -> Option { bug!("variant_kind") } fn struct_ctor_def_id(&self, struct_def_id: DefId) -> Option { bug!("struct_ctor_def_id") } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 78358ce534d9..53838b0760a7 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2437,12 +2437,41 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } } - /// Returns the `DefPath` of an item. Note that if `id` is not - /// local to this crate -- or is inlined into this crate -- the - /// result will be a non-local `DefPath`. + /// Convert a `DefId` into its fully expanded `DefPath` (every + /// `DefId` is really just an interned def-path). + /// + /// Note that if `id` is not local to this crate -- or is + /// inlined into this crate -- the result will be a non-local + /// `DefPath`. + /// + /// This function is only safe to use when you are sure that the + /// full def-path is accessible. Examples that are known to be + /// safe are local def-ids or items; see `opt_def_path` for more + /// details. pub fn def_path(self, id: DefId) -> ast_map::DefPath { + self.opt_def_path(id).unwrap_or_else(|| { + bug!("could not load def-path for {:?}", id) + }) + } + + /// Convert a `DefId` into its fully expanded `DefPath` (every + /// `DefId` is really just an interned def-path). + /// + /// When going across crates, we do not save the full info for + /// every cross-crate def-id, and hence we may not always be able + /// to create a def-path. Therefore, this returns + /// `Option` to cover that possibility. It will always + /// return `Some` for local def-ids, however, as well as for + /// items. The problems arise with "minor" def-ids like those + /// associated with a pattern, `impl Trait`, or other internal + /// detail to a fn. + /// + /// Note that if `id` is not local to this crate -- or is + /// inlined into this crate -- the result will be a non-local + /// `DefPath`. + pub fn opt_def_path(self, id: DefId) -> Option { if id.is_local() { - self.map.def_path(id) + Some(self.map.def_path(id)) } else { self.sess.cstore.relative_def_path(id) } diff --git a/src/librustc_metadata/csearch.rs b/src/librustc_metadata/csearch.rs index 5e5cc7e1e610..d7ca93235fdd 100644 --- a/src/librustc_metadata/csearch.rs +++ b/src/librustc_metadata/csearch.rs @@ -435,7 +435,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { decoder::def_key(&cdata, def.index) } - fn relative_def_path(&self, def: DefId) -> hir_map::DefPath { + fn relative_def_path(&self, def: DefId) -> Option { // See `Note` above in `def_key()` for why this read is // commented out: // diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index d75d5a3b3544..5bad89f1a593 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -759,7 +759,7 @@ pub fn maybe_get_item_ast<'a, 'tcx>(cdata: Cmd, tcx: TyCtxt<'a, 'tcx, 'tcx>, id: krate: cdata.cnum, index: def_key(cdata, id).parent.unwrap() }; - let mut parent_def_path = def_path(cdata, id); + let mut parent_def_path = def_path(cdata, id).unwrap(); parent_def_path.data.pop(); if let Some(ast_doc) = reader::maybe_get_doc(item_doc, tag_ast as usize) { let ii = decode_inlined_item(cdata, @@ -1626,9 +1626,16 @@ fn item_def_key(item_doc: rbml::Doc) -> hir_map::DefKey { } } -pub fn def_path(cdata: Cmd, id: DefIndex) -> hir_map::DefPath { +// Returns the path leading to the thing with this `id`. Note that +// some def-ids don't wind up in the metadata, so `def_path` sometimes +// returns `None` +pub fn def_path(cdata: Cmd, id: DefIndex) -> Option { debug!("def_path(id={:?})", id); - hir_map::DefPath::make(cdata.cnum, id, |parent| def_key(cdata, parent)) + if cdata.get_item(id).is_some() { + Some(hir_map::DefPath::make(cdata.cnum, id, |parent| def_key(cdata, parent))) + } else { + None + } } pub fn get_panic_strategy(data: &[u8]) -> PanicStrategy { From c2ffa2f938ec3171180b8e0d4dc20bf92b3a8cfd Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sun, 4 Sep 2016 06:48:17 -0400 Subject: [PATCH 227/443] pacify the mercilous tidy add licenses to shadow.rs --- src/librustc/dep_graph/shadow.rs | 10 ++++++++++ src/librustc/middle/cstore.rs | 4 +++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/librustc/dep_graph/shadow.rs b/src/librustc/dep_graph/shadow.rs index e038997e0ad4..f9f75d006775 100644 --- a/src/librustc/dep_graph/shadow.rs +++ b/src/librustc/dep_graph/shadow.rs @@ -1,3 +1,13 @@ +// 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. + //! The "Shadow Graph" is maintained on the main thread and which //! tracks each message relating to the dep-graph and applies some //! sanity checks as they go by. If an error results, it means you get diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 52645883a8be..d1722ac6f2f7 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -430,7 +430,9 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { // resolve fn def_key(&self, def: DefId) -> hir_map::DefKey { bug!("def_key") } - fn relative_def_path(&self, def: DefId) -> Option { bug!("relative_def_path") } + fn relative_def_path(&self, def: DefId) -> Option { + bug!("relative_def_path") + } fn variant_kind(&self, def_id: DefId) -> Option { bug!("variant_kind") } fn struct_ctor_def_id(&self, struct_def_id: DefId) -> Option { bug!("struct_ctor_def_id") } From 3057b7b9749f16ad982b54b4bdeee7e2c8a845bb Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 6 Sep 2016 12:14:43 -0400 Subject: [PATCH 228/443] ICH: Make CachingCodemapView robustly handle invalid spans. --- .../calculate_svh/caching_codemap_view.rs | 36 ++++++++++++++----- .../calculate_svh/svh_visitor.rs | 15 ++++---- 2 files changed, 36 insertions(+), 15 deletions(-) diff --git a/src/librustc_incremental/calculate_svh/caching_codemap_view.rs b/src/librustc_incremental/calculate_svh/caching_codemap_view.rs index 32aa5a427287..ad9c48420e21 100644 --- a/src/librustc_incremental/calculate_svh/caching_codemap_view.rs +++ b/src/librustc_incremental/calculate_svh/caching_codemap_view.rs @@ -53,16 +53,16 @@ impl<'tcx> CachingCodemapView<'tcx> { pub fn byte_pos_to_line_and_col(&mut self, pos: BytePos) - -> (Rc, usize, BytePos) { + -> Option<(Rc, usize, BytePos)> { self.time_stamp += 1; // Check if the position is in one of the cached lines for cache_entry in self.line_cache.iter_mut() { if pos >= cache_entry.line_start && pos < cache_entry.line_end { cache_entry.time_stamp = self.time_stamp; - return (cache_entry.file.clone(), - cache_entry.line_number, - pos - cache_entry.line_start); + return Some((cache_entry.file.clone(), + cache_entry.line_number, + pos - cache_entry.line_start)); } } @@ -78,8 +78,26 @@ impl<'tcx> CachingCodemapView<'tcx> { // If the entry doesn't point to the correct file, fix it up if pos < cache_entry.file.start_pos || pos >= cache_entry.file.end_pos { - let file_index = self.codemap.lookup_filemap_idx(pos); - cache_entry.file = self.codemap.files.borrow()[file_index].clone(); + let file_valid; + let files = self.codemap.files.borrow(); + + if files.len() > 0 { + let file_index = self.codemap.lookup_filemap_idx(pos); + let file = files[file_index].clone(); + + if pos >= file.start_pos && pos < file.end_pos { + cache_entry.file = file; + file_valid = true; + } else { + file_valid = false; + } + } else { + file_valid = false; + } + + if !file_valid { + return None; + } } let line_index = cache_entry.file.lookup_line(pos).unwrap(); @@ -90,8 +108,8 @@ impl<'tcx> CachingCodemapView<'tcx> { cache_entry.line_end = line_bounds.1; cache_entry.time_stamp = self.time_stamp; - return (cache_entry.file.clone(), - cache_entry.line_number, - pos - cache_entry.line_start); + return Some((cache_entry.file.clone(), + cache_entry.line_number, + pos - cache_entry.line_start)); } } diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs index 05a2f751d292..b1cad10f60aa 100644 --- a/src/librustc_incremental/calculate_svh/svh_visitor.rs +++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs @@ -86,8 +86,8 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> { span.hi }; - let (file1, line1, col1) = self.codemap.byte_pos_to_line_and_col(span.lo); - let (file2, line2, col2) = self.codemap.byte_pos_to_line_and_col(span_hi); + let loc1 = self.codemap.byte_pos_to_line_and_col(span.lo); + let loc2 = self.codemap.byte_pos_to_line_and_col(span_hi); let expansion_kind = match span.expn_id { NO_EXPANSION => SawSpanExpnKind::NoExpansion, @@ -95,9 +95,10 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> { _ => SawSpanExpnKind::SomeExpansion, }; - SawSpan(&file1.name[..], line1, col1, - &file2.name[..], line2, col2, - expansion_kind).hash(self.st); + SawSpan(loc1.as_ref().map(|&(ref fm, line, col)| (&fm.name[..], line, col)), + loc2.as_ref().map(|&(ref fm, line, col)| (&fm.name[..], line, col)), + expansion_kind) + .hash(self.st); if expansion_kind == SawSpanExpnKind::SomeExpansion { let call_site = self.codemap.codemap().source_callsite(span); @@ -171,7 +172,9 @@ enum SawAbiComponent<'a> { SawAssocTypeBinding, SawAttribute(ast::AttrStyle), SawMacroDef, - SawSpan(&'a str, usize, BytePos, &'a str, usize, BytePos, SawSpanExpnKind), + SawSpan(Option<(&'a str, usize, BytePos)>, + Option<(&'a str, usize, BytePos)>, + SawSpanExpnKind), } /// SawExprComponent carries all of the information that we want From d8c58d40eff80a256b27cab875795e42d83817ee Mon Sep 17 00:00:00 2001 From: Tim Neumann Date: Tue, 6 Sep 2016 18:53:43 +0200 Subject: [PATCH 229/443] re-add accidentally removed line --- src/librustc_typeck/check/wfcheck.rs | 1 + src/test/compile-fail/issue-36299.rs | 15 +++++++++++++++ 2 files changed, 16 insertions(+) create mode 100644 src/test/compile-fail/issue-36299.rs diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 6e87c29c4b36..c61d3e1a8762 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -480,6 +480,7 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { (ast_generics.lifetimes[index].lifetime.span, ast_generics.lifetimes[index].lifetime.name) } else { + let index = index - ast_generics.lifetimes.len(); (ast_generics.ty_params[index].span, ast_generics.ty_params[index].name) }; diff --git a/src/test/compile-fail/issue-36299.rs b/src/test/compile-fail/issue-36299.rs new file mode 100644 index 000000000000..88ac74cb09e4 --- /dev/null +++ b/src/test/compile-fail/issue-36299.rs @@ -0,0 +1,15 @@ +// 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. + +struct Foo<'a, A> {} +//~^ ERROR parameter `'a` is never used +//~| ERROR parameter `A` is never used + +fn main() {} From 3784067edcbcd0614f6c4c88f6445ca17ae27ff6 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 2 Sep 2016 12:01:03 -0700 Subject: [PATCH 230/443] Point macros 1.1 errors to the input item Before: ```rust error[E0106]: missing lifetime specifier --> src/main.rs:10:10 | 10 | #[derive(Serialize, Deserialize)] | ^ expected lifetime parameter error[E0038]: the trait `T` cannot be made into an object --> src/main.rs:15:15 | 15 | #[derive(Serialize, Deserialize)] | ^^^^^^^^^^ the trait `T` cannot be made into an object ``` After: ```rust error[E0106]: missing lifetime specifier --> src/main.rs:11:1 | 11 | struct A { | ^ expected lifetime parameter error[E0038]: the trait `T` cannot be made into an object --> src/main.rs:16:1 | 16 | struct B<'a> { | ^ the trait `T` cannot be made into an object ``` --- src/libsyntax_ext/deriving/custom.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/libsyntax_ext/deriving/custom.rs b/src/libsyntax_ext/deriving/custom.rs index 1f9c24a0dcd6..716cf3a94b51 100644 --- a/src/libsyntax_ext/deriving/custom.rs +++ b/src/libsyntax_ext/deriving/custom.rs @@ -53,6 +53,7 @@ impl MultiItemModifier for CustomDerive { } } + let input_span = item.span; let input = __internal::new_token_stream(item); let res = __internal::set_parse_sess(&ecx.parse_sess, || { let inner = self.inner; @@ -77,9 +78,9 @@ impl MultiItemModifier for CustomDerive { // Right now we have no knowledge of spans at all in custom derive // macros, everything is just parsed as a string. Reassign all spans to - // the #[derive] attribute for better errors here. + // the input `item` for better errors here. item.into_iter().flat_map(|item| { - ChangeSpan { span: span }.fold_item(item) + ChangeSpan { span: input_span }.fold_item(item) }).map(Annotatable::Item).collect() } } From 68d29cba95da88fafc5853c78b484f2708a305d8 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Wed, 7 Sep 2016 11:23:49 +1200 Subject: [PATCH 231/443] save-analysis: add docs data --- src/librustc_save_analysis/data.rs | 11 ++++++ src/librustc_save_analysis/dump_visitor.rs | 33 +++++++++++++---- src/librustc_save_analysis/external_data.rs | 24 +++++++++++- src/librustc_save_analysis/json_api_dumper.rs | 12 ++++++ src/librustc_save_analysis/json_dumper.rs | 12 ++++++ src/librustc_save_analysis/lib.rs | 37 ++++++++++++++++--- 6 files changed, 116 insertions(+), 13 deletions(-) diff --git a/src/librustc_save_analysis/data.rs b/src/librustc_save_analysis/data.rs index a58cce0745f3..5f6e65e289fd 100644 --- a/src/librustc_save_analysis/data.rs +++ b/src/librustc_save_analysis/data.rs @@ -134,6 +134,7 @@ pub struct EnumData { pub scope: NodeId, pub variants: Vec, pub visibility: Visibility, + pub docs: String, } /// Data for extern crates. @@ -167,6 +168,7 @@ pub struct FunctionData { pub value: String, pub visibility: Visibility, pub parent: Option, + pub docs: String, } /// Data about a function call. @@ -213,6 +215,7 @@ pub struct MacroData { pub span: Span, pub name: String, pub qualname: String, + pub docs: String, } /// Data about a macro use. @@ -248,6 +251,7 @@ pub struct MethodData { pub value: String, pub decl_id: Option, pub visibility: Visibility, + pub docs: String, } /// Data for modules. @@ -261,6 +265,7 @@ pub struct ModData { pub filename: String, pub items: Vec, pub visibility: Visibility, + pub docs: String, } /// Data for a reference to a module. @@ -283,6 +288,7 @@ pub struct StructData { pub value: String, pub fields: Vec, pub visibility: Visibility, + pub docs: String, } #[derive(Debug, RustcEncodable)] @@ -295,6 +301,7 @@ pub struct StructVariantData { pub value: String, pub scope: NodeId, pub parent: Option, + pub docs: String, } #[derive(Debug, RustcEncodable)] @@ -307,6 +314,7 @@ pub struct TraitData { pub value: String, pub items: Vec, pub visibility: Visibility, + pub docs: String, } #[derive(Debug, RustcEncodable)] @@ -319,6 +327,7 @@ pub struct TupleVariantData { pub value: String, pub scope: NodeId, pub parent: Option, + pub docs: String, } /// Data for a typedef. @@ -331,6 +340,7 @@ pub struct TypeDefData { pub value: String, pub visibility: Visibility, pub parent: Option, + pub docs: String, } /// Data for a reference to a type or trait. @@ -374,6 +384,7 @@ pub struct VariableData { pub value: String, pub type_value: String, pub visibility: Visibility, + pub docs: String, } #[derive(Debug, RustcEncodable)] diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index a695a0706620..faf9cb2b0e3b 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -36,7 +36,7 @@ use rustc::ty::{self, TyCtxt, ImplOrTraitItem, ImplOrTraitItemContainer}; use std::collections::HashSet; use std::hash::*; -use syntax::ast::{self, NodeId, PatKind}; +use syntax::ast::{self, NodeId, PatKind, Attribute}; use syntax::parse::token::{self, keywords}; use syntax::visit::{self, Visitor}; use syntax::print::pprust::{path_to_string, ty_to_string, bounds_to_string, generics_to_string}; @@ -44,7 +44,7 @@ use syntax::ptr::P; use syntax::codemap::Spanned; use syntax_pos::*; -use super::{escape, generated_code, SaveContext, PathCollector}; +use super::{escape, generated_code, SaveContext, PathCollector, docs_for_attrs}; use super::data::*; use super::dump::Dump; use super::external_data::Lower; @@ -368,6 +368,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { scope: 0, parent: None, visibility: Visibility::Inherited, + docs: String::new(), }.lower(self.tcx)); } } @@ -380,6 +381,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { id: ast::NodeId, name: ast::Name, vis: Visibility, + attrs: &[Attribute], span: Span) { debug!("process_method: {}:{}", id, name); @@ -421,6 +423,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { value: sig_str, decl_id: decl_id, visibility: vis, + docs: docs_for_attrs(attrs), }.lower(self.tcx)); } @@ -491,6 +494,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { value: String::new(), visibility: Visibility::Inherited, parent: None, + docs: String::new(), }.lower(self.tcx)); } } @@ -541,7 +545,8 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { typ: &ast::Ty, expr: &ast::Expr, parent_id: NodeId, - vis: Visibility) { + vis: Visibility, + attrs: &[Attribute]) { let qualname = format!("::{}", self.tcx.node_path_str(id)); let sub_span = self.span.sub_span_after_keyword(span, keywords::Const); @@ -558,6 +563,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { scope: self.cur_scope, parent: Some(parent_id), visibility: vis, + docs: docs_for_attrs(attrs), }.lower(self.tcx)); } @@ -600,6 +606,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { value: val, fields: fields, visibility: From::from(&item.vis), + docs: docs_for_attrs(&item.attrs), }.lower(self.tcx)); } @@ -653,6 +660,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { value: val, scope: enum_data.scope, parent: Some(item.id), + docs: docs_for_attrs(&variant.node.attrs), }.lower(self.tcx)); } } @@ -677,6 +685,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { value: val, scope: enum_data.scope, parent: Some(item.id), + docs: docs_for_attrs(&variant.node.attrs), }.lower(self.tcx)); } } @@ -759,6 +768,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { value: val, items: methods.iter().map(|i| i.id).collect(), visibility: From::from(&item.vis), + docs: docs_for_attrs(&item.attrs), }.lower(self.tcx)); } @@ -1007,6 +1017,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { scope: 0, parent: None, visibility: Visibility::Inherited, + docs: String::new(), }.lower(self.tcx)); } } @@ -1036,7 +1047,9 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { self.dumper.macro_data(MacroData { span: sub_span, name: data.name.clone(), - qualname: qualname.clone() + qualname: qualname.clone(), + // FIXME where do macro docs come from? + docs: String::new(), }.lower(self.tcx)); } } @@ -1049,7 +1062,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { qualname: qualname, scope: data.scope, callee_span: data.callee_span, - imported: data.imported + imported: data.imported, }.lower(self.tcx)); } } @@ -1065,7 +1078,8 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { &ty, &expr, trait_id, - Visibility::Public); + Visibility::Public, + &trait_item.attrs); } ast::TraitItemKind::Method(ref sig, ref body) => { self.process_method(sig, @@ -1073,6 +1087,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { trait_item.id, trait_item.ident.name, Visibility::Public, + &trait_item.attrs, trait_item.span); } ast::TraitItemKind::Const(_, None) | @@ -1091,7 +1106,8 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { &ty, &expr, impl_id, - From::from(&impl_item.vis)); + From::from(&impl_item.vis), + &impl_item.attrs); } ast::ImplItemKind::Method(ref sig, ref body) => { self.process_method(sig, @@ -1099,6 +1115,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { impl_item.id, impl_item.ident.name, From::from(&impl_item.vis), + &impl_item.attrs, impl_item.span); } ast::ImplItemKind::Type(_) | @@ -1240,6 +1257,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D> value: value, visibility: From::from(&item.vis), parent: None, + docs: docs_for_attrs(&item.attrs), }.lower(self.tcx)); } @@ -1429,6 +1447,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D> scope: 0, parent: None, visibility: Visibility::Inherited, + docs: String::new(), }.lower(self.tcx)); } } diff --git a/src/librustc_save_analysis/external_data.rs b/src/librustc_save_analysis/external_data.rs index 4333c6dd18e6..3642346582bb 100644 --- a/src/librustc_save_analysis/external_data.rs +++ b/src/librustc_save_analysis/external_data.rs @@ -93,6 +93,7 @@ pub struct EnumData { pub scope: DefId, pub variants: Vec, pub visibility: Visibility, + pub docs: String, } impl Lower for data::EnumData { @@ -108,6 +109,7 @@ impl Lower for data::EnumData { scope: make_def_id(self.scope, &tcx.map), variants: self.variants.into_iter().map(|id| make_def_id(id, &tcx.map)).collect(), visibility: self.visibility, + docs: self.docs, } } } @@ -170,6 +172,7 @@ pub struct FunctionData { pub value: String, pub visibility: Visibility, pub parent: Option, + pub docs: String, } impl Lower for data::FunctionData { @@ -186,6 +189,7 @@ impl Lower for data::FunctionData { value: self.value, visibility: self.visibility, parent: self.parent.map(|id| make_def_id(id, &tcx.map)), + docs: self.docs, } } } @@ -257,6 +261,7 @@ pub struct MacroData { pub span: SpanData, pub name: String, pub qualname: String, + pub docs: String, } impl Lower for data::MacroData { @@ -267,6 +272,7 @@ impl Lower for data::MacroData { span: SpanData::from_span(self.span, tcx.sess.codemap()), name: self.name, qualname: self.qualname, + docs: self.docs, } } } @@ -330,7 +336,8 @@ pub struct MethodData { pub value: String, pub decl_id: Option, pub visibility: Visibility, - pub parent: Option + pub parent: Option, + pub docs: String, } impl Lower for data::MethodData { @@ -347,6 +354,7 @@ impl Lower for data::MethodData { decl_id: self.decl_id, visibility: self.visibility, parent: Some(make_def_id(self.scope, &tcx.map)), + docs: self.docs, } } } @@ -362,6 +370,7 @@ pub struct ModData { pub filename: String, pub items: Vec, pub visibility: Visibility, + pub docs: String, } impl Lower for data::ModData { @@ -377,6 +386,7 @@ impl Lower for data::ModData { filename: self.filename, items: self.items.into_iter().map(|id| make_def_id(id, &tcx.map)).collect(), visibility: self.visibility, + docs: self.docs, } } } @@ -414,6 +424,7 @@ pub struct StructData { pub value: String, pub fields: Vec, pub visibility: Visibility, + pub docs: String, } impl Lower for data::StructData { @@ -430,6 +441,7 @@ impl Lower for data::StructData { value: self.value, fields: self.fields.into_iter().map(|id| make_def_id(id, &tcx.map)).collect(), visibility: self.visibility, + docs: self.docs, } } } @@ -444,6 +456,7 @@ pub struct StructVariantData { pub value: String, pub scope: DefId, pub parent: Option, + pub docs: String, } impl Lower for data::StructVariantData { @@ -459,6 +472,7 @@ impl Lower for data::StructVariantData { value: self.value, scope: make_def_id(self.scope, &tcx.map), parent: self.parent.map(|id| make_def_id(id, &tcx.map)), + docs: self.docs, } } } @@ -473,6 +487,7 @@ pub struct TraitData { pub value: String, pub items: Vec, pub visibility: Visibility, + pub docs: String, } impl Lower for data::TraitData { @@ -488,6 +503,7 @@ impl Lower for data::TraitData { value: self.value, items: self.items.into_iter().map(|id| make_def_id(id, &tcx.map)).collect(), visibility: self.visibility, + docs: self.docs, } } } @@ -502,6 +518,7 @@ pub struct TupleVariantData { pub value: String, pub scope: DefId, pub parent: Option, + pub docs: String, } impl Lower for data::TupleVariantData { @@ -517,6 +534,7 @@ impl Lower for data::TupleVariantData { value: self.value, scope: make_def_id(self.scope, &tcx.map), parent: self.parent.map(|id| make_def_id(id, &tcx.map)), + docs: self.docs, } } } @@ -531,6 +549,7 @@ pub struct TypeDefData { pub value: String, pub visibility: Visibility, pub parent: Option, + pub docs: String, } impl Lower for data::TypeDefData { @@ -545,6 +564,7 @@ impl Lower for data::TypeDefData { value: self.value, visibility: self.visibility, parent: self.parent.map(|id| make_def_id(id, &tcx.map)), + docs: self.docs, } } } @@ -632,6 +652,7 @@ pub struct VariableData { pub type_value: String, pub parent: Option, pub visibility: Visibility, + pub docs: String, } impl Lower for data::VariableData { @@ -649,6 +670,7 @@ impl Lower for data::VariableData { type_value: self.type_value, parent: self.parent.map(|id| make_def_id(id, &tcx.map)), visibility: self.visibility, + docs: self.docs, } } } diff --git a/src/librustc_save_analysis/json_api_dumper.rs b/src/librustc_save_analysis/json_api_dumper.rs index 874babb907e4..751c2d06ee75 100644 --- a/src/librustc_save_analysis/json_api_dumper.rs +++ b/src/librustc_save_analysis/json_api_dumper.rs @@ -168,6 +168,7 @@ struct Def { parent: Option, children: Vec, decl_id: Option, + docs: String, } #[derive(Debug, RustcEncodable)] @@ -209,6 +210,7 @@ impl From for Option { parent: None, children: data.variants.into_iter().map(|id| From::from(id)).collect(), decl_id: None, + docs: data.docs, }), _ => None, } @@ -227,6 +229,7 @@ impl From for Option { parent: data.parent.map(|id| From::from(id)), children: vec![], decl_id: None, + docs: data.docs, }) } } @@ -242,6 +245,7 @@ impl From for Option { parent: data.parent.map(|id| From::from(id)), children: vec![], decl_id: None, + docs: data.docs, }) } } @@ -258,6 +262,7 @@ impl From for Option { parent: None, children: data.fields.into_iter().map(|id| From::from(id)).collect(), decl_id: None, + docs: data.docs, }), _ => None, } @@ -276,6 +281,7 @@ impl From for Option { children: data.items.into_iter().map(|id| From::from(id)).collect(), parent: None, decl_id: None, + docs: data.docs, }), _ => None, } @@ -294,6 +300,7 @@ impl From for Option { children: vec![], parent: data.parent.map(|id| From::from(id)), decl_id: None, + docs: data.docs, }), _ => None, } @@ -312,6 +319,7 @@ impl From for Option { children: vec![], parent: data.parent.map(|id| From::from(id)), decl_id: data.decl_id.map(|id| From::from(id)), + docs: data.docs, }), _ => None, } @@ -329,6 +337,7 @@ impl From for Option { children: vec![], parent: None, decl_id: None, + docs: data.docs, }) } } @@ -345,6 +354,7 @@ impl From for Option { children: data.items.into_iter().map(|id| From::from(id)).collect(), parent: None, decl_id: None, + docs: data.docs, }), _ => None, } @@ -363,6 +373,7 @@ impl From for Option { children: vec![], parent: data.parent.map(|id| From::from(id)), decl_id: None, + docs: String::new(), }), _ => None, } @@ -386,6 +397,7 @@ impl From for Option { children: vec![], parent: data.parent.map(|id| From::from(id)), decl_id: None, + docs: data.docs, }), _ => None, } diff --git a/src/librustc_save_analysis/json_dumper.rs b/src/librustc_save_analysis/json_dumper.rs index b1955cbd7b80..3000376e7246 100644 --- a/src/librustc_save_analysis/json_dumper.rs +++ b/src/librustc_save_analysis/json_dumper.rs @@ -183,6 +183,7 @@ struct Def { value: String, children: Vec, decl_id: Option, + docs: String, } #[derive(Debug, RustcEncodable)] @@ -223,6 +224,7 @@ impl From for Def { value: data.value, children: data.variants.into_iter().map(|id| From::from(id)).collect(), decl_id: None, + docs: data.docs, } } } @@ -238,6 +240,7 @@ impl From for Def { value: data.value, children: vec![], decl_id: None, + docs: data.docs, } } } @@ -252,6 +255,7 @@ impl From for Def { value: data.value, children: vec![], decl_id: None, + docs: data.docs, } } } @@ -266,6 +270,7 @@ impl From for Def { value: data.value, children: data.fields.into_iter().map(|id| From::from(id)).collect(), decl_id: None, + docs: data.docs, } } } @@ -280,6 +285,7 @@ impl From for Def { value: data.value, children: data.items.into_iter().map(|id| From::from(id)).collect(), decl_id: None, + docs: data.docs, } } } @@ -294,6 +300,7 @@ impl From for Def { value: data.value, children: vec![], decl_id: None, + docs: data.docs, } } } @@ -308,6 +315,7 @@ impl From for Def { value: data.value, children: vec![], decl_id: data.decl_id.map(|id| From::from(id)), + docs: data.docs, } } } @@ -322,6 +330,7 @@ impl From for Def { value: String::new(), children: vec![], decl_id: None, + docs: data.docs, } } } @@ -336,6 +345,7 @@ impl From for Def { value: data.filename, children: data.items.into_iter().map(|id| From::from(id)).collect(), decl_id: None, + docs: data.docs, } } } @@ -350,6 +360,7 @@ impl From for Def { value: data.value, children: vec![], decl_id: None, + docs: String::new(), } } } @@ -369,6 +380,7 @@ impl From for Def { value: data.value, children: vec![], decl_id: None, + docs: data.docs, } } } diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index f32baf30ff42..eeb8d02429c0 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -29,6 +29,7 @@ extern crate serialize as rustc_serialize; extern crate syntax_pos; + mod csv_dumper; mod json_api_dumper; mod json_dumper; @@ -50,8 +51,8 @@ use std::env; use std::fs::{self, File}; use std::path::{Path, PathBuf}; -use syntax::ast::{self, NodeId, PatKind}; -use syntax::parse::token::{self, keywords}; +use syntax::ast::{self, NodeId, PatKind, Attribute}; +use syntax::parse::token::{self, keywords, InternedString}; use syntax::visit::{self, Visitor}; use syntax::print::pprust::{ty_to_string, arg_to_string}; use syntax::codemap::MacroAttribute; @@ -142,6 +143,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { value: make_signature(decl, generics), visibility: From::from(&item.vis), parent: None, + docs: docs_for_attrs(&item.attrs), })) } ast::ItemKind::Static(ref typ, mt, ref expr) => { @@ -168,6 +170,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { value: value, type_value: ty_to_string(&typ), visibility: From::from(&item.vis), + docs: docs_for_attrs(&item.attrs), })) } ast::ItemKind::Const(ref typ, ref expr) => { @@ -185,6 +188,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { value: self.span_utils.snippet(expr.span), type_value: ty_to_string(&typ), visibility: From::from(&item.vis), + docs: docs_for_attrs(&item.attrs), })) } ast::ItemKind::Mod(ref m) => { @@ -204,6 +208,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { filename: filename, items: m.items.iter().map(|i| i.id).collect(), visibility: From::from(&item.vis), + docs: docs_for_attrs(&item.attrs), })) } ast::ItemKind::Enum(ref def, _) => { @@ -225,6 +230,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { scope: self.enclosing_scope(item.id), variants: def.variants.iter().map(|v| v.node.data.id()).collect(), visibility: From::from(&item.vis), + docs: docs_for_attrs(&item.attrs), })) } ast::ItemKind::Impl(_, _, _, ref trait_ref, ref typ, _) => { @@ -291,6 +297,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { value: "".to_owned(), type_value: typ, visibility: From::from(&field.vis), + docs: docs_for_attrs(&field.attrs), }) } else { None @@ -303,7 +310,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, vis) = match self.tcx.impl_of_method(self.tcx.map.local_def_id(id)) { + let (qualname, vis, docs) = match self.tcx.impl_of_method(self.tcx.map.local_def_id(id)) { Some(impl_id) => match self.tcx.map.get_if_local(impl_id) { Some(NodeItem(item)) => { match item.node { @@ -316,7 +323,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { result.push_str(&self.tcx.item_path_str(def_id)); } result.push_str(">"); - (result, From::from(&item.vis)) + (result, From::from(&item.vis), docs_for_attrs(&item.attrs)) } _ => { span_bug!(span, @@ -338,7 +345,9 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { Some(def_id) => { match self.tcx.map.get_if_local(def_id) { Some(NodeItem(item)) => { - (format!("::{}", self.tcx.item_path_str(def_id)), From::from(&item.vis)) + (format!("::{}", self.tcx.item_path_str(def_id)), + From::from(&item.vis), + docs_for_attrs(&item.attrs)) } r => { span_bug!(span, @@ -382,6 +391,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { value: String::new(), visibility: vis, parent: Some(parent_scope), + docs: docs, }) } @@ -739,6 +749,23 @@ impl Visitor for PathCollector { } } + +fn docs_for_attrs(attrs: &[Attribute]) -> String { + let doc = InternedString::new("doc"); + let mut result = String::new(); + + for attr in attrs { + if attr.name() == doc { + if let Some(ref val) = attr.value_str() { + result.push_str(val); + result.push('\n'); + } + } + } + + result +} + #[derive(Clone, Copy, Debug)] pub enum Format { Csv, From 31100403fd7a3734b9281cc530795716f94240a0 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Wed, 7 Sep 2016 11:28:13 +1200 Subject: [PATCH 232/443] save-analysis: add a `kind` tag to JSON dumps --- src/librustc_save_analysis/json_api_dumper.rs | 10 ++++++++++ src/librustc_save_analysis/json_dumper.rs | 3 +++ src/librustc_save_analysis/lib.rs | 2 +- 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/librustc_save_analysis/json_api_dumper.rs b/src/librustc_save_analysis/json_api_dumper.rs index 751c2d06ee75..78eaa65872a4 100644 --- a/src/librustc_save_analysis/json_api_dumper.rs +++ b/src/librustc_save_analysis/json_api_dumper.rs @@ -16,6 +16,8 @@ use rustc_serialize::json::as_json; use external_data::*; use data::{VariableKind, Visibility}; use dump::Dump; +use super::Format; + // A dumper to dump a restricted set of JSON information, designed for use with // libraries distributed without their source. Clients are likely to use type @@ -81,17 +83,25 @@ impl<'b, W: Write + 'b> Dump for JsonApiDumper<'b, W> { #[derive(Debug, RustcEncodable)] struct Analysis { + kind: Format, prelude: Option, imports: Vec, defs: Vec, + // These two fields are dummies so that clients can parse the two kinds of + // JSON data in the same way. + refs: Vec<()>, + macro_refs: Vec<()>, } impl Analysis { fn new() -> Analysis { Analysis { + kind: Format::JsonApi, prelude: None, imports: vec![], defs: vec![], + refs: vec![], + macro_refs: vec![], } } } diff --git a/src/librustc_save_analysis/json_dumper.rs b/src/librustc_save_analysis/json_dumper.rs index 3000376e7246..2de883a55d32 100644 --- a/src/librustc_save_analysis/json_dumper.rs +++ b/src/librustc_save_analysis/json_dumper.rs @@ -16,6 +16,7 @@ use rustc_serialize::json::as_json; use external_data::*; use data::VariableKind; use dump::Dump; +use super::Format; pub struct JsonDumper<'b, W: Write + 'b> { output: &'b mut W, @@ -87,6 +88,7 @@ impl<'b, W: Write + 'b> Dump for JsonDumper<'b, W> { #[derive(Debug, RustcEncodable)] struct Analysis { + kind: Format, prelude: Option, imports: Vec, defs: Vec, @@ -97,6 +99,7 @@ struct Analysis { impl Analysis { fn new() -> Analysis { Analysis { + kind: Format::Json, prelude: None, imports: vec![], defs: vec![], diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index eeb8d02429c0..99ab0d2684fe 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -766,7 +766,7 @@ fn docs_for_attrs(attrs: &[Attribute]) -> String { result } -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy, Debug, RustcEncodable)] pub enum Format { Csv, Json, From a77b55d58f9b173b1e4fb96bb6935fadbfda3240 Mon Sep 17 00:00:00 2001 From: Justin LeFebvre Date: Tue, 6 Sep 2016 01:04:07 -0400 Subject: [PATCH 233/443] remove the extraneous not_equal implementation for slices. --- src/libcore/slice.rs | 21 ++------------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs index baa41aa7af5b..b22bdb43414f 100644 --- a/src/libcore/slice.rs +++ b/src/libcore/slice.rs @@ -1821,7 +1821,8 @@ impl PartialOrd for [T] { // intermediate trait for specialization of slice's PartialEq trait SlicePartialEq { fn equal(&self, other: &[B]) -> bool; - fn not_equal(&self, other: &[B]) -> bool; + + fn not_equal(&self, other: &[B]) -> bool { !self.equal(other) } } // Generic slice equality @@ -1841,20 +1842,6 @@ impl SlicePartialEq for [A] true } - - default fn not_equal(&self, other: &[B]) -> bool { - if self.len() != other.len() { - return true; - } - - for i in 0..self.len() { - if self[i].ne(&other[i]) { - return true; - } - } - - false - } } // Use memcmp for bytewise equality when the types allow @@ -1874,10 +1861,6 @@ impl SlicePartialEq for [A] other.as_ptr() as *const u8, size) == 0 } } - - fn not_equal(&self, other: &[A]) -> bool { - !self.equal(other) - } } #[doc(hidden)] From 0adcf46cdf3d85e78e761fdaaa9c3fa8a69df927 Mon Sep 17 00:00:00 2001 From: Jake Goldsborough Date: Tue, 6 Sep 2016 18:31:00 -0700 Subject: [PATCH 234/443] detecting nodejs in configure --- configure | 4 ++++ src/bootstrap/bootstrap.py | 9 --------- src/bootstrap/config.rs | 3 --- 3 files changed, 4 insertions(+), 12 deletions(-) diff --git a/configure b/configure index bcc1faea3b5d..352b77560b73 100755 --- a/configure +++ b/configure @@ -634,6 +634,7 @@ valopt datadir "${CFG_PREFIX}/share" "install data" valopt infodir "${CFG_PREFIX}/share/info" "install additional info" valopt llvm-root "" "set LLVM root" valopt python "" "set path to python" +valopt nodejs "" "set path to nodejs" valopt jemalloc-root "" "set directory where libjemalloc_pic.a is located" valopt build "${DEFAULT_BUILD}" "GNUs ./configure syntax LLVM build triple" valopt android-cross-path "" "Android NDK standalone path (deprecated)" @@ -749,6 +750,9 @@ if [ $(echo $python_version | grep -c '^Python 2\.7') -ne 1 ]; then err "Found $python_version, but Python 2.7 is required" fi +# Checking for node, but not required +probe CFG_NODEJS nodejs node + # 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 ] diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 3f4a18ab1247..17a7c9ca66a2 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -236,15 +236,6 @@ class RustBuild: return config + '/bin/rustc' + self.exe_suffix() return os.path.join(self.bin_root(), "bin/rustc" + self.exe_suffix()) - def nodejs(self): - config = self.get_toml('nodejs') - if config: - return config - if os.path.exists(os.path.join(self.bin_root(), "bin/nodejs")): - return os.path.join(self.bin_root(), "bin/nodejs" + self.exe_suffix()) - elif os.path.exists(os.path.join(self.bin_root(), "bin/node")): - return os.path.join(self.bin_root(), "bin/node" + self.exe_suffix()) - def get_string(self, line): start = line.find('"') end = start + 1 + line[start+1:].find('"') diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 5a7ae4f6973d..682a6f74126a 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -67,7 +67,6 @@ pub struct Config { pub target: Vec, pub rustc: Option, pub cargo: Option, - pub nodejs: Option, pub local_rebuild: bool, // libstd features @@ -112,7 +111,6 @@ struct Build { host: Vec, target: Vec, cargo: Option, - nodejs: Option, rustc: Option, compiler_docs: Option, docs: Option, @@ -217,7 +215,6 @@ impl Config { } config.rustc = build.rustc.map(PathBuf::from); config.cargo = build.cargo.map(PathBuf::from); - config.nodejs = build.nodejs.map(PathBuf::from); set(&mut config.compiler_docs, build.compiler_docs); set(&mut config.docs, build.docs); From b99c5cf109925b3a13aa768ad4644000d926b851 Mon Sep 17 00:00:00 2001 From: Tshepang Lekhonkhobe Date: Wed, 7 Sep 2016 04:15:56 +0200 Subject: [PATCH 235/443] doc: we got coercion going on here, so no need to be this explicit --- src/libstd/path.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 9a5b1da0f08f..12f8619cde64 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -1169,9 +1169,9 @@ impl PathBuf { /// let mut p = PathBuf::from("/test/test.rs"); /// /// p.pop(); - /// assert_eq!(Path::new("/test"), p.as_path()); + /// assert_eq!(Path::new("/test"), p); /// p.pop(); - /// assert_eq!(Path::new("/"), p.as_path()); + /// assert_eq!(Path::new("/"), p); /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn pop(&mut self) -> bool { From 8cfc69ecea9874ad28253ecc47d50099f9e7001e Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 6 Sep 2016 21:49:02 -0500 Subject: [PATCH 236/443] add utility musl_root method, update config.toml.example --- src/bootstrap/compile.rs | 3 +-- src/bootstrap/config.toml.example | 10 ++++++---- src/bootstrap/lib.rs | 7 +++++++ src/bootstrap/sanity.rs | 3 +-- 4 files changed, 15 insertions(+), 8 deletions(-) diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index e14317b23b4d..dbb356c82e6f 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -60,8 +60,7 @@ pub fn std<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) { } } if target.contains("musl") { - if let Some(p) = build.config.target_config[target].musl_root.as_ref() - .or(build.config.musl_root.as_ref()) { + if let Some(p) = build.musl_root(target) { cargo.env("MUSL_ROOT", p); } } diff --git a/src/bootstrap/config.toml.example b/src/bootstrap/config.toml.example index 2894adafef62..1b453baa2984 100644 --- a/src/bootstrap/config.toml.example +++ b/src/bootstrap/config.toml.example @@ -115,10 +115,6 @@ # nightly features #channel = "dev" -# The root location of the MUSL installation directory. The library directory -# will also need to contain libunwind.a for an unwinding implementation. -#musl-root = "..." - # By default the `rustc` executable is built with `-Wl,-rpath` flags on Unix # platforms to ensure that the compiler is usable by default from the build # directory (as it links to a number of dynamic libraries). This may not be @@ -160,3 +156,9 @@ # the NDK for the target lives. This is used to find the C compiler to link and # build native code. #android-ndk = "/path/to/ndk" + +# The root location of the MUSL installation directory. The library directory +# will also need to contain libunwind.a for an unwinding implementation. Note +# that this option only makes sense for MUSL targets that produce statically +# linked binaries +#musl-root = "..." diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index dbf29cda4921..94c14f7ea254 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -977,6 +977,13 @@ impl Build { } return base } + + /// Returns the "musl root" for this `target`, if defined + fn musl_root(&self, target: &str) -> Option<&Path> { + self.config.target_config[target].musl_root.as_ref() + .or(self.config.musl_root.as_ref()) + .map(|p| &**p) + } } impl<'a> Compiler<'a> { diff --git a/src/bootstrap/sanity.rs b/src/bootstrap/sanity.rs index f1d7f869a965..c69f9489c306 100644 --- a/src/bootstrap/sanity.rs +++ b/src/bootstrap/sanity.rs @@ -111,8 +111,7 @@ pub fn check(build: &mut Build) { // Make sure musl-root is valid if specified if target.contains("musl") && !target.contains("mips") { - match build.config.target_config[target].musl_root.as_ref() - .or(build.config.musl_root.as_ref()) { + match build.musl_root(target) { Some(root) => { if fs::metadata(root.join("lib/libc.a")).is_err() { panic!("couldn't find libc.a in musl dir: {}", From f84d081a7e705da1f3e920801319424b53cfd8b0 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Tue, 6 Sep 2016 09:47:35 +0000 Subject: [PATCH 237/443] Avoid instaiblity errors in code generated by `syntax_ext::deriving::call_intrinsic()`. --- src/libsyntax_ext/deriving/mod.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/libsyntax_ext/deriving/mod.rs b/src/libsyntax_ext/deriving/mod.rs index 5582166c12e9..fcbce3638908 100644 --- a/src/libsyntax_ext/deriving/mod.rs +++ b/src/libsyntax_ext/deriving/mod.rs @@ -338,10 +338,19 @@ fn hygienic_type_parameter(item: &Annotatable, base: &str) -> String { /// Constructs an expression that calls an intrinsic fn call_intrinsic(cx: &ExtCtxt, - span: Span, + mut span: Span, intrinsic: &str, args: Vec>) -> P { + span.expn_id = cx.codemap().record_expansion(codemap::ExpnInfo { + call_site: span, + callee: codemap::NameAndSpan { + format: codemap::MacroAttribute(intern("derive")), + span: Some(span), + allow_internal_unstable: true, + }, + }); + let path = cx.std_path(&["intrinsics", intrinsic]); let call = cx.expr_call_global(span, path, args); From d6ea10ec764bbddd39cc4a3d34b6a4987ac867a6 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Wed, 7 Sep 2016 03:09:09 +0000 Subject: [PATCH 238/443] Add regression test. --- .../auxiliary/custom_derive_partial_eq.rs | 81 +++++++++++++++++++ .../custom-derive-partial-eq.rs | 22 +++++ 2 files changed, 103 insertions(+) create mode 100644 src/test/run-pass-fulldeps/auxiliary/custom_derive_partial_eq.rs create mode 100644 src/test/run-pass-fulldeps/custom-derive-partial-eq.rs diff --git a/src/test/run-pass-fulldeps/auxiliary/custom_derive_partial_eq.rs b/src/test/run-pass-fulldeps/auxiliary/custom_derive_partial_eq.rs new file mode 100644 index 000000000000..956f789dab83 --- /dev/null +++ b/src/test/run-pass-fulldeps/auxiliary/custom_derive_partial_eq.rs @@ -0,0 +1,81 @@ +// 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. + +// force-host + +#![feature(plugin_registrar, rustc_private, item_like_imports)] + +extern crate syntax; +extern crate syntax_ext; +extern crate rustc_plugin; + +use syntax_ext::deriving; +use deriving::generic::*; +use deriving::generic::ty::*; + +use rustc_plugin::Registry; +use syntax::ast::*; +use syntax::codemap::Span; +use syntax::ext::base::*; +use syntax::ext::build::AstBuilder; +use syntax::parse::token::{intern, InternedString}; +use syntax::ptr::P; + +#[plugin_registrar] +pub fn plugin_registrar(reg: &mut Registry) { + reg.register_syntax_extension(intern("derive_CustomPartialEq"), + MultiDecorator(Box::new(expand_deriving_partial_eq))); +} + +fn expand_deriving_partial_eq(cx: &mut ExtCtxt, span: Span, mitem: &MetaItem, item: &Annotatable, + push: &mut FnMut(Annotatable)) { + // structures are equal if all fields are equal, and non equal, if + // any fields are not equal or if the enum variants are different + fn cs_eq(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P { + cs_fold(true, + |cx, span, subexpr, self_f, other_fs| { + let other_f = (other_fs.len(), other_fs.get(0)).1.unwrap(); + let eq = cx.expr_binary(span, BinOpKind::Eq, self_f, other_f.clone()); + cx.expr_binary(span, BinOpKind::And, subexpr, eq) + }, + cx.expr_bool(span, true), + Box::new(|cx, span, _, _| cx.expr_bool(span, false)), + cx, + span, + substr) + } + + let inline = cx.meta_word(span, InternedString::new("inline")); + let attrs = vec!(cx.attribute(span, inline)); + let methods = vec![MethodDef { + name: "eq", + generics: LifetimeBounds::empty(), + explicit_self: borrowed_explicit_self(), + args: vec!(borrowed_self()), + ret_ty: Literal(deriving::generic::ty::Path::new_local("bool")), + attributes: attrs, + is_unsafe: false, + unify_fieldless_variants: true, + combine_substructure: combine_substructure(Box::new(cs_eq)), + }]; + + let trait_def = TraitDef { + span: span, + attributes: Vec::new(), + path: deriving::generic::ty::Path::new(vec!["std", "cmp", "PartialEq"]), + additional_bounds: Vec::new(), + generics: LifetimeBounds::empty(), + is_unsafe: false, + supports_unions: false, + methods: methods, + associated_types: Vec::new(), + }; + trait_def.expand(cx, mitem, item, push) +} diff --git a/src/test/run-pass-fulldeps/custom-derive-partial-eq.rs b/src/test/run-pass-fulldeps/custom-derive-partial-eq.rs new file mode 100644 index 000000000000..8cc7ab4219dc --- /dev/null +++ b/src/test/run-pass-fulldeps/custom-derive-partial-eq.rs @@ -0,0 +1,22 @@ +// 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. + +// aux-build:custom_derive_partial_eq.rs +// ignore-stage1 +// ignore-pretty : (#23623) problems when ending with // comments + +#![feature(plugin, custom_derive)] +#![plugin(custom_derive_partial_eq)] +#![allow(unused)] + +#[derive(CustomPartialEq)] // Check that this is not a stability error. +enum E { V1, V2 } + +fn main() {} From 102b3a937b8bb5ef601fd586a3d9ffcd518d6bf3 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Tue, 6 Sep 2016 21:10:15 -0400 Subject: [PATCH 239/443] Add doc example for `std::time::Instant::elapsed`. --- src/libstd/time/mod.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/libstd/time/mod.rs b/src/libstd/time/mod.rs index 0e1508a1c4c2..154f603c84f1 100644 --- a/src/libstd/time/mod.rs +++ b/src/libstd/time/mod.rs @@ -150,6 +150,18 @@ impl Instant { /// This function may panic if the current time is earlier than this /// instant, which is something that can happen if an `Instant` is /// produced synthetically. + /// + /// # Examples + /// + /// ```no_run + /// use std::thread::sleep; + /// use std::time::{Duration, Instant}; + /// + /// let instant = Instant::now(); + /// let three_secs = Duration::from_secs(3); + /// sleep(three_secs); + /// assert!(instant.elapsed() >= three_secs); + /// ``` #[stable(feature = "time2", since = "1.8.0")] pub fn elapsed(&self) -> Duration { Instant::now() - *self From 8760a5e3cc8bab89053ef9cee9757160e76f517d Mon Sep 17 00:00:00 2001 From: Ulrich Weigand Date: Wed, 7 Sep 2016 17:09:24 +0200 Subject: [PATCH 240/443] Follow target ABI sign-/zero-extension rules for enum types While attempting to port Rust to s390x, I ran into an ABI violation (that caused rust_eh_personality to be miscompiled, breaking unwinding). The problem is that this function returns an enum type, which is supposed to be sign-extended according to the s390x ABI. However, common code would ignore target sign-/zero-extension rules for any types that do not satisfy is_integral(), which includes enums. For the general case of Rust enum types, which map to structure types with a discriminant, that seems correct. However, in the special case of simple enums that map directly to C enum types (i.e. LLVM integers), this is incorrect; we must follow the target extension rules for those. Signed-off-by: Ulrich Weigand --- src/librustc_trans/abi.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs index c2b040c32f6a..ab0fd0c92edd 100644 --- a/src/librustc_trans/abi.rs +++ b/src/librustc_trans/abi.rs @@ -26,6 +26,7 @@ use cabi_asmjs; use machine::{llalign_of_min, llsize_of, llsize_of_real, llsize_of_store}; use type_::Type; use type_of; +use adt; use rustc::hir; use rustc::ty::{self, Ty}; @@ -317,6 +318,14 @@ impl FnType { if ty.is_integral() { arg.signedness = Some(ty.is_signed()); } + // Rust enum types that map onto C enums (LLVM integers) also + // need to follow the target ABI zero-/sign-extension rules. + if let ty::TyEnum(..) = ty.sty { + if arg.ty.kind() == llvm::Integer { + let repr = adt::represent_type(ccx, ty); + arg.signedness = Some(adt::is_discr_signed(&repr)); + } + } if llsize_of_real(ccx, arg.ty) == 0 { // For some forsaken reason, x86_64-pc-windows-gnu // doesn't ignore zero-sized struct arguments. From 3f0462acbbabc7703dffdd2771d6cca56eb5545b Mon Sep 17 00:00:00 2001 From: Ulrich Weigand Date: Wed, 7 Sep 2016 17:21:10 +0200 Subject: [PATCH 241/443] Fix argument to FIONBIO ioctl The FIONBIO ioctl takes as argument a pointer to an integer, which should be either 0 or 1 to indicate whether nonblocking mode is to be switched off or on. The type of the pointed-to variable is "int". However, the set_nonblocking routine in libstd/sys/unix/net.rs passes a pointer to a libc::c_ulong variable. This doesn't matter on all 32-bit platforms and on all litte-endian platforms, but it will break on big-endian 64-bit platforms. Found while porting Rust to s390x (a big-endian 64-bit platform). Signed-off-by: Ulrich Weigand --- src/libstd/sys/unix/net.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/sys/unix/net.rs b/src/libstd/sys/unix/net.rs index 3f77abd7f44d..f124ea651ec2 100644 --- a/src/libstd/sys/unix/net.rs +++ b/src/libstd/sys/unix/net.rs @@ -213,7 +213,7 @@ impl Socket { } pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { - let mut nonblocking = nonblocking as libc::c_ulong; + let mut nonblocking = nonblocking as libc::c_int; cvt(unsafe { libc::ioctl(*self.as_inner(), libc::FIONBIO, &mut nonblocking) }).map(|_| ()) } From ce413e0da234ecc68648c81d7c476da3a8d68b9e Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Wed, 7 Sep 2016 12:37:16 +1200 Subject: [PATCH 242/443] save-analysis: tweak the type value for functions --- src/librustc_save_analysis/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 99ab0d2684fe..164869c5e159 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -676,7 +676,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { } fn make_signature(decl: &ast::FnDecl, generics: &ast::Generics) -> String { - let mut sig = String::new(); + let mut sig = "fn ".to_owned(); if !generics.lifetimes.is_empty() || !generics.ty_params.is_empty() { sig.push('<'); sig.push_str(&generics.lifetimes.iter() @@ -696,7 +696,7 @@ fn make_signature(decl: &ast::FnDecl, generics: &ast::Generics) -> String { sig.push_str(&decl.inputs.iter().map(arg_to_string).collect::>().join(", ")); sig.push(')'); match decl.output { - ast::FunctionRetTy::Default(_) => {} + ast::FunctionRetTy::Default(_) => sig.push_str(" -> ()"), ast::FunctionRetTy::Ty(ref t) => sig.push_str(&format!(" -> {}", ty_to_string(t))), } From 493544a1f9009c794015697440093f59ab1856c7 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Wed, 7 Sep 2016 08:31:11 -0700 Subject: [PATCH 243/443] save-analysis: only emit type in the value for variables --- src/librustc_save_analysis/dump_visitor.rs | 8 ++++++-- src/librustc_save_analysis/json_dumper.rs | 2 +- src/librustc_save_analysis/lib.rs | 1 - 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index faf9cb2b0e3b..05859a63c5d3 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -1427,11 +1427,15 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D> for &(id, ref p, immut, ref_kind) in &collector.collected_paths { match self.tcx.expect_def(id) { Def::Local(_, id) => { - let value = if immut == ast::Mutability::Immutable { + let mut value = if immut == ast::Mutability::Immutable { self.span.snippet(p.span).to_string() } else { "".to_string() }; + let typ = self.tcx.node_types() + .get(&id).map(|t| t.to_string()).unwrap_or(String::new()); + value.push_str(": "); + value.push_str(&typ); assert!(p.segments.len() == 1, "qualified path for local variable def in arm"); @@ -1443,7 +1447,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D> name: path_to_string(p), qualname: format!("{}${}", path_to_string(p), id), value: value, - type_value: String::new(), + type_value: typ, scope: 0, parent: None, visibility: Visibility::Inherited, diff --git a/src/librustc_save_analysis/json_dumper.rs b/src/librustc_save_analysis/json_dumper.rs index 2de883a55d32..75abff8d37ed 100644 --- a/src/librustc_save_analysis/json_dumper.rs +++ b/src/librustc_save_analysis/json_dumper.rs @@ -380,7 +380,7 @@ impl From for Def { span: data.span, name: data.name, qualname: data.qualname, - value: data.value, + value: data.type_value, children: vec![], decl_id: None, docs: data.docs, diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 164869c5e159..3c0f10755089 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -749,7 +749,6 @@ impl Visitor for PathCollector { } } - fn docs_for_attrs(attrs: &[Attribute]) -> String { let doc = InternedString::new("doc"); let mut result = String::new(); From b58294e3289cdaca6ef07c77777e4787cad285ad Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Wed, 7 Sep 2016 09:27:56 -0700 Subject: [PATCH 244/443] save-analysis: strip /// or whatever from doc comments --- src/librustc_save_analysis/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 3c0f10755089..6170e14940ec 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -52,6 +52,7 @@ use std::fs::{self, File}; use std::path::{Path, PathBuf}; use syntax::ast::{self, NodeId, PatKind, Attribute}; +use syntax::parse::lexer::comments::strip_doc_comment_decoration; use syntax::parse::token::{self, keywords, InternedString}; use syntax::visit::{self, Visitor}; use syntax::print::pprust::{ty_to_string, arg_to_string}; @@ -756,7 +757,7 @@ fn docs_for_attrs(attrs: &[Attribute]) -> String { for attr in attrs { if attr.name() == doc { if let Some(ref val) = attr.value_str() { - result.push_str(val); + result.push_str(&strip_doc_comment_decoration(val)); result.push('\n'); } } From ce3cecf116a2d691c53f37c1d257a416ecfd381b Mon Sep 17 00:00:00 2001 From: Ulrich Weigand Date: Wed, 7 Sep 2016 21:03:21 +0200 Subject: [PATCH 245/443] Use layout_of to detect C enums --- src/librustc_trans/abi.rs | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs index ab0fd0c92edd..42289ec094f3 100644 --- a/src/librustc_trans/abi.rs +++ b/src/librustc_trans/abi.rs @@ -26,7 +26,6 @@ use cabi_asmjs; use machine::{llalign_of_min, llsize_of, llsize_of_real, llsize_of_store}; use type_::Type; use type_of; -use adt; use rustc::hir; use rustc::ty::{self, Ty}; @@ -36,6 +35,7 @@ use std::cmp; pub use syntax::abi::Abi; pub use rustc::ty::layout::{FAT_PTR_ADDR, FAT_PTR_EXTRA}; +use rustc::ty::layout::Layout; #[derive(Clone, Copy, PartialEq, Debug)] enum ArgKind { @@ -318,13 +318,10 @@ impl FnType { if ty.is_integral() { arg.signedness = Some(ty.is_signed()); } - // Rust enum types that map onto C enums (LLVM integers) also - // need to follow the target ABI zero-/sign-extension rules. - if let ty::TyEnum(..) = ty.sty { - if arg.ty.kind() == llvm::Integer { - let repr = adt::represent_type(ccx, ty); - arg.signedness = Some(adt::is_discr_signed(&repr)); - } + // Rust enum types that map onto C enums also need to follow + // the target ABI zero-/sign-extension rules. + if let Layout::CEnum { signed, .. } = *ccx.layout_of(ty) { + arg.signedness = Some(signed); } if llsize_of_real(ccx, arg.ty) == 0 { // For some forsaken reason, x86_64-pc-windows-gnu From 04b776e5eca7aa49618a1425f08c8825e51b19dc Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sun, 4 Sep 2016 18:37:30 +0300 Subject: [PATCH 246/443] Zero first byte of CString on drop This should prevent code like ``` let ptr = CString::new("hello").unwrap().as_ptr(); ``` from working by accident. --- src/libstd/ffi/c_str.rs | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs index 38222c014f61..2d5e8c041940 100644 --- a/src/libstd/ffi/c_str.rs +++ b/src/libstd/ffi/c_str.rs @@ -19,6 +19,7 @@ use mem; use memchr; use ops; use os::raw::c_char; +use ptr; use slice; use str::{self, Utf8Error}; @@ -68,6 +69,9 @@ use str::{self, Utf8Error}; #[derive(PartialEq, PartialOrd, Eq, Ord, Hash, Clone)] #[stable(feature = "rust1", since = "1.0.0")] pub struct CString { + // Invariant 1: the slice ends with a zero byte and has a length of at least one. + // Invariant 2: the slice contains only one zero byte. + // Improper usage of unsafe function can break Invariant 2, but not Invariant 1. inner: Box<[u8]>, } @@ -244,7 +248,7 @@ impl CString { /// Failure to call `from_raw` will lead to a memory leak. #[stable(feature = "cstr_memory", since = "1.4.0")] pub fn into_raw(self) -> *mut c_char { - Box::into_raw(self.inner) as *mut c_char + Box::into_raw(self.into_inner()) as *mut c_char } /// Converts the `CString` into a `String` if it contains valid Unicode data. @@ -265,7 +269,7 @@ impl CString { /// it is guaranteed to not have any interior nul bytes. #[stable(feature = "cstring_into", since = "1.7.0")] pub fn into_bytes(self) -> Vec { - let mut vec = self.inner.into_vec(); + let mut vec = self.into_inner().into_vec(); let _nul = vec.pop(); debug_assert_eq!(_nul, Some(0u8)); vec @@ -275,7 +279,7 @@ impl CString { /// includes the trailing nul byte. #[stable(feature = "cstring_into", since = "1.7.0")] pub fn into_bytes_with_nul(self) -> Vec { - self.inner.into_vec() + self.into_inner().into_vec() } /// Returns the contents of this `CString` as a slice of bytes. @@ -293,6 +297,24 @@ impl CString { pub fn as_bytes_with_nul(&self) -> &[u8] { &self.inner } + + // Bypass "move out of struct which implements `Drop` trait" restriction. + fn into_inner(self) -> Box<[u8]> { + unsafe { + let result = ptr::read(&self.inner); + mem::forget(self); + result + } + } +} + +// Turns this `CString` into an empty string to prevent +// memory unsafe code from working by accident. +#[stable(feature = "cstring_drop", since = "1.13.0")] +impl Drop for CString { + fn drop(&mut self) { + unsafe { *self.inner.get_unchecked_mut(0) = 0; } + } } #[stable(feature = "rust1", since = "1.0.0")] From f9a340804c998f25691be182fc8bc40b8fc9a496 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 7 Sep 2016 10:13:49 +0300 Subject: [PATCH 247/443] Add a test for CString drop --- src/test/run-pass/cstring-drop.rs | 49 +++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 src/test/run-pass/cstring-drop.rs diff --git a/src/test/run-pass/cstring-drop.rs b/src/test/run-pass/cstring-drop.rs new file mode 100644 index 000000000000..960391bb8dea --- /dev/null +++ b/src/test/run-pass/cstring-drop.rs @@ -0,0 +1,49 @@ +// 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. + +// ignore-emscripten + +// Test that `CString::new("hello").unwrap().as_ptr()` pattern +// leads to failure. + +use std::env; +use std::ffi::{CString, CStr}; +use std::os::raw::c_char; +use std::process::{Command, Stdio}; + +fn main() { + let args: Vec = env::args().collect(); + if args.len() > 1 && args[1] == "child" { + // Repeat several times to be more confident that + // it is `Drop` for `CString` that does the cleanup, + // and not just some lucky UB. + let xs = vec![CString::new("Hello").unwrap(); 10]; + let ys = xs.iter().map(|s| s.as_ptr()).collect::>(); + drop(xs); + assert!(ys.into_iter().any(is_hello)); + return; + } + + let output = Command::new(&args[0]).arg("child").output().unwrap(); + assert!(!output.status.success()); +} + +fn is_hello(s: *const c_char) -> bool { + // `s` is a dangling pointer and reading it is technically + // undefined behavior. But we want to prevent the most diabolical + // kind of UB (apart from nasal demons): reading a value that was + // previously written. + // + // Segfaulting or reading an empty string is Ok, + // reading "Hello" is bad. + let s = unsafe { CStr::from_ptr(s) }; + let hello = CString::new("Hello").unwrap(); + s == hello.as_ref() +} From 7e46f2ceaa84ae7ba7143fcbe8bb3d0da2449fb4 Mon Sep 17 00:00:00 2001 From: Jake Goldsborough Date: Wed, 7 Sep 2016 13:13:37 -0700 Subject: [PATCH 248/443] moving nodejs detection logic to configure and adding a nodejs cmd sanity check --- src/bootstrap/config.rs | 4 ++++ src/bootstrap/sanity.rs | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 682a6f74126a..b17012025119 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -79,6 +79,7 @@ pub struct Config { pub musl_root: Option, pub prefix: Option, pub codegen_tests: bool, + pub nodejs: Option, } /// Per-target configuration stored in the global configuration structure. @@ -391,6 +392,9 @@ impl Config { self.rustc = Some(PathBuf::from(value).join("bin/rustc")); self.cargo = Some(PathBuf::from(value).join("bin/cargo")); } + "CFG_NODEJS" if value.len() > 0 => { + self.nodejs = Some(PathBuf::from(value)); + } _ => {} } } diff --git a/src/bootstrap/sanity.rs b/src/bootstrap/sanity.rs index ae7f2e018f9f..c345893954f4 100644 --- a/src/bootstrap/sanity.rs +++ b/src/bootstrap/sanity.rs @@ -76,7 +76,7 @@ pub fn check(build: &mut Build) { need_cmd("python".as_ref()); // If a manual nodejs was added to the config, - // of if a nodejs install is detected through bootstrap.py, use it. + // of if a nodejs install is detected through config, use it. if build.config.nodejs.is_some() { need_cmd("nodejs".as_ref()) } From f6aab5b9e516f3086e75745f53aaf77212bedde9 Mon Sep 17 00:00:00 2001 From: Jakob Demler Date: Wed, 7 Sep 2016 22:15:32 +0200 Subject: [PATCH 249/443] Fixed typo in nomicon --- src/doc/nomicon/ownership.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/nomicon/ownership.md b/src/doc/nomicon/ownership.md index 6be8d3b70286..a6ecf6ab91b4 100644 --- a/src/doc/nomicon/ownership.md +++ b/src/doc/nomicon/ownership.md @@ -52,7 +52,7 @@ let mut data = vec![1, 2, 3]; let x = &data[0]; // OH NO! `push` causes the backing storage of `data` to be reallocated. -// Dangling pointer! User after free! Alas! +// Dangling pointer! Use after free! Alas! // (this does not compile in Rust) data.push(4); From 41d1cd7196d6799fa960ac220d20b958c1b797ed Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Wed, 7 Sep 2016 23:18:46 +0200 Subject: [PATCH 250/443] add static_in_const feature gate also updates tests and deletes the spurious .bk files I inadvertently added last time. --- src/librustc_typeck/collect.rs | 2 +- src/librustc_typeck/rscope.rs | 39 ++++++++++ src/libsyntax/feature_gate.rs | 3 + src/test/compile-fail/const-unsized.rs | 2 + src/test/compile-fail/issue-24446.rs | 2 +- src/test/compile-fail/rfc1623.rs | 2 +- src/test/compile-fail/rfc1623.rs.bk | 98 -------------------------- src/test/run-pass/rfc1623.rs | 1 + src/test/run-pass/rfc1623.rs.bk | 81 --------------------- 9 files changed, 48 insertions(+), 182 deletions(-) delete mode 100644 src/test/compile-fail/rfc1623.rs.bk delete mode 100644 src/test/run-pass/rfc1623.rs.bk diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index fcc0b09e31ac..0eb6a747263e 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1567,7 +1567,7 @@ fn type_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, NodeItem(item) => { match item.node { ItemStatic(ref t, ..) | ItemConst(ref t, _) => { - ccx.icx(&()).to_ty(&ElidableRscope::new(ty::ReStatic), &t) + ccx.icx(&()).to_ty(&StaticRscope::new(&ccx.tcx), &t) } ItemFn(ref decl, unsafety, _, abi, ref generics, _) => { let tofd = AstConv::ty_of_bare_fn(&ccx.icx(generics), unsafety, abi, &decl, diff --git a/src/librustc_typeck/rscope.rs b/src/librustc_typeck/rscope.rs index f5b13c4207d9..5b00a625bacf 100644 --- a/src/librustc_typeck/rscope.rs +++ b/src/librustc_typeck/rscope.rs @@ -213,6 +213,45 @@ impl RegionScope for ElidableRscope { } } +/// A scope that behaves as an ElidabeRscope with a `'static` default region +/// that should also warn if the `static_in_const` feature is unset. +#[derive(Copy, Clone)] +pub struct StaticRscope<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { + tcx: &'a ty::TyCtxt<'a, 'gcx, 'tcx>, +} + +impl<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> StaticRscope<'a, 'gcx, 'tcx> { + /// create a new StaticRscope from a reference to the `TyCtxt` + pub fn new(tcx: &'a ty::TyCtxt<'a, 'gcx, 'tcx>) -> Self { + StaticRscope { tcx: tcx } + } +} + +impl<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> RegionScope for StaticRscope<'a, 'gcx, 'tcx> { + fn anon_regions(&self, + _span: Span, + count: usize) + -> Result, Option>> { + Ok(vec![ty::ReStatic; count]) + } + + fn object_lifetime_default(&self, span: Span) -> Option { + Some(self.base_object_lifetime_default(span)) + } + + fn base_object_lifetime_default(&self, span: Span) -> ty::Region { + if !self.tcx.sess.features.borrow().static_in_const { + self.tcx + .sess + .struct_span_warn(span, + "This needs a `'static` lifetime or the \ + `static_in_const` feature, see #35897") + .emit(); + } + ty::ReStatic + } +} + /// A scope in which we generate anonymous, late-bound regions for /// omitted regions. This occurs in function signatures. pub struct BindingRscope { diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index dd2956f706c9..8b8a41fc2048 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -295,6 +295,9 @@ declare_features! ( // Allows untagged unions `union U { ... }` (active, untagged_unions, "1.13.0", Some(32836)), + + // elide `'static` lifetimes in `static`s and `const`s + (active, static_in_const, "1.13.0", Some(35897)), ); declare_features! ( diff --git a/src/test/compile-fail/const-unsized.rs b/src/test/compile-fail/const-unsized.rs index a73164b957c8..07d6edb1f3b1 100644 --- a/src/test/compile-fail/const-unsized.rs +++ b/src/test/compile-fail/const-unsized.rs @@ -15,6 +15,7 @@ const CONST_0: Debug+Sync = *(&0 as &(Debug+Sync)); //~| NOTE `std::fmt::Debug + Sync + 'static: std::marker::Sized` not satisfied //~| NOTE does not have a constant size known at compile-time //~| NOTE constant expressions must have a statically known size +//~| WARNING This needs a `'static` lifetime or the `static_in_const` feature const CONST_FOO: str = *"foo"; //~^ ERROR `str: std::marker::Sized` is not satisfied @@ -27,6 +28,7 @@ static STATIC_1: Debug+Sync = *(&1 as &(Debug+Sync)); //~| NOTE `std::fmt::Debug + Sync + 'static: std::marker::Sized` not satisfied //~| NOTE does not have a constant size known at compile-time //~| NOTE constant expressions must have a statically known size +//~| WARNING This needs a `'static` lifetime or the `static_in_const` feature static STATIC_BAR: str = *"bar"; //~^ ERROR `str: std::marker::Sized` is not satisfied diff --git a/src/test/compile-fail/issue-24446.rs b/src/test/compile-fail/issue-24446.rs index b9382520cf9d..d721c8bb6d2b 100644 --- a/src/test/compile-fail/issue-24446.rs +++ b/src/test/compile-fail/issue-24446.rs @@ -12,7 +12,7 @@ fn main() { static foo: Fn() -> u32 = || -> u32 { //~^ ERROR: mismatched types //~| ERROR: `std::ops::Fn() -> u32 + 'static: std::marker::Sized` is not satisfied - + //~| WARNING: This needs a `'static` lifetime or the `static_in_const` feature 0 }; } diff --git a/src/test/compile-fail/rfc1623.rs b/src/test/compile-fail/rfc1623.rs index 1d8fc7fe111c..083cc218eecf 100644 --- a/src/test/compile-fail/rfc1623.rs +++ b/src/test/compile-fail/rfc1623.rs @@ -7,7 +7,7 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. - +#![feature(static_in_const)] #![allow(dead_code)] fn non_elidable<'a, 'b>(a: &'a u8, b: &'b u8) -> &'a u8 { diff --git a/src/test/compile-fail/rfc1623.rs.bk b/src/test/compile-fail/rfc1623.rs.bk deleted file mode 100644 index abdcc02de767..000000000000 --- a/src/test/compile-fail/rfc1623.rs.bk +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![allow(dead_code)] - -fn non_elidable<'a, 'b>(a: &'a u8, b: &'b u8) -> &'a u8 { a } - -// the boundaries of elision -static NON_ELIDABLE_FN : &fn(&u8, &u8) -> &u8 = -//~^ ERROR: missing lifetime specifier - &(non_elidable as fn(&u8, &u8) -> &u8); - -struct SomeStruct<'x, 'y, 'z: 'x> { - foo: &'x Foo<'z>, - bar: &'x Bar<'z>, - f: &'y for<'a, 'b: 'a> Fn(&'a Foo<'b>) -> &'a Bar<'b>, -} - -fn id(t: T) -> T { t } - -static SOME_STRUCT : &SomeStruct = SomeStruct { - foo: &Foo { bools: &[false, true] }, - bar: &Bar { bools: &[true, true] }, - f: &id, -}; - -// very simple test for a 'static static with default lifetime -static STATIC_STR : &'static str = "&'static str"; -const CONST_STR : &'static str = "&'static str"; - -// this should be the same as without default: -static EXPLICIT_STATIC_STR : &'static str = "&'static str"; -const EXPLICIT_CONST_STR : &'static str = "&'static str"; - -// a function that elides to an unbound lifetime for both in- and output -fn id_u8_slice(arg: &[u8]) -> &[u8] { arg } - -// one with a function, argument elided -static STATIC_SIMPLE_FN : &'static fn(&[u8]) -> &[u8] = - &(id_u8_slice as fn(&[u8]) -> &[u8]); -const CONST_SIMPLE_FN : &'static fn(&[u8]) -> &[u8] = - &(id_u8_slice as fn(&[u8]) -> &[u8]); - -// this should be the same as without elision -static STATIC_NON_ELIDED_fN : &'static for<'a> fn(&'a [u8]) -> &'a [u8] = - &(id_u8_slice as for<'a> fn(&'a [u8]) -> &'a [u8]); -const CONST_NON_ELIDED_fN : &'static for<'a> fn(&'a [u8]) -> &'a [u8] = - &(id_u8_slice as for<'a> fn(&'a [u8]) -> &'a [u8]); - -// another function that elides, each to a different unbound lifetime -fn multi_args(a: &u8, b: &u8, c: &u8) { } - -static STATIC_MULTI_FN : &'static fn(&u8, &u8, &u8) = - &(multi_args as fn(&u8, &u8, &u8)); -const CONST_MULTI_FN : &'static fn(&u8, &u8, &u8) = - &(multi_args as fn(&u8, &u8, &u8)); - -struct Foo<'a> { - bools: &'a [bool] -} - -static STATIC_FOO : Foo<'static> = Foo { bools: &[true, false] }; -const CONST_FOO : Foo<'static> = Foo { bools: &[true, false] }; - -type Bar<'a> = Foo<'a>; - -static STATIC_BAR : Bar<'static> = Bar { bools: &[true, false] }; -const CONST_BAR : Bar<'static> = Bar { bools: &[true, false] }; - -type Baz<'a> = fn(&'a [u8]) -> Option; - -fn baz(e: &[u8]) -> Option { e.first().map(|x| *x) } - -static STATIC_BAZ : &'static Baz<'static> = &(baz as Baz); -const CONST_BAZ : &'static Baz<'static> = &(baz as Baz); - -static BYTES : &'static [u8] = &[1, 2, 3]; - -fn main() { - let x = &[1u8, 2, 3]; - let y = x; - - //this works, so lifetime < `'static` is valid - assert_eq!(Some(1), STATIC_BAZ(y)); - assert_eq!(Some(1), CONST_BAZ(y)); - - let y = &[1u8, 2, 3]; - //^~ ERROR: borrowed values does not live long enough - STATIC_BAZ(BYTES); // BYTES has static lifetime - CONST_BAZ(y); // This forces static lifetime, which y has not -} diff --git a/src/test/run-pass/rfc1623.rs b/src/test/run-pass/rfc1623.rs index 17453933c8ab..fc9143dc450b 100644 --- a/src/test/run-pass/rfc1623.rs +++ b/src/test/run-pass/rfc1623.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(static_in_const)] #![allow(dead_code)] // very simple test for a 'static static with default lifetime diff --git a/src/test/run-pass/rfc1623.rs.bk b/src/test/run-pass/rfc1623.rs.bk deleted file mode 100644 index 0915118ca27c..000000000000 --- a/src/test/run-pass/rfc1623.rs.bk +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![allow(dead_code)] - -// very simple test for a 'static static with default lifetime -static STATIC_STR : &str = "&'static str"; -const CONST_STR : &str = "&'static str"; - -// this should be the same as without default: -static EXPLICIT_STATIC_STR : &'static str = "&'static str"; -const EXPLICIT_CONST_STR : &'static str = "&'static str"; - -// a function that elides to an unbound lifetime for both in- and output -fn id_u8_slice(arg: &[u8]) -> &[u8] { arg } - -// one with a function, argument elided -static STATIC_SIMPLE_FN : &fn(&[u8]) -> &[u8] = - &(id_u8_slice as fn(&[u8]) -> &[u8]); -const CONST_SIMPLE_FN : &fn(&[u8]) -> &[u8] = - &(id_u8_slice as fn(&[u8]) -> &[u8]); - -// this should be the same as without elision -static STATIC_NON_ELIDED_fN : &for<'a> fn(&'a [u8]) -> &'a [u8] = - &(id_u8_slice as for<'a> fn(&'a [u8]) -> &'a [u8]); -const CONST_NON_ELIDED_fN : &for<'a> fn(&'a [u8]) -> &'a [u8] = - &(id_u8_slice as for<'a> fn(&'a [u8]) -> &'a [u8]); - -// another function that elides, each to a different unbound lifetime -fn multi_args(a: &u8, b: &u8, c: &u8) { } - -static STATIC_MULTI_FN : &fn(&u8, &u8, &u8) = - &(multi_args as fn(&u8, &u8, &u8)); -const CONST_MULTI_FN : &fn(&u8, &u8, &u8) = - &(multi_args as fn(&u8, &u8, &u8)); - -struct Foo<'a> { - bools: &'a [bool] -} - -static STATIC_FOO : Foo = Foo { bools: &[true, false] }; -const CONST_FOO : Foo = Foo { bools: &[true, false] }; - -type Bar<'a> = Foo<'a>; - -static STATIC_BAR : Bar = Bar { bools: &[true, false] }; -const CONST_BAR : Bar = Bar { bools: &[true, false] }; - -type Baz<'a> = fn(&'a [u8]) -> Option; - -fn baz(e: &[u8]) -> Option { e.first().map(|x| *x) } - -static STATIC_BAZ : &Baz = &(baz as Baz); -const CONST_BAZ : &Baz = &(baz as Baz); - -static BYTES : &[u8] = &[1, 2, 3]; - -fn main() { - // make sure that the lifetime is actually elided (and not defaulted) - let x = &[1u8, 2, 3]; - STATIC_SIMPLE_FN(x); - CONST_SIMPLE_FN(x); - - STATIC_BAZ(BYTES); // neees static lifetime - CONST_BAZ(BYTES); - - // make sure this works with different lifetimes - let a = &1; - { - let b = &2; - let c = &3; - CONST_MULTI_FN(a, b, c); - } -} From 3af0c6572eebd2c7fad72e8ba37eac71b8abc8bc Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Fri, 2 Sep 2016 01:44:23 +0000 Subject: [PATCH 251/443] Refactor code out of the folder implementation for `StripUnconfigured`. --- src/libsyntax/config.rs | 154 ++++++++++++++++------------- src/libsyntax/util/small_vector.rs | 6 ++ 2 files changed, 90 insertions(+), 70 deletions(-) diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs index 7f6395997abe..07604bffa1c6 100644 --- a/src/libsyntax/config.rs +++ b/src/libsyntax/config.rs @@ -13,7 +13,7 @@ use feature_gate::{emit_feature_err, EXPLAIN_STMT_ATTR_SYNTAX, Features, get_fea use {fold, attr}; use ast; use codemap::{Spanned, respan}; -use parse::{ParseSess, token}; +use parse::ParseSess; use ptr::P; use util::small_vector::SmallVector; @@ -60,6 +60,15 @@ pub fn features(mut krate: ast::Crate, sess: &ParseSess, should_test: bool) (krate, features) } +macro_rules! configure { + ($this:ident, $node:ident) => { + match $this.configure($node) { + Some(node) => node, + None => return Default::default(), + } + } +} + impl<'a> StripUnconfigured<'a> { fn configure(&mut self, node: T) -> Option { let node = self.process_cfg_attrs(node); @@ -156,37 +165,35 @@ impl<'a> StripUnconfigured<'a> { } } } -} -impl<'a> fold::Folder for StripUnconfigured<'a> { - fn fold_foreign_mod(&mut self, foreign_mod: ast::ForeignMod) -> ast::ForeignMod { + fn configure_foreign_mod(&mut self, foreign_mod: ast::ForeignMod) -> ast::ForeignMod { ast::ForeignMod { abi: foreign_mod.abi, - items: foreign_mod.items.into_iter().filter_map(|item| { - self.configure(item).map(|item| fold::noop_fold_foreign_item(item, self)) - }).collect(), + items: foreign_mod.items.into_iter().filter_map(|item| self.configure(item)).collect(), } } - fn fold_item_kind(&mut self, item: ast::ItemKind) -> ast::ItemKind { - let fold_struct = |this: &mut Self, vdata| match vdata { + fn configure_variant_data(&mut self, vdata: ast::VariantData) -> ast::VariantData { + match vdata { ast::VariantData::Struct(fields, id) => { - let fields = fields.into_iter().filter_map(|field| this.configure(field)); + let fields = fields.into_iter().filter_map(|field| self.configure(field)); ast::VariantData::Struct(fields.collect(), id) } ast::VariantData::Tuple(fields, id) => { - let fields = fields.into_iter().filter_map(|field| this.configure(field)); + let fields = fields.into_iter().filter_map(|field| self.configure(field)); ast::VariantData::Tuple(fields.collect(), id) } ast::VariantData::Unit(id) => ast::VariantData::Unit(id) - }; + } + } - let item = match item { + fn configure_item_kind(&mut self, item: ast::ItemKind) -> ast::ItemKind { + match item { ast::ItemKind::Struct(def, generics) => { - ast::ItemKind::Struct(fold_struct(self, def), generics) + ast::ItemKind::Struct(self.configure_variant_data(def), generics) } ast::ItemKind::Union(def, generics) => { - ast::ItemKind::Union(fold_struct(self, def), generics) + ast::ItemKind::Union(self.configure_variant_data(def), generics) } ast::ItemKind::Enum(def, generics) => { let variants = def.variants.into_iter().filter_map(|v| { @@ -195,7 +202,7 @@ impl<'a> fold::Folder for StripUnconfigured<'a> { node: ast::Variant_ { name: v.node.name, attrs: v.node.attrs, - data: fold_struct(self, v.node.data), + data: self.configure_variant_data(v.node.data), disr_expr: v.node.disr_expr, }, span: v.span @@ -207,12 +214,19 @@ impl<'a> fold::Folder for StripUnconfigured<'a> { }, generics) } item => item, - }; - - fold::noop_fold_item_kind(item, self) + } } - fn fold_expr(&mut self, expr: P) -> P { + fn configure_expr_kind(&mut self, expr_kind: ast::ExprKind) -> ast::ExprKind { + if let ast::ExprKind::Match(m, arms) = expr_kind { + let arms = arms.into_iter().filter_map(|a| self.configure(a)).collect(); + ast::ExprKind::Match(m, arms) + } else { + expr_kind + } + } + + fn configure_expr(&mut self, expr: P) -> P { self.visit_stmt_or_expr_attrs(expr.attrs()); // If an expr is valid to cfg away it will have been removed by the @@ -227,62 +241,62 @@ impl<'a> fold::Folder for StripUnconfigured<'a> { self.sess.span_diagnostic.span_err(attr.span, msg); } - let expr = self.process_cfg_attrs(expr); - fold_expr(self, expr) + self.process_cfg_attrs(expr) } - fn fold_opt_expr(&mut self, expr: P) -> Option> { - self.configure(expr).map(|expr| fold_expr(self, expr)) - } - - fn fold_stmt(&mut self, stmt: ast::Stmt) -> SmallVector { + fn configure_stmt(&mut self, stmt: ast::Stmt) -> Option { self.visit_stmt_or_expr_attrs(stmt.attrs()); - self.configure(stmt).map(|stmt| fold::noop_fold_stmt(stmt, self)) - .unwrap_or(SmallVector::zero()) - } - - fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac { - fold::noop_fold_mac(mac, self) - } - - fn fold_item(&mut self, item: P) -> SmallVector> { - self.configure(item).map(|item| fold::noop_fold_item(item, self)) - .unwrap_or(SmallVector::zero()) - } - - fn fold_impl_item(&mut self, item: ast::ImplItem) -> SmallVector { - self.configure(item).map(|item| fold::noop_fold_impl_item(item, self)) - .unwrap_or(SmallVector::zero()) - } - - fn fold_trait_item(&mut self, item: ast::TraitItem) -> SmallVector { - self.configure(item).map(|item| fold::noop_fold_trait_item(item, self)) - .unwrap_or(SmallVector::zero()) - } - - fn fold_interpolated(&mut self, nt: token::Nonterminal) -> token::Nonterminal { - // Don't configure interpolated AST (c.f. #34171). - // Interpolated AST will get configured once the surrounding tokens are parsed. - nt + self.configure(stmt) } } -fn fold_expr(folder: &mut StripUnconfigured, expr: P) -> P { - expr.map(|ast::Expr {id, span, node, attrs}| { - fold::noop_fold_expr(ast::Expr { - id: id, - node: match node { - ast::ExprKind::Match(m, arms) => { - ast::ExprKind::Match(m, arms.into_iter() - .filter_map(|a| folder.configure(a)) - .collect()) - } - _ => node - }, - span: span, - attrs: attrs, - }, folder) - }) +impl<'a> fold::Folder for StripUnconfigured<'a> { + fn fold_foreign_mod(&mut self, foreign_mod: ast::ForeignMod) -> ast::ForeignMod { + let foreign_mod = self.configure_foreign_mod(foreign_mod); + fold::noop_fold_foreign_mod(foreign_mod, self) + } + + fn fold_item_kind(&mut self, item: ast::ItemKind) -> ast::ItemKind { + let item = self.configure_item_kind(item); + fold::noop_fold_item_kind(item, self) + } + + fn fold_expr(&mut self, expr: P) -> P { + let mut expr = self.configure_expr(expr).unwrap(); + expr.node = self.configure_expr_kind(expr.node); + P(fold::noop_fold_expr(expr, self)) + } + + fn fold_opt_expr(&mut self, expr: P) -> Option> { + let mut expr = configure!(self, expr).unwrap(); + expr.node = self.configure_expr_kind(expr.node); + Some(P(fold::noop_fold_expr(expr, self))) + } + + fn fold_stmt(&mut self, stmt: ast::Stmt) -> SmallVector { + match self.configure_stmt(stmt) { + Some(stmt) => fold::noop_fold_stmt(stmt, self), + None => return SmallVector::zero(), + } + } + + fn fold_item(&mut self, item: P) -> SmallVector> { + fold::noop_fold_item(configure!(self, item), self) + } + + fn fold_impl_item(&mut self, item: ast::ImplItem) -> SmallVector { + fold::noop_fold_impl_item(configure!(self, item), self) + } + + fn fold_trait_item(&mut self, item: ast::TraitItem) -> SmallVector { + fold::noop_fold_trait_item(configure!(self, item), self) + } + + fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac { + // Don't configure interpolated AST (c.f. #34171). + // Interpolated AST will get configured once the surrounding tokens are parsed. + mac + } } fn is_cfg(attr: &ast::Attribute) -> bool { diff --git a/src/libsyntax/util/small_vector.rs b/src/libsyntax/util/small_vector.rs index 893646f121f0..373dfc4ddfac 100644 --- a/src/libsyntax/util/small_vector.rs +++ b/src/libsyntax/util/small_vector.rs @@ -29,6 +29,12 @@ enum SmallVectorRepr { Many(Vec), } +impl Default for SmallVector { + fn default() -> Self { + SmallVector { repr: Zero } + } +} + impl Into> for SmallVector { fn into(self) -> Vec { match self.repr { From d951d5dec44f71eed82daba0854f404cc4bfe2a5 Mon Sep 17 00:00:00 2001 From: Andrew Paseltiner Date: Wed, 7 Sep 2016 18:26:53 -0400 Subject: [PATCH 252/443] Handle `ReEmpty` for `impl Trait` Closes #35668 --- src/librustc_typeck/check/writeback.rs | 4 ++-- src/test/compile-fail/issue-35668.rs | 24 ++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) create mode 100644 src/test/compile-fail/issue-35668.rs diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 4be032c6f7f0..0b70d904c265 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -319,7 +319,8 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { let outside_ty = gcx.fold_regions(&inside_ty, &mut false, |r, _| { match *r { // 'static is valid everywhere. - ty::ReStatic => gcx.mk_region(ty::ReStatic), + ty::ReStatic | + ty::ReEmpty => gcx.mk_region(*r), // Free regions that come from early-bound regions are valid. ty::ReFree(ty::FreeRegion { @@ -341,7 +342,6 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { } ty::ReVar(_) | - ty::ReEmpty | ty::ReErased => { let span = reason.span(self.tcx()); span_bug!(span, "invalid region in impl Trait: {:?}", r); diff --git a/src/test/compile-fail/issue-35668.rs b/src/test/compile-fail/issue-35668.rs new file mode 100644 index 000000000000..c9323db054c8 --- /dev/null +++ b/src/test/compile-fail/issue-35668.rs @@ -0,0 +1,24 @@ +// 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. + +#![feature(conservative_impl_trait)] + +fn func<'a, T>(a: &'a [T]) -> impl Iterator { + a.iter().map(|a| a*a) + //~^ ERROR binary operation `*` cannot be applied to type `&T` +} + +fn main() { + let a = (0..30).collect::>(); + + for k in func(&a) { + println!("{}", k); + } +} From d76bf3ed80b0f6d6fb44704f98df1067353de300 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Wed, 7 Sep 2016 22:24:01 +0000 Subject: [PATCH 253/443] Strip unconfigured nodes in the `InvocationCollector` fold. --- src/libsyntax/config.rs | 12 +++--- src/libsyntax/ext/expand.rs | 73 ++++++++++++++++++++++++++++++------- src/libsyntax/lib.rs | 1 + 3 files changed, 67 insertions(+), 19 deletions(-) diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs index 07604bffa1c6..3f5b294cc044 100644 --- a/src/libsyntax/config.rs +++ b/src/libsyntax/config.rs @@ -70,7 +70,7 @@ macro_rules! configure { } impl<'a> StripUnconfigured<'a> { - fn configure(&mut self, node: T) -> Option { + pub fn configure(&mut self, node: T) -> Option { let node = self.process_cfg_attrs(node); if self.in_cfg(node.attrs()) { Some(node) } else { None } } @@ -166,7 +166,7 @@ impl<'a> StripUnconfigured<'a> { } } - fn configure_foreign_mod(&mut self, foreign_mod: ast::ForeignMod) -> ast::ForeignMod { + pub fn configure_foreign_mod(&mut self, foreign_mod: ast::ForeignMod) -> ast::ForeignMod { ast::ForeignMod { abi: foreign_mod.abi, items: foreign_mod.items.into_iter().filter_map(|item| self.configure(item)).collect(), @@ -187,7 +187,7 @@ impl<'a> StripUnconfigured<'a> { } } - fn configure_item_kind(&mut self, item: ast::ItemKind) -> ast::ItemKind { + pub fn configure_item_kind(&mut self, item: ast::ItemKind) -> ast::ItemKind { match item { ast::ItemKind::Struct(def, generics) => { ast::ItemKind::Struct(self.configure_variant_data(def), generics) @@ -217,7 +217,7 @@ impl<'a> StripUnconfigured<'a> { } } - fn configure_expr_kind(&mut self, expr_kind: ast::ExprKind) -> ast::ExprKind { + pub fn configure_expr_kind(&mut self, expr_kind: ast::ExprKind) -> ast::ExprKind { if let ast::ExprKind::Match(m, arms) = expr_kind { let arms = arms.into_iter().filter_map(|a| self.configure(a)).collect(); ast::ExprKind::Match(m, arms) @@ -226,7 +226,7 @@ impl<'a> StripUnconfigured<'a> { } } - fn configure_expr(&mut self, expr: P) -> P { + pub fn configure_expr(&mut self, expr: P) -> P { self.visit_stmt_or_expr_attrs(expr.attrs()); // If an expr is valid to cfg away it will have been removed by the @@ -244,7 +244,7 @@ impl<'a> StripUnconfigured<'a> { self.process_cfg_attrs(expr) } - fn configure_stmt(&mut self, stmt: ast::Stmt) -> Option { + pub fn configure_stmt(&mut self, stmt: ast::Stmt) -> Option { self.visit_stmt_or_expr_attrs(stmt.attrs()); self.configure(stmt) } diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 0986d32ff56a..68aca3ee32f9 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -208,14 +208,23 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } fn collect_invocations(&mut self, expansion: Expansion) -> (Expansion, Vec) { - let expansion = expansion.fold_with(&mut StripUnconfigured { - config: &self.cx.cfg, - should_test: self.cx.ecfg.should_test, - sess: self.cx.parse_sess, - features: self.cx.ecfg.features, - }); - let mut collector = InvocationCollector { cx: self.cx, invocations: Vec::new() }; - (expansion.fold_with(&mut collector), collector.invocations) + let crate_config = mem::replace(&mut self.cx.cfg, Vec::new()); + let result = { + let mut collector = InvocationCollector { + cfg: StripUnconfigured { + config: &crate_config, + should_test: self.cx.ecfg.should_test, + sess: self.cx.parse_sess, + features: self.cx.ecfg.features, + }, + cx: self.cx, + invocations: Vec::new(), + }; + (expansion.fold_with(&mut collector), collector.invocations) + }; + + self.cx.cfg = crate_config; + result } fn expand_invoc(&mut self, invoc: Invocation) -> Expansion { @@ -403,9 +412,19 @@ impl<'a, 'b> MacroExpander<'a, 'b> { struct InvocationCollector<'a, 'b: 'a> { cx: &'a mut ExtCtxt<'b>, + cfg: StripUnconfigured<'a>, invocations: Vec, } +macro_rules! fully_configure { + ($this:ident, $node:ident, $noop_fold:ident) => { + match $noop_fold($node, &mut $this.cfg).pop() { + Some(node) => node, + None => return SmallVector::zero(), + } + } +} + impl<'a, 'b> InvocationCollector<'a, 'b> { fn collect(&mut self, expansion_kind: ExpansionKind, kind: InvocationKind) -> Expansion { let mark = Mark::fresh(); @@ -475,11 +494,17 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { } false } + + fn configure(&mut self, node: T) -> Option { + self.cfg.configure(node) + } } impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { fn fold_expr(&mut self, expr: P) -> P { - let expr = expr.unwrap(); + let mut expr = self.cfg.configure_expr(expr).unwrap(); + expr.node = self.cfg.configure_expr_kind(expr.node); + if let ast::ExprKind::Mac(mac) = expr.node { self.collect_bang(mac, expr.attrs.into(), expr.span, ExpansionKind::Expr).make_expr() } else { @@ -488,7 +513,9 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { } fn fold_opt_expr(&mut self, expr: P) -> Option> { - let expr = expr.unwrap(); + let mut expr = configure!(self, expr).unwrap(); + expr.node = self.cfg.configure_expr_kind(expr.node); + if let ast::ExprKind::Mac(mac) = expr.node { self.collect_bang(mac, expr.attrs.into(), expr.span, ExpansionKind::OptExpr) .make_opt_expr() @@ -511,6 +538,11 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { } fn fold_stmt(&mut self, stmt: ast::Stmt) -> SmallVector { + let stmt = match self.cfg.configure_stmt(stmt) { + Some(stmt) => stmt, + None => return SmallVector::zero(), + }; + let (mac, style, attrs) = match stmt.node { StmtKind::Mac(mac) => mac.unwrap(), _ => return noop_fold_stmt(stmt, self), @@ -540,9 +572,11 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { } fn fold_item(&mut self, item: P) -> SmallVector> { + let item = configure!(self, item); + let (item, attr) = self.classify_item(item); if let Some(attr) = attr { - let item = Annotatable::Item(item); + let item = Annotatable::Item(fully_configure!(self, item, noop_fold_item)); return self.collect_attr(attr, item, ExpansionKind::Items).make_items(); } @@ -610,9 +644,12 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { } fn fold_trait_item(&mut self, item: ast::TraitItem) -> SmallVector { + let item = configure!(self, item); + let (item, attr) = self.classify_item(item); if let Some(attr) = attr { - let item = Annotatable::TraitItem(P(item)); + let item = + Annotatable::TraitItem(P(fully_configure!(self, item, noop_fold_trait_item))); return self.collect_attr(attr, item, ExpansionKind::TraitItems).make_trait_items() } @@ -626,9 +663,11 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { } fn fold_impl_item(&mut self, item: ast::ImplItem) -> SmallVector { + let item = configure!(self, item); + let (item, attr) = self.classify_item(item); if let Some(attr) = attr { - let item = Annotatable::ImplItem(P(item)); + let item = Annotatable::ImplItem(P(fully_configure!(self, item, noop_fold_impl_item))); return self.collect_attr(attr, item, ExpansionKind::ImplItems).make_impl_items(); } @@ -653,6 +692,14 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { _ => unreachable!(), } } + + fn fold_foreign_mod(&mut self, foreign_mod: ast::ForeignMod) -> ast::ForeignMod { + noop_fold_foreign_mod(self.cfg.configure_foreign_mod(foreign_mod), self) + } + + fn fold_item_kind(&mut self, item: ast::ItemKind) -> ast::ItemKind { + noop_fold_item_kind(self.cfg.configure_item_kind(item), self) + } } pub struct ExpansionConfig<'feat> { diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index 42201231247a..4a2c9aff2d2b 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -104,6 +104,7 @@ pub mod abi; pub mod ast; pub mod attr; pub mod codemap; +#[macro_use] pub mod config; pub mod entry; pub mod feature_gate; From 2d759046ba685f419b3de79367e5b973c1b84105 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Fri, 2 Sep 2016 03:35:59 +0000 Subject: [PATCH 254/443] Implement stackless placeholder expansion. --- src/libsyntax/ext/expand.rs | 19 +++++++++++++++---- src/libsyntax/ext/placeholders.rs | 11 +++++++---- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 68aca3ee32f9..c5b637a98000 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -26,7 +26,6 @@ use ptr::P; use tokenstream::TokenTree; use util::small_vector::SmallVector; -use std::collections::HashMap; use std::mem; use std::path::PathBuf; use std::rc::Rc; @@ -182,10 +181,11 @@ impl<'a, 'b> MacroExpander<'a, 'b> { // Fully expand all the invocations in `expansion`. fn expand(&mut self, expansion: Expansion) -> Expansion { + self.cx.recursion_count = 0; let (expansion, mut invocations) = self.collect_invocations(expansion); invocations.reverse(); - let mut expansions = HashMap::new(); + let mut expansions = vec![vec![(0, expansion)]]; while let Some(invoc) = invocations.pop() { let Invocation { mark, module, depth, backtrace, .. } = invoc; self.cx.syntax_env.current_module = module; @@ -198,13 +198,24 @@ impl<'a, 'b> MacroExpander<'a, 'b> { self.cx.recursion_count = depth + 1; let (expansion, new_invocations) = self.collect_invocations(expansion); - expansions.insert(mark.as_u32(), expansion); + if expansions.len() == depth { + expansions.push(Vec::new()); + } + expansions[depth].push((mark.as_u32(), expansion)); if !self.single_step { invocations.extend(new_invocations.into_iter().rev()); } } - expansion.fold_with(&mut PlaceholderExpander::new(expansions)) + let mut placeholder_expander = PlaceholderExpander::new(); + while let Some(expansions) = expansions.pop() { + for (mark, expansion) in expansions.into_iter().rev() { + let expansion = expansion.fold_with(&mut placeholder_expander); + placeholder_expander.add(mark, expansion); + } + } + + placeholder_expander.remove(0) } fn collect_invocations(&mut self, expansion: Expansion) -> (Expansion, Vec) { diff --git a/src/libsyntax/ext/placeholders.rs b/src/libsyntax/ext/placeholders.rs index f1665bdde751..abadcf867b14 100644 --- a/src/libsyntax/ext/placeholders.rs +++ b/src/libsyntax/ext/placeholders.rs @@ -74,15 +74,18 @@ pub struct PlaceholderExpander { } impl PlaceholderExpander { - pub fn new(expansions: HashMap) -> Self { + pub fn new() -> Self { PlaceholderExpander { - expansions: expansions, + expansions: HashMap::new(), } } + pub fn add(&mut self, id: ast::NodeId, expansion: Expansion) { + self.expansions.insert(id, expansion); + } + pub fn remove(&mut self, id: ast::NodeId) -> Expansion { - let expansion = self.expansions.remove(&id).unwrap(); - expansion.fold_with(self) + self.expansions.remove(&id).unwrap() } } From 9ac91fa48b3eb479cccb5695395faed8f59ece8e Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Mon, 5 Sep 2016 04:08:38 +0000 Subject: [PATCH 255/443] Improve `directory` computation during invocation collection. --- src/libsyntax/ext/expand.rs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index c5b637a98000..4715eda83749 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -615,16 +615,20 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { ast::ItemKind::Mod(ast::Mod { inner, .. }) => { let mut paths = (*self.cx.syntax_env.paths()).clone(); paths.mod_path.push(item.ident); - if item.span.contains(inner) { + + // Detect if this is an inline module (`mod m { ... }` as opposed to `mod m;`). + // In the non-inline case, `inner` is never the dummy span (c.f. `parse_item_mod`). + // Thus, if `inner` is the dummy span, we know the module is inline. + let inline_module = item.span.contains(inner) || inner == syntax_pos::DUMMY_SP; + + if inline_module { paths.directory.push(&*{ ::attr::first_attr_value_str_by_name(&item.attrs, "path") .unwrap_or(item.ident.name.as_str()) }); } else { - paths.directory = match inner { - syntax_pos::DUMMY_SP => PathBuf::new(), - _ => PathBuf::from(self.cx.parse_sess.codemap().span_to_filename(inner)), - }; + paths.directory = + PathBuf::from(self.cx.parse_sess.codemap().span_to_filename(inner)); paths.directory.pop(); } From a2faf5477c46e425d02b48ec0be6eea49c694fc2 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 8 Sep 2016 01:16:06 +0200 Subject: [PATCH 256/443] Set run button transparent instead of invisible --- src/librustdoc/html/highlight.rs | 6 +++++- src/librustdoc/html/markdown.rs | 8 +++++--- src/librustdoc/html/render.rs | 3 ++- src/librustdoc/html/static/playpen.js | 15 +-------------- src/librustdoc/html/static/rustdoc.css | 5 ++++- 5 files changed, 17 insertions(+), 20 deletions(-) diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index 6cb79d6e8630..855588a4c3a4 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -33,7 +33,8 @@ use syntax::parse; use syntax_pos::Span; /// Highlights `src`, returning the HTML output. -pub fn render_with_highlighting(src: &str, class: Option<&str>, id: Option<&str>) -> String { +pub fn render_with_highlighting(src: &str, class: Option<&str>, id: Option<&str>, + extension: Option<&str>) -> String { debug!("highlighting: ================\n{}\n==============", src); let sess = parse::ParseSess::new(); let fm = sess.codemap().new_filemap("".to_string(), None, src.to_string()); @@ -47,6 +48,9 @@ pub fn render_with_highlighting(src: &str, class: Option<&str>, id: Option<&str> return format!("
{}
", src); } + if let Some(extension) = extension { + write!(out, "{}", extension).unwrap(); + } write_footer(&mut out).unwrap(); String::from_utf8_lossy(&out[..]).into_owned() } diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 139e1033175e..aff5a964f75c 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -262,9 +262,11 @@ pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool) -> fmt::Result { &Default::default()); s.push_str(&format!("{}", Escape(&test))); }); - s.push_str(&highlight::render_with_highlighting(&text, - Some("rust-example-rendered"), - None)); + s.push_str(&highlight::render_with_highlighting( + &text, + Some("rust-example-rendered"), + None, + Some("
Run"))); let output = CString::new(s).unwrap(); hoedown_buffer_puts(ob, output.as_ptr()); }) diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 4c6ac56105c6..147710c39f47 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -2909,7 +2909,7 @@ impl<'a> fmt::Display for Source<'a> { write!(fmt, "{0:1$}\n", i, cols)?; } write!(fmt, "

")?; - write!(fmt, "{}", highlight::render_with_highlighting(s, None, None))?; + write!(fmt, "{}", highlight::render_with_highlighting(s, None, None, None))?; Ok(()) } } @@ -2918,6 +2918,7 @@ fn item_macro(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, t: &clean::Macro) -> fmt::Result { w.write_str(&highlight::render_with_highlighting(&t.source, Some("macro"), + None, None))?; render_stability_since_raw(w, it.stable_since(), None)?; document(w, cx, it) diff --git a/src/librustdoc/html/static/playpen.js b/src/librustdoc/html/static/playpen.js index 8f8a753b06c9..cad97c04e1ac 100644 --- a/src/librustdoc/html/static/playpen.js +++ b/src/librustdoc/html/static/playpen.js @@ -27,9 +27,7 @@ document.addEventListener('DOMContentLoaded', function() { return; } - var a = document.createElement('a'); - a.setAttribute('class', 'test-arrow'); - a.textContent = 'Run'; + var a = el.querySelectorAll('a.test-arrow')[0]; var code = el.previousElementSibling.textContent; @@ -40,17 +38,6 @@ document.addEventListener('DOMContentLoaded', function() { a.setAttribute('href', window.playgroundUrl + '?code=' + encodeURIComponent(code) + channel); - a.setAttribute('target', '_blank'); - - el.appendChild(a); - }; - - el.onmouseout = function(e) { - if (el.contains(e.relatedTarget)) { - return; - } - - el.removeChild(el.querySelectorAll('a.test-arrow')[0]); }; }); }); diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index c97cacd10c38..2884320b82eb 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -568,15 +568,18 @@ pre.rust .lifetime { color: #B76514; } .rusttest { display: none; } pre.rust { position: relative; } a.test-arrow { + background-color: rgba(78, 139, 202, 0.2); display: inline-block; position: absolute; - background-color: #4e8bca; padding: 5px 10px 5px 10px; border-radius: 5px; font-size: 130%; top: 5px; right: 5px; } +a.test-arrow:hover{ + background-color: #4e8bca; +} .section-header:hover a:after { content: '\2002\00a7\2002'; From a25428269d8cac3ef00162a19dcbb5d5d5c47192 Mon Sep 17 00:00:00 2001 From: Jared Roesch Date: Wed, 7 Sep 2016 17:22:19 -0700 Subject: [PATCH 257/443] Fix duplicate error code --- src/librustc_typeck/check/wfcheck.rs | 4 ++-- src/librustc_typeck/diagnostics.rs | 4 ++-- .../traits-inductive-overflow-supertrait-oibit.rs | 2 +- src/test/compile-fail/typeck-auto-trait-no-supertraits-2.rs | 4 ++-- src/test/compile-fail/typeck-auto-trait-no-supertraits.rs | 6 +++--- src/test/compile-fail/typeck-auto-trait-no-typeparams.rs | 2 +- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 6e39e33c9a8d..0fe703aca79b 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -300,11 +300,11 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { if !items.is_empty() { error_380(self.ccx, span); } else if has_ty_params { - err = Some(struct_span_err!(self.tcx().sess, span, E0566, + err = Some(struct_span_err!(self.tcx().sess, span, E0567, "traits with auto impls (`e.g. impl \ Trait for ..`) can not have type parameters")); } else if has_predicates { - err = Some(struct_span_err!(self.tcx().sess, span, E0565, + err = Some(struct_span_err!(self.tcx().sess, span, E0568, "traits with auto impls (`e.g. impl \ Trait for ..`) cannot have predicates")); } diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 7b7b4d2aa00f..e5c901f223ff 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -4072,6 +4072,6 @@ register_diagnostics! { E0563, // cannot determine a type for this `impl Trait`: {} E0564, // only named lifetimes are allowed in `impl Trait`, // but `{}` was found in the type `{}` - E0565, // auto-traits can not have predicates, - E0566, // auto traits can not have type parameters + E0567, // auto traits can not have type parameters + E0568, // auto-traits can not have predicates, } diff --git a/src/test/compile-fail/traits-inductive-overflow-supertrait-oibit.rs b/src/test/compile-fail/traits-inductive-overflow-supertrait-oibit.rs index 168148b92fe4..fe0e583b20a3 100644 --- a/src/test/compile-fail/traits-inductive-overflow-supertrait-oibit.rs +++ b/src/test/compile-fail/traits-inductive-overflow-supertrait-oibit.rs @@ -14,7 +14,7 @@ #![feature(optin_builtin_traits)] -trait Magic: Copy {} //~ ERROR E0565 +trait Magic: Copy {} //~ ERROR E0568 impl Magic for .. {} fn copy(x: T) -> (T, T) { (x, x) } diff --git a/src/test/compile-fail/typeck-auto-trait-no-supertraits-2.rs b/src/test/compile-fail/typeck-auto-trait-no-supertraits-2.rs index 60da647f6824..f6678ac7c2d8 100644 --- a/src/test/compile-fail/typeck-auto-trait-no-supertraits-2.rs +++ b/src/test/compile-fail/typeck-auto-trait-no-supertraits-2.rs @@ -10,8 +10,8 @@ #![feature(optin_builtin_traits)] -trait Magic : Sized where Option : Magic {} //~ ERROR E0565 -impl Magic for .. {} +trait Magic : Sized where Option : Magic {} //~ ERROR E0568 +impl Magic for .. {} impl Magic for T {} fn copy(x: T) -> (T, T) { (x, x) } diff --git a/src/test/compile-fail/typeck-auto-trait-no-supertraits.rs b/src/test/compile-fail/typeck-auto-trait-no-supertraits.rs index 177d594da18a..9497dfb39d7d 100644 --- a/src/test/compile-fail/typeck-auto-trait-no-supertraits.rs +++ b/src/test/compile-fail/typeck-auto-trait-no-supertraits.rs @@ -23,7 +23,7 @@ // type that contains a mutable reference, enabling // mutable aliasing. // -// You can imagine an even more dangerous test, +// You can imagine an even more dangerous test, // which currently compiles on nightly. // // fn main() { @@ -34,8 +34,8 @@ #![feature(optin_builtin_traits)] -trait Magic: Copy {} //~ ERROR E0565 -impl Magic for .. {} +trait Magic: Copy {} //~ ERROR E0568 +impl Magic for .. {} impl Magic for T {} fn copy(x: T) -> (T, T) { (x, x) } diff --git a/src/test/compile-fail/typeck-auto-trait-no-typeparams.rs b/src/test/compile-fail/typeck-auto-trait-no-typeparams.rs index f2841a413db9..5a852c54869a 100644 --- a/src/test/compile-fail/typeck-auto-trait-no-typeparams.rs +++ b/src/test/compile-fail/typeck-auto-trait-no-typeparams.rs @@ -10,5 +10,5 @@ #![feature(optin_builtin_traits)] -trait Magic {} //~ ERROR E0566 +trait Magic {} //~ ERROR E0567 impl Magic for .. {} From e0eea8b7c1fbf2247694a94e216c239e0ec285b1 Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Thu, 8 Sep 2016 07:26:55 +0200 Subject: [PATCH 258/443] =?UTF-8?q?warning=20=E2=86=92=20error,=20lowercas?= =?UTF-8?q?e?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/librustc_typeck/rscope.rs | 6 +++--- src/test/compile-fail/const-unsized.rs | 4 ++-- src/test/compile-fail/issue-24446.rs | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/librustc_typeck/rscope.rs b/src/librustc_typeck/rscope.rs index 5b00a625bacf..be44dce8a8ac 100644 --- a/src/librustc_typeck/rscope.rs +++ b/src/librustc_typeck/rscope.rs @@ -243,9 +243,9 @@ impl<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> RegionScope for StaticRscope<'a, 'gcx, 'tcx> if !self.tcx.sess.features.borrow().static_in_const { self.tcx .sess - .struct_span_warn(span, - "This needs a `'static` lifetime or the \ - `static_in_const` feature, see #35897") + .struct_span_err(span, + "this needs a `'static` lifetime or the \ + `static_in_const` feature, see #35897") .emit(); } ty::ReStatic diff --git a/src/test/compile-fail/const-unsized.rs b/src/test/compile-fail/const-unsized.rs index 07d6edb1f3b1..d3c0bf002135 100644 --- a/src/test/compile-fail/const-unsized.rs +++ b/src/test/compile-fail/const-unsized.rs @@ -15,7 +15,7 @@ const CONST_0: Debug+Sync = *(&0 as &(Debug+Sync)); //~| NOTE `std::fmt::Debug + Sync + 'static: std::marker::Sized` not satisfied //~| NOTE does not have a constant size known at compile-time //~| NOTE constant expressions must have a statically known size -//~| WARNING This needs a `'static` lifetime or the `static_in_const` feature +//~| ERROR this needs a `'static` lifetime or the `static_in_const` feature const CONST_FOO: str = *"foo"; //~^ ERROR `str: std::marker::Sized` is not satisfied @@ -28,7 +28,7 @@ static STATIC_1: Debug+Sync = *(&1 as &(Debug+Sync)); //~| NOTE `std::fmt::Debug + Sync + 'static: std::marker::Sized` not satisfied //~| NOTE does not have a constant size known at compile-time //~| NOTE constant expressions must have a statically known size -//~| WARNING This needs a `'static` lifetime or the `static_in_const` feature +//~| ERROR this needs a `'static` lifetime or the `static_in_const` feature static STATIC_BAR: str = *"bar"; //~^ ERROR `str: std::marker::Sized` is not satisfied diff --git a/src/test/compile-fail/issue-24446.rs b/src/test/compile-fail/issue-24446.rs index d721c8bb6d2b..bcc1d3c3e42d 100644 --- a/src/test/compile-fail/issue-24446.rs +++ b/src/test/compile-fail/issue-24446.rs @@ -12,7 +12,7 @@ fn main() { static foo: Fn() -> u32 = || -> u32 { //~^ ERROR: mismatched types //~| ERROR: `std::ops::Fn() -> u32 + 'static: std::marker::Sized` is not satisfied - //~| WARNING: This needs a `'static` lifetime or the `static_in_const` feature + //~| ERROR: this needs a `'static` lifetime or the `static_in_const` feature 0 }; } From 2859177ea0f36863672e05b8be044b4c94cfd8f1 Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Thu, 8 Sep 2016 07:29:37 +0200 Subject: [PATCH 259/443] added feature gate test --- .../compile-fail/feature-gate-static-in-const.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 src/test/compile-fail/feature-gate-static-in-const.rs diff --git a/src/test/compile-fail/feature-gate-static-in-const.rs b/src/test/compile-fail/feature-gate-static-in-const.rs new file mode 100644 index 000000000000..c1fc7cdd06cd --- /dev/null +++ b/src/test/compile-fail/feature-gate-static-in-const.rs @@ -0,0 +1,14 @@ +// 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. + +static FOO: &str = "this will work once static_in_const is stable"; +//~^ ERROR: this needs a `'static` lifetime or the `static_in_const` feature + +fn main() {} From df611a62bb4407373bea42d2fb623e6579972521 Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Thu, 8 Sep 2016 07:34:41 +0200 Subject: [PATCH 260/443] added feature description to reference --- src/doc/reference.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/doc/reference.md b/src/doc/reference.md index f29cdf6b0803..b72c3743a69c 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -2441,6 +2441,9 @@ The currently implemented features of the reference compiler are: into a Rust program. This capability, especially the signature for the annotated function, is subject to change. +* `static_in_const` - Enables lifetime elision with a `'static` default for + `const` and `static` item declarations. + * `thread_local` - The usage of the `#[thread_local]` attribute is experimental and should be seen as unstable. This attribute is used to declare a `static` as being unique per-thread leveraging From 8c9571279dbdfa509ca2c3e81527457cc9ae169f Mon Sep 17 00:00:00 2001 From: Seo Sanghyeon Date: Thu, 8 Sep 2016 18:43:21 +0900 Subject: [PATCH 261/443] Use LLVM_COMPONENTS to run tests just for supported targets --- src/test/run-make/atomic-lock-free/Makefile | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/test/run-make/atomic-lock-free/Makefile b/src/test/run-make/atomic-lock-free/Makefile index 78e7bb231372..3021555f39d8 100644 --- a/src/test/run-make/atomic-lock-free/Makefile +++ b/src/test/run-make/atomic-lock-free/Makefile @@ -5,22 +5,31 @@ all: ifeq ($(UNAME),Linux) +ifeq ($(filter x86,$(LLVM_COMPONENTS)),x86) $(RUSTC) --target=i686-unknown-linux-gnu atomic_lock_free.rs nm "$(TMPDIR)/libatomic_lock_free.rlib" | grep -vq __atomic_fetch_add $(RUSTC) --target=x86_64-unknown-linux-gnu atomic_lock_free.rs nm "$(TMPDIR)/libatomic_lock_free.rlib" | grep -vq __atomic_fetch_add +endif +ifeq ($(filter arm,$(LLVM_COMPONENTS)),arm) $(RUSTC) --target=arm-unknown-linux-gnueabi atomic_lock_free.rs nm "$(TMPDIR)/libatomic_lock_free.rlib" | grep -vq __atomic_fetch_add $(RUSTC) --target=arm-unknown-linux-gnueabihf atomic_lock_free.rs nm "$(TMPDIR)/libatomic_lock_free.rlib" | grep -vq __atomic_fetch_add $(RUSTC) --target=armv7-unknown-linux-gnueabihf atomic_lock_free.rs nm "$(TMPDIR)/libatomic_lock_free.rlib" | grep -vq __atomic_fetch_add +endif +ifeq ($(filter aarch64,$(LLVM_COMPONENTS)),aarch64) $(RUSTC) --target=aarch64-unknown-linux-gnu atomic_lock_free.rs nm "$(TMPDIR)/libatomic_lock_free.rlib" | grep -vq __atomic_fetch_add +endif +ifeq ($(filter mips,$(LLVM_COMPONENTS)),mips) $(RUSTC) --target=mips-unknown-linux-gnu atomic_lock_free.rs nm "$(TMPDIR)/libatomic_lock_free.rlib" | grep -vq __atomic_fetch_add $(RUSTC) --target=mipsel-unknown-linux-gnu atomic_lock_free.rs nm "$(TMPDIR)/libatomic_lock_free.rlib" | grep -vq __atomic_fetch_add +endif +ifeq ($(filter powerpc,$(LLVM_COMPONENTS)),powerpc) $(RUSTC) --target=powerpc-unknown-linux-gnu atomic_lock_free.rs nm "$(TMPDIR)/libatomic_lock_free.rlib" | grep -vq __atomic_fetch_add $(RUSTC) --target=powerpc64-unknown-linux-gnu atomic_lock_free.rs @@ -28,3 +37,4 @@ ifeq ($(UNAME),Linux) $(RUSTC) --target=powerpc64le-unknown-linux-gnu atomic_lock_free.rs nm "$(TMPDIR)/libatomic_lock_free.rlib" | grep -vq __atomic_fetch_add endif +endif From a3f05cec762948e68d2f5cc29003781f44f79820 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Thu, 8 Sep 2016 12:58:05 +0200 Subject: [PATCH 262/443] clean up `get_vtable`'s doc comment --- src/librustc_trans/meth.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/librustc_trans/meth.rs b/src/librustc_trans/meth.rs index e958795570ee..ee2f24d21e07 100644 --- a/src/librustc_trans/meth.rs +++ b/src/librustc_trans/meth.rs @@ -116,9 +116,11 @@ pub fn trans_object_shim<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>, llfn } -/// Creates a returns a dynamic vtable for the given type and vtable origin. +/// Creates a dynamic vtable for the given type and vtable origin. /// This is used only for objects. /// +/// The vtables are cached instead of created on every call. +/// /// The `trait_ref` encodes the erased self type. Hence if we are /// making an object `Foo` from a value of type `Foo`, then /// `trait_ref` would map `T:Trait`. From d4c6a61c44bdf470a88a7a24d83cfd31f9b70992 Mon Sep 17 00:00:00 2001 From: ggomez Date: Thu, 8 Sep 2016 16:08:47 +0200 Subject: [PATCH 263/443] Ignore this block code because of OSX failure --- src/librustc_metadata/diagnostics.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc_metadata/diagnostics.rs b/src/librustc_metadata/diagnostics.rs index 01c7d7fc79d5..f52e1437acc9 100644 --- a/src/librustc_metadata/diagnostics.rs +++ b/src/librustc_metadata/diagnostics.rs @@ -32,8 +32,8 @@ as frameworks are specific to that operating system. Erroneous code example: -```compile_fail,E0455 -#[link(name = "FooCoreServices", kind = "framework")] extern {} +```ignore +#[link(name = "FooCoreServices", kind = "framework")] extern {} // OS used to compile is Linux for example ``` From dd570d64be6f95d601d5104d93207538b236f7cd Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Thu, 8 Sep 2016 19:18:07 +0200 Subject: [PATCH 264/443] For size of `struct P(Q)`, don't double-count the prefix added by `Q`. Fix #36278. Fix #36294. --- src/librustc_trans/glue.rs | 13 ++++++++- .../run-pass/issue-36278-prefix-nesting.rs | 28 +++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 src/test/run-pass/issue-36278-prefix-nesting.rs diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs index 34c92f334d0a..967ecd9ba416 100644 --- a/src/librustc_trans/glue.rs +++ b/src/librustc_trans/glue.rs @@ -348,9 +348,20 @@ pub fn size_and_align_of_dst<'blk, 'tcx>(bcx: &BlockAndBuilder<'blk, 'tcx>, let layout = ccx.layout_of(t); debug!("DST {} layout: {:?}", t, layout); + // Returns size in bytes of all fields except the last one + // (we will be recursing on the last one). + fn local_prefix_bytes(variant: &ty::layout::Struct) -> u64 { + let fields = variant.offset_after_field.len(); + if fields > 1 { + variant.offset_after_field[fields - 2].bytes() + } else { + 0 + } + } + let (sized_size, sized_align) = match *layout { ty::layout::Layout::Univariant { ref variant, .. } => { - (variant.min_size().bytes(), variant.align.abi()) + (local_prefix_bytes(variant), variant.align.abi()) } _ => { bug!("size_and_align_of_dst: expcted Univariant for `{}`, found {:#?}", diff --git a/src/test/run-pass/issue-36278-prefix-nesting.rs b/src/test/run-pass/issue-36278-prefix-nesting.rs new file mode 100644 index 000000000000..95269d0569de --- /dev/null +++ b/src/test/run-pass/issue-36278-prefix-nesting.rs @@ -0,0 +1,28 @@ +// 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. + +// Issue 36278: On an unsized struct with >1 level of nontrivial +// nesting, ensure we are computing dynamic size of prefix correctly. + +use std::mem; + +const SZ: usize = 100; +struct P([u8; SZ], T); + +type Ack = P>; + +fn main() { + let size_of_sized; let size_of_unsized; + let x: Box> = Box::new(P([0; SZ], P([0; SZ], [0; 0]))); + size_of_sized = mem::size_of_val::>(&x); + let y: Box> = x; + size_of_unsized = mem::size_of_val::>(&y); + assert_eq!(size_of_sized, size_of_unsized); +} From 707a40f2065cb46d12c4f4991e6408585b315c92 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 8 Sep 2016 10:41:48 -0700 Subject: [PATCH 265/443] Point compile-fail errors to the input item instead of the derive --- src/test/compile-fail-fulldeps/rustc-macro/append-impl.rs | 2 +- .../compile-fail-fulldeps/rustc-macro/expand-to-unstable-2.rs | 2 +- .../compile-fail-fulldeps/rustc-macro/expand-to-unstable.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/compile-fail-fulldeps/rustc-macro/append-impl.rs b/src/test/compile-fail-fulldeps/rustc-macro/append-impl.rs index fa0b5763803f..1300fe66585c 100644 --- a/src/test/compile-fail-fulldeps/rustc-macro/append-impl.rs +++ b/src/test/compile-fail-fulldeps/rustc-macro/append-impl.rs @@ -23,8 +23,8 @@ trait Append { #[derive(PartialEq, Append, Eq)] -//~^^ ERROR: the semantics of constant patterns is not yet settled struct A { +//~^ ERROR: the semantics of constant patterns is not yet settled inner: u32, } diff --git a/src/test/compile-fail-fulldeps/rustc-macro/expand-to-unstable-2.rs b/src/test/compile-fail-fulldeps/rustc-macro/expand-to-unstable-2.rs index 29b9fd228094..14c3d84e75be 100644 --- a/src/test/compile-fail-fulldeps/rustc-macro/expand-to-unstable-2.rs +++ b/src/test/compile-fail-fulldeps/rustc-macro/expand-to-unstable-2.rs @@ -17,8 +17,8 @@ extern crate derive_unstable_2; #[derive(Unstable)] -//~^ ERROR: reserved for internal compiler struct A; +//~^ ERROR: reserved for internal compiler fn main() { foo(); diff --git a/src/test/compile-fail-fulldeps/rustc-macro/expand-to-unstable.rs b/src/test/compile-fail-fulldeps/rustc-macro/expand-to-unstable.rs index 874081760f66..aa9aaa811562 100644 --- a/src/test/compile-fail-fulldeps/rustc-macro/expand-to-unstable.rs +++ b/src/test/compile-fail-fulldeps/rustc-macro/expand-to-unstable.rs @@ -17,8 +17,8 @@ extern crate derive_unstable; #[derive(Unstable)] -//~^ ERROR: use of unstable library feature struct A; +//~^ ERROR: use of unstable library feature fn main() { unsafe { foo(); } From f2b672d5567c3b20542e845baaf8a9c47d9df907 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Tue, 6 Sep 2016 01:26:02 +0300 Subject: [PATCH 266/443] Refactor `TyStruct`/`TyEnum`/`TyUnion` into `TyAdt` --- src/librustc/infer/error_reporting.rs | 5 +- src/librustc/infer/freshen.rs | 4 +- src/librustc/middle/dead.rs | 23 +- src/librustc/middle/effect.rs | 14 +- src/librustc/middle/expr_use_visitor.rs | 43 +- src/librustc/middle/mem_categorization.rs | 5 +- src/librustc/middle/stability.rs | 62 ++- src/librustc/mir/tcx.rs | 7 +- src/librustc/traits/coherence.rs | 6 +- src/librustc/traits/error_reporting.rs | 38 +- src/librustc/traits/select.rs | 16 +- src/librustc/ty/cast.rs | 2 +- src/librustc/ty/contents.rs | 3 +- src/librustc/ty/context.rs | 22 +- src/librustc/ty/error.rs | 8 +- src/librustc/ty/fast_reject.rs | 14 +- src/librustc/ty/flags.rs | 2 +- src/librustc/ty/item_path.rs | 8 +- src/librustc/ty/layout.rs | 446 +++++++++--------- src/librustc/ty/mod.rs | 44 +- src/librustc/ty/outlives.rs | 4 +- src/librustc/ty/relate.rs | 18 +- src/librustc/ty/structural_impls.rs | 8 +- src/librustc/ty/sty.rs | 43 +- src/librustc/ty/util.rs | 118 ++--- src/librustc/ty/walk.rs | 5 +- src/librustc/ty/wf.rs | 4 +- src/librustc/util/ppaux.rs | 4 +- src/librustc_borrowck/borrowck/check_loans.rs | 4 +- src/librustc_borrowck/borrowck/fragments.rs | 101 ++-- .../borrowck/gather_loans/gather_moves.rs | 2 +- .../borrowck/gather_loans/move_error.rs | 4 +- .../borrowck/gather_loans/restrictions.rs | 9 +- .../borrowck/mir/elaborate_drops.rs | 4 +- src/librustc_borrowck/borrowck/mir/mod.rs | 2 +- src/librustc_borrowck/borrowck/move_data.rs | 57 ++- src/librustc_const_eval/check_match.rs | 39 +- src/librustc_const_eval/eval.rs | 15 +- src/librustc_lint/builtin.rs | 6 +- src/librustc_lint/types.rs | 194 ++++---- src/librustc_lint/unused.rs | 4 +- src/librustc_metadata/decoder.rs | 17 +- src/librustc_metadata/tydecode.rs | 18 +- src/librustc_metadata/tyencode.rs | 12 +- src/librustc_mir/build/expr/as_rvalue.rs | 2 +- src/librustc_mir/hair/cx/expr.rs | 89 ++-- src/librustc_mir/hair/cx/pattern.rs | 10 +- src/librustc_mir/transform/type_check.rs | 16 +- src/librustc_passes/consts.rs | 4 +- src/librustc_privacy/lib.rs | 14 +- src/librustc_save_analysis/dump_visitor.rs | 2 +- src/librustc_save_analysis/lib.rs | 10 +- src/librustc_trans/adt.rs | 306 ++++++------ src/librustc_trans/base.rs | 3 +- src/librustc_trans/collector.rs | 12 +- src/librustc_trans/common.rs | 7 +- src/librustc_trans/context.rs | 10 +- src/librustc_trans/debuginfo/metadata.rs | 58 +-- src/librustc_trans/debuginfo/mod.rs | 2 +- src/librustc_trans/debuginfo/type_names.rs | 4 +- src/librustc_trans/glue.rs | 165 +++---- src/librustc_trans/intrinsic.rs | 2 +- src/librustc_trans/trans_item.rs | 4 +- src/librustc_trans/type_of.rs | 14 +- src/librustc_typeck/check/_match.rs | 6 +- src/librustc_typeck/check/cast.rs | 2 +- src/librustc_typeck/check/dropck.rs | 26 +- src/librustc_typeck/check/method/probe.rs | 4 +- src/librustc_typeck/check/method/suggest.rs | 6 +- src/librustc_typeck/check/mod.rs | 38 +- src/librustc_typeck/coherence/mod.rs | 15 +- src/librustc_typeck/coherence/orphan.rs | 15 +- src/librustc_typeck/collect.rs | 14 +- src/librustc_typeck/variance/constraints.rs | 4 +- src/librustdoc/clean/inline.rs | 2 +- src/librustdoc/clean/mod.rs | 14 +- src/test/run-pass/auxiliary/issue13507.rs | 4 +- 77 files changed, 1110 insertions(+), 1238 deletions(-) diff --git a/src/librustc/infer/error_reporting.rs b/src/librustc/infer/error_reporting.rs index 38f3f055cbb2..b8a3bdfcf257 100644 --- a/src/librustc/infer/error_reporting.rs +++ b/src/librustc/infer/error_reporting.rs @@ -488,10 +488,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // if they are both "path types", there's a chance of ambiguity // due to different versions of the same crate match (&exp_found.expected.sty, &exp_found.found.sty) { - (&ty::TyEnum(ref exp_adt, _), &ty::TyEnum(ref found_adt, _)) | - (&ty::TyStruct(ref exp_adt, _), &ty::TyStruct(ref found_adt, _)) | - (&ty::TyEnum(ref exp_adt, _), &ty::TyStruct(ref found_adt, _)) | - (&ty::TyStruct(ref exp_adt, _), &ty::TyEnum(ref found_adt, _)) => { + (&ty::TyAdt(exp_adt, _), &ty::TyAdt(found_adt, _)) => { report_path_match(err, exp_adt.did, found_adt.did); }, _ => () diff --git a/src/librustc/infer/freshen.rs b/src/librustc/infer/freshen.rs index 8aeb0757f5de..eea12b7f1971 100644 --- a/src/librustc/infer/freshen.rs +++ b/src/librustc/infer/freshen.rs @@ -156,7 +156,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> { ty::TyInt(..) | ty::TyUint(..) | ty::TyFloat(..) | - ty::TyEnum(..) | + ty::TyAdt(..) | ty::TyBox(..) | ty::TyStr | ty::TyError | @@ -167,8 +167,6 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> { ty::TyFnDef(..) | ty::TyFnPtr(_) | ty::TyTrait(..) | - ty::TyStruct(..) | - ty::TyUnion(..) | ty::TyClosure(..) | ty::TyNever | ty::TyTuple(..) | diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index 26a89feb2181..9db6ac1dcefd 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -86,8 +86,6 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { } fn lookup_and_handle_definition(&mut self, id: ast::NodeId) { - use ty::TypeVariants::{TyEnum, TyStruct, TyUnion}; - let def = self.tcx.expect_def(id); // If `bar` is a trait item, make sure to mark Foo as alive in `Foo::bar` @@ -95,11 +93,8 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { Def::AssociatedTy(..) | Def::Method(_) | Def::AssociatedConst(_) if self.tcx.trait_of_item(def.def_id()).is_some() => { if let Some(substs) = self.tcx.tables.borrow().item_substs.get(&id) { - match substs.substs.type_at(0).sty { - TyEnum(tyid, _) | TyStruct(tyid, _) | TyUnion(tyid, _) => { - self.check_def_id(tyid.did) - } - _ => {} + if let ty::TyAdt(tyid, _) = substs.substs.type_at(0).sty { + self.check_def_id(tyid.did); } } } @@ -133,23 +128,27 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { fn handle_field_access(&mut self, lhs: &hir::Expr, name: ast::Name) { match self.tcx.expr_ty_adjusted(lhs).sty { - ty::TyStruct(def, _) | ty::TyUnion(def, _) => { + ty::TyAdt(def, _) => { self.insert_def_id(def.struct_variant().field_named(name).did); } - _ => span_bug!(lhs.span, "named field access on non-struct/union"), + _ => span_bug!(lhs.span, "named field access on non-ADT"), } } fn handle_tup_field_access(&mut self, lhs: &hir::Expr, idx: usize) { - if let ty::TyStruct(def, _) = self.tcx.expr_ty_adjusted(lhs).sty { - self.insert_def_id(def.struct_variant().fields[idx].did); + match self.tcx.expr_ty_adjusted(lhs).sty { + ty::TyAdt(def, _) => { + self.insert_def_id(def.struct_variant().fields[idx].did); + } + ty::TyTuple(..) => {} + _ => span_bug!(lhs.span, "numeric field access on non-ADT"), } } fn handle_field_pattern_match(&mut self, lhs: &hir::Pat, pats: &[codemap::Spanned]) { let variant = match self.tcx.node_id_to_type(lhs.id).sty { - ty::TyStruct(adt, _) | ty::TyUnion(adt, _) | ty::TyEnum(adt, _) => { + ty::TyAdt(adt, _) => { adt.variant_of_def(self.tcx.expect_def(lhs.id)) } _ => span_bug!(lhs.span, "non-ADT in struct pattern") diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs index a7af0b50b849..8b8d15b0b6eb 100644 --- a/src/librustc/middle/effect.rs +++ b/src/librustc/middle/effect.rs @@ -178,8 +178,10 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EffectCheckVisitor<'a, 'tcx> { } } hir::ExprField(ref base_expr, field) => { - if let ty::TyUnion(..) = self.tcx.expr_ty_adjusted(base_expr).sty { - self.require_unsafe(field.span, "access to union field"); + if let ty::TyAdt(adt, ..) = self.tcx.expr_ty_adjusted(base_expr).sty { + if adt.is_union() { + self.require_unsafe(field.span, "access to union field"); + } } } _ => {} @@ -190,9 +192,11 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EffectCheckVisitor<'a, 'tcx> { fn visit_pat(&mut self, pat: &hir::Pat) { if let PatKind::Struct(_, ref fields, _) = pat.node { - if let ty::TyUnion(..) = self.tcx.pat_ty(pat).sty { - for field in fields { - self.require_unsafe(field.span, "matching on union field"); + if let ty::TyAdt(adt, ..) = self.tcx.pat_ty(pat).sty { + if adt.is_union() { + for field in fields { + self.require_unsafe(field.span, "matching on union field"); + } } } } diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index d32954d3800a..9f05dde4e66f 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -671,28 +671,31 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { // Select just those fields of the `with` // expression that will actually be used - if let ty::TyStruct(def, substs) = with_cmt.ty.sty { - // Consume those fields of the with expression that are needed. - for with_field in &def.struct_variant().fields { - if !contains_field_named(with_field, fields) { - let cmt_field = self.mc.cat_field( - &*with_expr, - with_cmt.clone(), - with_field.name, - with_field.ty(self.tcx(), substs) - ); - self.delegate_consume(with_expr.id, with_expr.span, cmt_field); + match with_cmt.ty.sty { + ty::TyAdt(adt, substs) if adt.is_struct() => { + // Consume those fields of the with expression that are needed. + for with_field in &adt.struct_variant().fields { + if !contains_field_named(with_field, fields) { + let cmt_field = self.mc.cat_field( + &*with_expr, + with_cmt.clone(), + with_field.name, + with_field.ty(self.tcx(), substs) + ); + self.delegate_consume(with_expr.id, with_expr.span, cmt_field); + } } } - } else { - // the base expression should always evaluate to a - // struct; however, when EUV is run during typeck, it - // may not. This will generate an error earlier in typeck, - // so we can just ignore it. - if !self.tcx().sess.has_errors() { - span_bug!( - with_expr.span, - "with expression doesn't evaluate to a struct"); + _ => { + // the base expression should always evaluate to a + // struct; however, when EUV is run during typeck, it + // may not. This will generate an error earlier in typeck, + // so we can just ignore it. + if !self.tcx().sess.has_errors() { + span_bug!( + with_expr.span, + "with expression doesn't evaluate to a struct"); + } } } diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index f8eb0d4a0ece..39d5487e8beb 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -223,8 +223,7 @@ fn deref_kind(t: Ty, context: DerefKindContext) -> McResult { Ok(deref_ptr(UnsafePtr(mt.mutbl))) } - ty::TyEnum(..) | - ty::TyStruct(..) => { // newtype + ty::TyAdt(..) => { // newtype Ok(deref_interior(InteriorField(PositionalField(0)))) } @@ -1154,7 +1153,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { } Def::Struct(..) => { match self.pat_ty(&pat)?.sty { - ty::TyStruct(adt_def, _) => { + ty::TyAdt(adt_def, _) => { adt_def.struct_variant().fields.len() } ref ty => { diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index c62c99c3b706..9a56959de38b 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -20,7 +20,7 @@ use lint; use middle::cstore::LOCAL_CRATE; use hir::def::Def; use hir::def_id::{CRATE_DEF_INDEX, DefId, DefIndex}; -use ty::{self, TyCtxt}; +use ty::{self, TyCtxt, AdtKind}; use middle::privacy::AccessLevels; use syntax::parse::token::InternedString; use syntax_pos::{Span, DUMMY_SP}; @@ -561,17 +561,19 @@ pub fn check_expr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, e: &hir::Expr, hir::ExprField(ref base_e, ref field) => { span = field.span; match tcx.expr_ty_adjusted(base_e).sty { - ty::TyStruct(def, _) | ty::TyUnion(def, _) => { + ty::TyAdt(def, _) => { def.struct_variant().field_named(field.node).did } _ => span_bug!(e.span, - "stability::check_expr: named field access on non-struct/union") + "stability::check_expr: named field access on non-ADT") } } hir::ExprTupField(ref base_e, ref field) => { span = field.span; match tcx.expr_ty_adjusted(base_e).sty { - ty::TyStruct(def, _) => def.struct_variant().fields[field.node].did, + ty::TyAdt(def, _) => { + def.struct_variant().fields[field.node].did + } ty::TyTuple(..) => return, _ => span_bug!(e.span, "stability::check_expr: unnamed field access on \ @@ -579,31 +581,28 @@ pub fn check_expr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, e: &hir::Expr, } } hir::ExprStruct(_, ref expr_fields, _) => { - let type_ = tcx.expr_ty(e); - match type_.sty { - ty::TyStruct(def, _) | ty::TyUnion(def, _) => { - // check the stability of each field that appears - // in the construction expression. - for field in expr_fields { - let did = def.struct_variant() - .field_named(field.name.node) - .did; - maybe_do_stability_check(tcx, did, field.span, cb); - } + match tcx.expr_ty(e).sty { + ty::TyAdt(adt, ..) => match adt.adt_kind() { + AdtKind::Struct | AdtKind::Union => { + // check the stability of each field that appears + // in the construction expression. + for field in expr_fields { + let did = adt.struct_variant().field_named(field.name.node).did; + maybe_do_stability_check(tcx, did, field.span, cb); + } - // we're done. - return - } - // we don't look at stability attributes on - // struct-like enums (yet...), but it's definitely not - // a bug to have construct one. - ty::TyEnum(..) => return, - _ => { - span_bug!(e.span, - "stability::check_expr: struct construction \ - of non-struct/union, type {:?}", - type_); - } + // we're done. + return + } + AdtKind::Enum => { + // we don't look at stability attributes on + // struct-like enums (yet...), but it's definitely not + // a bug to have construct one. + return + } + }, + ref ty => span_bug!(e.span, "stability::check_expr: struct \ + construction of non-ADT type: {:?}", ty) } } _ => return @@ -648,10 +647,9 @@ pub fn check_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, pat: &hir::Pat, debug!("check_pat(pat = {:?})", pat); if is_internal(tcx, pat.span) { return; } - let v = match tcx.pat_ty_opt(pat) { - Some(&ty::TyS { sty: ty::TyStruct(def, _), .. }) | - Some(&ty::TyS { sty: ty::TyUnion(def, _), .. }) => def.struct_variant(), - Some(_) | None => return, + let v = match tcx.pat_ty_opt(pat).map(|ty| &ty.sty) { + Some(&ty::TyAdt(adt, _)) if !adt.is_enum() => adt.struct_variant(), + _ => return, }; match pat.node { // Foo(a, b, c) diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs index c82e723525b4..74ad6c602f6c 100644 --- a/src/librustc/mir/tcx.rs +++ b/src/librustc/mir/tcx.rs @@ -40,7 +40,7 @@ impl<'a, 'gcx, 'tcx> LvalueTy<'tcx> { LvalueTy::Ty { ty } => ty, LvalueTy::Downcast { adt_def, substs, variant_index: _ } => - tcx.mk_enum(adt_def, substs), + tcx.mk_adt(adt_def, substs), } } @@ -75,7 +75,8 @@ impl<'a, 'gcx, 'tcx> LvalueTy<'tcx> { } ProjectionElem::Downcast(adt_def1, index) => match self.to_ty(tcx).sty { - ty::TyEnum(adt_def, substs) => { + ty::TyAdt(adt_def, substs) => { + assert!(adt_def.is_enum()); assert!(index < adt_def.variants.len()); assert_eq!(adt_def, adt_def1); LvalueTy::Downcast { adt_def: adt_def, @@ -83,7 +84,7 @@ impl<'a, 'gcx, 'tcx> LvalueTy<'tcx> { variant_index: index } } _ => { - bug!("cannot downcast non-enum type: `{:?}`", self) + bug!("cannot downcast non-ADT type: `{:?}`", self) } }, ProjectionElem::Field(_, fty) => LvalueTy::Ty { ty: fty } diff --git a/src/librustc/traits/coherence.rs b/src/librustc/traits/coherence.rs index 0a7d3e6e76d8..83774f0cf7ea 100644 --- a/src/librustc/traits/coherence.rs +++ b/src/librustc/traits/coherence.rs @@ -224,7 +224,7 @@ fn fundamental_ty(tcx: TyCtxt, ty: Ty) -> bool { match ty.sty { ty::TyBox(..) | ty::TyRef(..) => true, - ty::TyEnum(def, _) | ty::TyStruct(def, _) | ty::TyUnion(def, _) => + ty::TyAdt(def, _) => def.is_fundamental(), ty::TyTrait(ref data) => tcx.has_attr(data.principal.def_id(), "fundamental"), @@ -260,9 +260,7 @@ fn ty_is_local_constructor(tcx: TyCtxt, ty: Ty, infer_is_local: InferIsLocal)-> infer_is_local.0 } - ty::TyEnum(def, _) | - ty::TyStruct(def, _) | - ty::TyUnion(def, _) => { + ty::TyAdt(def, _) => { def.did.is_local() } diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index e5ebe96932d4..52ddd8ab5dac 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -27,7 +27,7 @@ use super::{ use fmt_macros::{Parser, Piece, Position}; use hir::def_id::DefId; use infer::{self, InferCtxt, TypeOrigin}; -use ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable}; +use ty::{self, AdtKind, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable}; use ty::error::ExpectedFound; use ty::fast_reject; use ty::fold::TypeFolder; @@ -151,32 +151,30 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { ty::TyBool => Some(0), ty::TyChar => Some(1), ty::TyStr => Some(2), - ty::TyInt(..) | ty::TyUint(..) | - ty::TyInfer(ty::IntVar(..)) => Some(3), + ty::TyInt(..) | ty::TyUint(..) | ty::TyInfer(ty::IntVar(..)) => Some(3), ty::TyFloat(..) | ty::TyInfer(ty::FloatVar(..)) => Some(4), - ty::TyEnum(..) => Some(5), - ty::TyStruct(..) => Some(6), - ty::TyBox(..) | ty::TyRef(..) | ty::TyRawPtr(..) => Some(7), - ty::TyArray(..) | ty::TySlice(..) => Some(8), - ty::TyFnDef(..) | ty::TyFnPtr(..) => Some(9), - ty::TyTrait(..) => Some(10), - ty::TyClosure(..) => Some(11), - ty::TyTuple(..) => Some(12), - ty::TyProjection(..) => Some(13), - ty::TyParam(..) => Some(14), - ty::TyAnon(..) => Some(15), - ty::TyNever => Some(16), - ty::TyUnion(..) => Some(17), + ty::TyBox(..) | ty::TyRef(..) | ty::TyRawPtr(..) => Some(5), + ty::TyArray(..) | ty::TySlice(..) => Some(6), + ty::TyFnDef(..) | ty::TyFnPtr(..) => Some(7), + ty::TyTrait(..) => Some(8), + ty::TyClosure(..) => Some(9), + ty::TyTuple(..) => Some(10), + ty::TyProjection(..) => Some(11), + ty::TyParam(..) => Some(12), + ty::TyAnon(..) => Some(13), + ty::TyNever => Some(14), + ty::TyAdt(adt, ..) => match adt.adt_kind() { + AdtKind::Struct => Some(15), + AdtKind::Union => Some(16), + AdtKind::Enum => Some(17), + }, ty::TyInfer(..) | ty::TyError => None } } match (type_category(a), type_category(b)) { (Some(cat_a), Some(cat_b)) => match (&a.sty, &b.sty) { - (&ty::TyStruct(def_a, _), &ty::TyStruct(def_b, _)) | - (&ty::TyUnion(def_a, _), &ty::TyUnion(def_b, _)) | - (&ty::TyEnum(def_a, _), &ty::TyEnum(def_b, _)) => - def_a == def_b, + (&ty::TyAdt(def_a, _), &ty::TyAdt(def_b, _)) => def_a == def_b, _ => cat_a == cat_b }, // infer and error can be equated to all types diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 3f2bc8cbd13c..94dba7d12a8c 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -1638,7 +1638,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { (&ty::TyArray(..), &ty::TySlice(_)) => true, // Struct -> Struct. - (&ty::TyStruct(def_id_a, _), &ty::TyStruct(def_id_b, _)) => { + (&ty::TyAdt(def_id_a, _), &ty::TyAdt(def_id_b, _)) if def_id_a.is_struct() => { def_id_a == def_id_b } @@ -1780,8 +1780,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { Where(ty::Binder(tys.last().into_iter().cloned().collect())) } - ty::TyStruct(def, substs) | ty::TyUnion(def, substs) | - ty::TyEnum(def, substs) => { + ty::TyAdt(def, substs) => { let sized_crit = def.sized_constraint(self.tcx()); // (*) binder moved here Where(ty::Binder(match sized_crit.sty { @@ -1837,8 +1836,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { Where(ty::Binder(tys.to_vec())) } - ty::TyStruct(..) | ty::TyUnion(..) | ty::TyEnum(..) | - ty::TyProjection(..) | ty::TyParam(..) | ty::TyAnon(..) => { + ty::TyAdt(..) | ty::TyProjection(..) | ty::TyParam(..) | ty::TyAnon(..) => { // Fallback to whatever user-defined impls exist in this case. None } @@ -1930,11 +1928,11 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } // for `PhantomData`, we pass `T` - ty::TyStruct(def, substs) if def.is_phantom_data() => { + ty::TyAdt(def, substs) if def.is_phantom_data() => { substs.types().collect() } - ty::TyStruct(def, substs) | ty::TyUnion(def, substs) | ty::TyEnum(def, substs) => { + ty::TyAdt(def, substs) => { def.all_fields() .map(|f| f.ty(self.tcx(), substs)) .collect() @@ -2566,7 +2564,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } // Struct -> Struct. - (&ty::TyStruct(def, substs_a), &ty::TyStruct(_, substs_b)) => { + (&ty::TyAdt(def, substs_a), &ty::TyAdt(_, substs_b)) => { let fields = def .all_fields() .map(|f| f.unsubst_ty()) @@ -2621,7 +2619,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { k } }); - let new_struct = tcx.mk_struct(def, Substs::new(tcx, params)); + let new_struct = tcx.mk_adt(def, Substs::new(tcx, params)); let origin = TypeOrigin::Misc(obligation.cause.span); let InferOk { obligations, .. } = self.infcx.sub_types(false, origin, new_struct, target) diff --git a/src/librustc/ty/cast.rs b/src/librustc/ty/cast.rs index c8d282d18af1..0badb85e9e09 100644 --- a/src/librustc/ty/cast.rs +++ b/src/librustc/ty/cast.rs @@ -65,7 +65,7 @@ impl<'tcx> CastTy<'tcx> { ty::TyInt(_) => Some(CastTy::Int(IntTy::I)), ty::TyUint(u) => Some(CastTy::Int(IntTy::U(u))), ty::TyFloat(_) => Some(CastTy::Float), - ty::TyEnum(d,_) if d.is_payloadfree() => + ty::TyAdt(d,_) if d.is_enum() && d.is_payloadfree() => Some(CastTy::Int(IntTy::CEnum)), ty::TyRawPtr(ref mt) => Some(CastTy::Ptr(mt)), ty::TyRef(_, ref mt) => Some(CastTy::RPtr(mt)), diff --git a/src/librustc/ty/contents.rs b/src/librustc/ty/contents.rs index e0e8a329e6e1..b499e1346e73 100644 --- a/src/librustc/ty/contents.rs +++ b/src/librustc/ty/contents.rs @@ -224,8 +224,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> { |ty| tc_ty(tcx, *ty, cache)) } - ty::TyStruct(def, substs) | ty::TyUnion(def, substs) | - ty::TyEnum(def, substs) => { + ty::TyAdt(def, substs) => { let mut res = TypeContents::union(&def.variants, |v| { TypeContents::union(&v.fields, |f| { diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 0fc1641d31f7..20601493d68f 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -27,7 +27,7 @@ use ty::subst::Substs; use traits; use ty::{self, TraitRef, Ty, TypeAndMut}; use ty::{TyS, TypeVariants}; -use ty::{AdtDef, ClosureSubsts, Region}; +use ty::{AdtKind, AdtDef, ClosureSubsts, Region}; use hir::FreevarMap; use ty::{BareFnTy, InferTy, ParamTy, ProjectionTy, TraitObject}; use ty::{TyVar, TyVid, IntVar, IntVid, FloatVar, FloatVid}; @@ -620,7 +620,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn intern_adt_def(self, did: DefId, - kind: ty::AdtKind, + kind: AdtKind, variants: Vec>) -> ty::AdtDefMaster<'gcx> { let def = ty::AdtDefData::new(self, did, kind, variants); @@ -1032,8 +1032,8 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { pub fn print_debug_stats(self) { sty_debug_print!( self, - TyEnum, TyBox, TyArray, TySlice, TyRawPtr, TyRef, TyFnDef, TyFnPtr, TyTrait, - TyStruct, TyUnion, TyClosure, TyTuple, TyParam, TyInfer, TyProjection, TyAnon); + TyAdt, TyBox, TyArray, TySlice, TyRawPtr, TyRef, TyFnDef, TyFnPtr, + TyTrait, TyClosure, TyTuple, TyParam, TyInfer, TyProjection, TyAnon); println!("Substs interner: #{}", self.interners.substs.borrow().len()); println!("BareFnTy interner: #{}", self.interners.bare_fn.borrow().len()); @@ -1227,9 +1227,9 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.mk_imm_ref(self.mk_region(ty::ReStatic), self.mk_str()) } - pub fn mk_enum(self, def: AdtDef<'tcx>, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> { + pub fn mk_adt(self, def: AdtDef<'tcx>, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> { // take a copy of substs so that we own the vectors inside - self.mk_ty(TyEnum(def, substs)) + self.mk_ty(TyAdt(def, substs)) } pub fn mk_box(self, ty: Ty<'tcx>) -> Ty<'tcx> { @@ -1316,16 +1316,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.mk_ty(TyProjection(inner)) } - pub fn mk_struct(self, def: AdtDef<'tcx>, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> { - // take a copy of substs so that we own the vectors inside - self.mk_ty(TyStruct(def, substs)) - } - - pub fn mk_union(self, def: AdtDef<'tcx>, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> { - // take a copy of substs so that we own the vectors inside - self.mk_ty(TyUnion(def, substs)) - } - pub fn mk_closure(self, closure_id: DefId, substs: &'tcx Substs<'tcx>, diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs index 0e33e396f7e1..d820fddea390 100644 --- a/src/librustc/ty/error.rs +++ b/src/librustc/ty/error.rs @@ -216,7 +216,7 @@ impl<'a, 'gcx, 'lcx, 'tcx> ty::TyS<'tcx> { ty::TyUint(_) | ty::TyFloat(_) | ty::TyStr | ty::TyNever => self.to_string(), ty::TyTuple(ref tys) if tys.is_empty() => self.to_string(), - ty::TyEnum(def, _) => format!("enum `{}`", tcx.item_path_str(def.did)), + ty::TyAdt(def, _) => format!("{} `{}`", def.descr(), tcx.item_path_str(def.did)), ty::TyBox(_) => "box".to_string(), ty::TyArray(_, n) => format!("array of {} elements", n), ty::TySlice(_) => "slice".to_string(), @@ -244,12 +244,6 @@ impl<'a, 'gcx, 'lcx, 'tcx> ty::TyS<'tcx> { ty::TyTrait(ref inner) => { format!("trait {}", tcx.item_path_str(inner.principal.def_id())) } - ty::TyStruct(def, _) => { - format!("struct `{}`", tcx.item_path_str(def.did)) - } - ty::TyUnion(def, _) => { - format!("union `{}`", tcx.item_path_str(def.did)) - } ty::TyClosure(..) => "closure".to_string(), ty::TyTuple(_) => "tuple".to_string(), ty::TyInfer(ty::TyVar(_)) => "inferred type".to_string(), diff --git a/src/librustc/ty/fast_reject.rs b/src/librustc/ty/fast_reject.rs index 84f34a640dd8..ee1544d2d996 100644 --- a/src/librustc/ty/fast_reject.rs +++ b/src/librustc/ty/fast_reject.rs @@ -22,15 +22,13 @@ pub enum SimplifiedType { IntSimplifiedType(ast::IntTy), UintSimplifiedType(ast::UintTy), FloatSimplifiedType(ast::FloatTy), - EnumSimplifiedType(DefId), + AdtSimplifiedType(DefId), StrSimplifiedType, VecSimplifiedType, PtrSimplifiedType, NeverSimplifiedType, TupleSimplifiedType(usize), TraitSimplifiedType(DefId), - StructSimplifiedType(DefId), - UnionSimplifiedType(DefId), ClosureSimplifiedType(DefId), AnonSimplifiedType(DefId), FunctionSimplifiedType(usize), @@ -57,19 +55,13 @@ pub fn simplify_type<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, ty::TyInt(int_type) => Some(IntSimplifiedType(int_type)), ty::TyUint(uint_type) => Some(UintSimplifiedType(uint_type)), ty::TyFloat(float_type) => Some(FloatSimplifiedType(float_type)), - ty::TyEnum(def, _) => Some(EnumSimplifiedType(def.did)), + ty::TyAdt(def, _) => Some(AdtSimplifiedType(def.did)), ty::TyStr => Some(StrSimplifiedType), ty::TyArray(..) | ty::TySlice(_) => Some(VecSimplifiedType), ty::TyRawPtr(_) => Some(PtrSimplifiedType), ty::TyTrait(ref trait_info) => { Some(TraitSimplifiedType(trait_info.principal.def_id())) } - ty::TyStruct(def, _) => { - Some(StructSimplifiedType(def.did)) - } - ty::TyUnion(def, _) => { - Some(UnionSimplifiedType(def.did)) - } ty::TyRef(_, mt) => { // since we introduce auto-refs during method lookup, we // just treat &T and T as equivalent from the point of @@ -79,7 +71,7 @@ pub fn simplify_type<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, ty::TyBox(_) => { // treat like we would treat `Box` match tcx.lang_items.require_owned_box() { - Ok(def_id) => Some(StructSimplifiedType(def_id)), + Ok(def_id) => Some(AdtSimplifiedType(def_id)), Err(msg) => tcx.sess.fatal(&msg), } } diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs index ce6e4d6516ec..cddd59fa83c1 100644 --- a/src/librustc/ty/flags.rs +++ b/src/librustc/ty/flags.rs @@ -102,7 +102,7 @@ impl FlagComputation { } } - &ty::TyEnum(_, substs) | &ty::TyStruct(_, substs) | &ty::TyUnion(_, substs) => { + &ty::TyAdt(_, substs) => { self.add_substs(substs); } diff --git a/src/librustc/ty/item_path.rs b/src/librustc/ty/item_path.rs index ddb0a6970cba..b6b55fc0e33d 100644 --- a/src/librustc/ty/item_path.rs +++ b/src/librustc/ty/item_path.rs @@ -262,9 +262,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // impl on `Foo`, but fallback to `::bar` if self-type is // anything other than a simple path. match self_ty.sty { - ty::TyStruct(adt_def, substs) | - ty::TyUnion(adt_def, substs) | - ty::TyEnum(adt_def, substs) => { + ty::TyAdt(adt_def, substs) => { if substs.types().next().is_none() { // ignore regions self.push_item_path(buffer, adt_def.did); } else { @@ -320,9 +318,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// decisions and we may want to adjust it later. pub fn characteristic_def_id_of_type(ty: Ty) -> Option { match ty.sty { - ty::TyStruct(adt_def, _) | - ty::TyUnion(adt_def, _) | - ty::TyEnum(adt_def, _) => Some(adt_def.did), + ty::TyAdt(adt_def, _) => Some(adt_def.did), ty::TyTrait(ref data) => Some(data.principal.def_id()), diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 276fc708eed1..3c0aa041d2dd 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -15,7 +15,7 @@ pub use self::Primitive::*; use infer::InferCtxt; use session::Session; use traits; -use ty::{self, Ty, TyCtxt, TypeFoldable}; +use ty::{self, AdtKind, Ty, TyCtxt, TypeFoldable}; use syntax::ast::{FloatTy, IntTy, UintTy}; use syntax::attr; @@ -555,7 +555,7 @@ impl<'a, 'gcx, 'tcx> Struct { } // Is this the NonZero lang item wrapping a pointer or integer type? - (&Univariant { non_zero: true, .. }, &ty::TyStruct(def, substs)) => { + (&Univariant { non_zero: true, .. }, &ty::TyAdt(def, substs)) if def.is_struct() => { let fields = &def.struct_variant().fields; assert_eq!(fields.len(), 1); match *fields[0].ty(tcx, substs).layout(infcx)? { @@ -573,7 +573,7 @@ impl<'a, 'gcx, 'tcx> Struct { // Perhaps one of the fields of this struct is non-zero // let's recurse and find out - (_, &ty::TyStruct(def, substs)) => { + (_, &ty::TyAdt(def, substs)) if def.is_struct() => { Struct::non_zero_field_path(infcx, def.struct_variant().fields .iter().map(|field| { field.ty(tcx, substs) @@ -694,7 +694,7 @@ pub enum Layout { non_zero: bool }, - /// SIMD vectors, from TyStruct marked with #[repr(simd)]. + /// SIMD vectors, from structs marked with #[repr(simd)]. Vector { element: Primitive, count: u64 @@ -715,7 +715,7 @@ pub enum Layout { non_zero: bool }, - // Remaining variants are all ADTs such as TyStruct, TyEnum or TyTuple. + // Remaining variants are all ADTs such as structs, enums or tuples. /// C-like enums; basically an integer. CEnum { @@ -919,240 +919,242 @@ impl<'a, 'gcx, 'tcx> Layout { } // ADTs. - ty::TyStruct(def, substs) => { - if ty.is_simd() { - // SIMD vector types. - let element = ty.simd_type(tcx); - match *element.layout(infcx)? { - Scalar { value, .. } => { - return success(Vector { - element: value, - count: ty.simd_size(tcx) as u64 - }); - } - _ => { - tcx.sess.fatal(&format!("monomorphising SIMD type `{}` with \ - a non-machine element type `{}`", - ty, element)); + ty::TyAdt(def, substs) => match def.adt_kind() { + AdtKind::Struct => { + if ty.is_simd() { + // SIMD vector types. + let element = ty.simd_type(tcx); + match *element.layout(infcx)? { + Scalar { value, .. } => { + return success(Vector { + element: value, + count: ty.simd_size(tcx) as u64 + }); + } + _ => { + tcx.sess.fatal(&format!("monomorphising SIMD type `{}` with \ + a non-machine element type `{}`", + ty, element)); + } } } - } - let fields = def.struct_variant().fields.iter().map(|field| { - field.ty(tcx, substs).layout(infcx) - }); - let packed = tcx.lookup_packed(def.did); - let mut st = Struct::new(dl, packed); - st.extend(dl, fields, ty)?; - - Univariant { - variant: st, - non_zero: Some(def.did) == tcx.lang_items.non_zero() - } - } - ty::TyUnion(def, substs) => { - let fields = def.struct_variant().fields.iter().map(|field| { - field.ty(tcx, substs).layout(infcx) - }); - let packed = tcx.lookup_packed(def.did); - let mut un = Union::new(dl, packed); - un.extend(dl, fields, ty)?; - UntaggedUnion { variants: un } - } - ty::TyEnum(def, substs) => { - let hint = *tcx.lookup_repr_hints(def.did).get(0) - .unwrap_or(&attr::ReprAny); - - if def.variants.is_empty() { - // Uninhabitable; represent as unit - // (Typechecking will reject discriminant-sizing attrs.) - assert_eq!(hint, attr::ReprAny); - - return success(Univariant { - variant: Struct::new(dl, false), - non_zero: false - }); - } - - if def.variants.iter().all(|v| v.fields.is_empty()) { - // All bodies empty -> intlike - let (mut min, mut max) = (i64::MAX, i64::MIN); - for v in &def.variants { - let x = v.disr_val.to_u64_unchecked() as i64; - if x < min { min = x; } - if x > max { max = x; } - } - - let (discr, signed) = Integer::repr_discr(tcx, hint, min, max); - return success(CEnum { - discr: discr, - signed: signed, - min: min as u64, - max: max as u64 - }); - } - - // Since there's at least one - // non-empty body, explicit discriminants should have - // been rejected by a checker before this point. - for (i, v) in def.variants.iter().enumerate() { - if i as u64 != v.disr_val.to_u64_unchecked() { - bug!("non-C-like enum {} with specified discriminants", - tcx.item_path_str(def.did)); - } - } - - if def.variants.len() == 1 { - // Equivalent to a struct/tuple/newtype. - // (Typechecking will reject discriminant-sizing attrs.) - assert_eq!(hint, attr::ReprAny); - let fields = def.variants[0].fields.iter().map(|field| { + let fields = def.struct_variant().fields.iter().map(|field| { field.ty(tcx, substs).layout(infcx) }); - let mut st = Struct::new(dl, false); + let packed = tcx.lookup_packed(def.did); + let mut st = Struct::new(dl, packed); st.extend(dl, fields, ty)?; - return success(Univariant { variant: st, non_zero: false }); - } - // Cache the substituted and normalized variant field types. - let variants = def.variants.iter().map(|v| { - v.fields.iter().map(|field| field.ty(tcx, substs)).collect::>() - }).collect::>(); - - if variants.len() == 2 && hint == attr::ReprAny { - // Nullable pointer optimization - for discr in 0..2 { - let other_fields = variants[1 - discr].iter().map(|ty| { - ty.layout(infcx) - }); - if !Struct::would_be_zero_sized(dl, other_fields)? { - continue; - } - let path = Struct::non_zero_field_path(infcx, - variants[discr].iter().cloned())?; - let mut path = if let Some(p) = path { p } else { continue }; - - // FIXME(eddyb) should take advantage of a newtype. - if path == &[0] && variants[discr].len() == 1 { - match *variants[discr][0].layout(infcx)? { - Scalar { value, .. } => { - return success(RawNullablePointer { - nndiscr: discr as u64, - value: value - }); - } - _ => { - bug!("Layout::compute: `{}`'s non-zero \ - `{}` field not scalar?!", - ty, variants[discr][0]) - } - } - } - - path.push(0); // For GEP through a pointer. - path.reverse(); - let mut st = Struct::new(dl, false); - st.extend(dl, variants[discr].iter().map(|ty| ty.layout(infcx)), ty)?; - return success(StructWrappedNullablePointer { - nndiscr: discr as u64, - nonnull: st, - discrfield: path - }); + Univariant { + variant: st, + non_zero: Some(def.did) == tcx.lang_items.non_zero() } } - - // The general case. - let discr_max = (variants.len() - 1) as i64; - assert!(discr_max >= 0); - let (min_ity, _) = Integer::repr_discr(tcx, hint, 0, discr_max); - - let mut align = dl.aggregate_align; - let mut size = Size::from_bytes(0); - - // We're interested in the smallest alignment, so start large. - let mut start_align = Align::from_bytes(256, 256).unwrap(); - - // Create the set of structs that represent each variant - // Use the minimum integer type we figured out above - let discr = Some(Scalar { value: Int(min_ity), non_zero: false }); - let mut variants = variants.into_iter().map(|fields| { - let mut found_start = false; - let fields = fields.into_iter().map(|field| { - let field = field.layout(infcx)?; - if !found_start { - // Find the first field we can't move later - // to make room for a larger discriminant. - let field_align = field.align(dl); - if field.size(dl).bytes() != 0 || field_align.abi() != 1 { - start_align = start_align.min(field_align); - found_start = true; - } - } - Ok(field) + AdtKind::Union => { + let fields = def.struct_variant().fields.iter().map(|field| { + field.ty(tcx, substs).layout(infcx) }); - let mut st = Struct::new(dl, false); - st.extend(dl, discr.iter().map(Ok).chain(fields), ty)?; - size = cmp::max(size, st.min_size()); - align = align.max(st.align); - Ok(st) - }).collect::, _>>()?; - - // Align the maximum variant size to the largest alignment. - size = size.abi_align(align); - - if size.bytes() >= dl.obj_size_bound() { - return Err(LayoutError::SizeOverflow(ty)); + let packed = tcx.lookup_packed(def.did); + let mut un = Union::new(dl, packed); + un.extend(dl, fields, ty)?; + UntaggedUnion { variants: un } } + AdtKind::Enum => { + let hint = *tcx.lookup_repr_hints(def.did).get(0) + .unwrap_or(&attr::ReprAny); - // Check to see if we should use a different type for the - // discriminant. We can safely use a type with the same size - // as the alignment of the first field of each variant. - // We increase the size of the discriminant to avoid LLVM copying - // padding when it doesn't need to. This normally causes unaligned - // load/stores and excessive memcpy/memset operations. By using a - // bigger integer size, LLVM can be sure about it's contents and - // won't be so conservative. + if def.variants.is_empty() { + // Uninhabitable; represent as unit + // (Typechecking will reject discriminant-sizing attrs.) + assert_eq!(hint, attr::ReprAny); - // Use the initial field alignment - let wanted = start_align.abi(); - let mut ity = min_ity; - for &candidate in &[I16, I32, I64] { - let ty = Int(candidate); - if wanted == ty.align(dl).abi() && wanted == ty.size(dl).bytes() { - ity = candidate; - break; + return success(Univariant { + variant: Struct::new(dl, false), + non_zero: false + }); } - } - // FIXME(eddyb) conservative only to avoid diverging from trans::adt. - if align.abi() != start_align.abi() { - ity = min_ity; - } + if def.variants.iter().all(|v| v.fields.is_empty()) { + // All bodies empty -> intlike + let (mut min, mut max) = (i64::MAX, i64::MIN); + for v in &def.variants { + let x = v.disr_val.to_u64_unchecked() as i64; + if x < min { min = x; } + if x > max { max = x; } + } - // If the alignment is not larger than the chosen discriminant size, - // don't use the alignment as the final size. - if ity <= min_ity { - ity = min_ity; - } else { - // Patch up the variants' first few fields. - let old_ity_size = Int(min_ity).size(dl); - let new_ity_size = Int(ity).size(dl); - for variant in &mut variants { - for offset in &mut variant.offset_after_field { - if *offset > old_ity_size { - break; - } - *offset = new_ity_size; + let (discr, signed) = Integer::repr_discr(tcx, hint, min, max); + return success(CEnum { + discr: discr, + signed: signed, + min: min as u64, + max: max as u64 + }); + } + + // Since there's at least one + // non-empty body, explicit discriminants should have + // been rejected by a checker before this point. + for (i, v) in def.variants.iter().enumerate() { + if i as u64 != v.disr_val.to_u64_unchecked() { + bug!("non-C-like enum {} with specified discriminants", + tcx.item_path_str(def.did)); } } - } - General { - discr: ity, - variants: variants, - size: size, - align: align + if def.variants.len() == 1 { + // Equivalent to a struct/tuple/newtype. + // (Typechecking will reject discriminant-sizing attrs.) + assert_eq!(hint, attr::ReprAny); + let fields = def.variants[0].fields.iter().map(|field| { + field.ty(tcx, substs).layout(infcx) + }); + let mut st = Struct::new(dl, false); + st.extend(dl, fields, ty)?; + return success(Univariant { variant: st, non_zero: false }); + } + + // Cache the substituted and normalized variant field types. + let variants = def.variants.iter().map(|v| { + v.fields.iter().map(|field| field.ty(tcx, substs)).collect::>() + }).collect::>(); + + if variants.len() == 2 && hint == attr::ReprAny { + // Nullable pointer optimization + for discr in 0..2 { + let other_fields = variants[1 - discr].iter().map(|ty| { + ty.layout(infcx) + }); + if !Struct::would_be_zero_sized(dl, other_fields)? { + continue; + } + let path = Struct::non_zero_field_path(infcx, + variants[discr].iter().cloned())?; + let mut path = if let Some(p) = path { p } else { continue }; + + // FIXME(eddyb) should take advantage of a newtype. + if path == &[0] && variants[discr].len() == 1 { + match *variants[discr][0].layout(infcx)? { + Scalar { value, .. } => { + return success(RawNullablePointer { + nndiscr: discr as u64, + value: value + }); + } + _ => { + bug!("Layout::compute: `{}`'s non-zero \ + `{}` field not scalar?!", + ty, variants[discr][0]) + } + } + } + + path.push(0); // For GEP through a pointer. + path.reverse(); + let mut st = Struct::new(dl, false); + st.extend(dl, variants[discr].iter().map(|ty| ty.layout(infcx)), ty)?; + return success(StructWrappedNullablePointer { + nndiscr: discr as u64, + nonnull: st, + discrfield: path + }); + } + } + + // The general case. + let discr_max = (variants.len() - 1) as i64; + assert!(discr_max >= 0); + let (min_ity, _) = Integer::repr_discr(tcx, hint, 0, discr_max); + + let mut align = dl.aggregate_align; + let mut size = Size::from_bytes(0); + + // We're interested in the smallest alignment, so start large. + let mut start_align = Align::from_bytes(256, 256).unwrap(); + + // Create the set of structs that represent each variant + // Use the minimum integer type we figured out above + let discr = Some(Scalar { value: Int(min_ity), non_zero: false }); + let mut variants = variants.into_iter().map(|fields| { + let mut found_start = false; + let fields = fields.into_iter().map(|field| { + let field = field.layout(infcx)?; + if !found_start { + // Find the first field we can't move later + // to make room for a larger discriminant. + let field_align = field.align(dl); + if field.size(dl).bytes() != 0 || field_align.abi() != 1 { + start_align = start_align.min(field_align); + found_start = true; + } + } + Ok(field) + }); + let mut st = Struct::new(dl, false); + st.extend(dl, discr.iter().map(Ok).chain(fields), ty)?; + size = cmp::max(size, st.min_size()); + align = align.max(st.align); + Ok(st) + }).collect::, _>>()?; + + // Align the maximum variant size to the largest alignment. + size = size.abi_align(align); + + if size.bytes() >= dl.obj_size_bound() { + return Err(LayoutError::SizeOverflow(ty)); + } + + // Check to see if we should use a different type for the + // discriminant. We can safely use a type with the same size + // as the alignment of the first field of each variant. + // We increase the size of the discriminant to avoid LLVM copying + // padding when it doesn't need to. This normally causes unaligned + // load/stores and excessive memcpy/memset operations. By using a + // bigger integer size, LLVM can be sure about it's contents and + // won't be so conservative. + + // Use the initial field alignment + let wanted = start_align.abi(); + let mut ity = min_ity; + for &candidate in &[I16, I32, I64] { + let ty = Int(candidate); + if wanted == ty.align(dl).abi() && wanted == ty.size(dl).bytes() { + ity = candidate; + break; + } + } + + // FIXME(eddyb) conservative only to avoid diverging from trans::adt. + if align.abi() != start_align.abi() { + ity = min_ity; + } + + // If the alignment is not larger than the chosen discriminant size, + // don't use the alignment as the final size. + if ity <= min_ity { + ity = min_ity; + } else { + // Patch up the variants' first few fields. + let old_ity_size = Int(min_ity).size(dl); + let new_ity_size = Int(ity).size(dl); + for variant in &mut variants { + for offset in &mut variant.offset_after_field { + if *offset > old_ity_size { + break; + } + *offset = new_ity_size; + } + } + } + + General { + discr: ity, + variants: variants, + size: size, + align: align + } } - } + }, // Types with no meaningful known layout. ty::TyProjection(_) | ty::TyAnon(..) => { @@ -1317,9 +1319,9 @@ impl<'a, 'gcx, 'tcx> SizeSkeleton<'gcx> { } } - ty::TyStruct(def, substs) | ty::TyEnum(def, substs) => { + ty::TyAdt(def, substs) => { // Only newtypes and enums w/ nullable pointer optimization. - if def.variants.is_empty() || def.variants.len() > 2 { + if def.is_union() || def.variants.is_empty() || def.variants.len() > 2 { return Err(err); } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index dfe24d5627bf..91e395074508 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -952,9 +952,7 @@ impl<'tcx> TraitPredicate<'tcx> { self.input_types() .flat_map(|t| t.walk()) .filter_map(|t| match t.sty { - ty::TyStruct(adt_def, _) | - ty::TyUnion(adt_def, _) | - ty::TyEnum(adt_def, _) => + ty::TyAdt(adt_def, _) => Some(adt_def.did), _ => None @@ -1573,18 +1571,49 @@ impl<'a, 'gcx, 'tcx, 'container> AdtDefData<'gcx, 'container> { self.flags.set(self.flags.get() | AdtFlags::IS_DTORCK_VALID) } + #[inline] + pub fn is_struct(&self) -> bool { + !self.is_union() && !self.is_enum() + } + + #[inline] + pub fn is_union(&self) -> bool { + self.flags.get().intersects(AdtFlags::IS_UNION) + } + + #[inline] + pub fn is_enum(&self) -> bool { + self.flags.get().intersects(AdtFlags::IS_ENUM) + } + /// Returns the kind of the ADT - Struct or Enum. #[inline] pub fn adt_kind(&self) -> AdtKind { - if self.flags.get().intersects(AdtFlags::IS_ENUM) { + if self.is_enum() { AdtKind::Enum - } else if self.flags.get().intersects(AdtFlags::IS_UNION) { + } else if self.is_union() { AdtKind::Union } else { AdtKind::Struct } } + pub fn descr(&self) -> &'static str { + match self.adt_kind() { + AdtKind::Struct => "struct", + AdtKind::Union => "union", + AdtKind::Enum => "enum", + } + } + + pub fn variant_descr(&self) -> &'static str { + match self.adt_kind() { + AdtKind::Struct => "struct", + AdtKind::Union => "union", + AdtKind::Enum => "variant", + } + } + /// Returns whether this is a dtorck type. If this returns /// true, this type being safe for destruction requires it to be /// alive; Otherwise, only the contents are required to be. @@ -1622,8 +1651,7 @@ impl<'a, 'gcx, 'tcx, 'container> AdtDefData<'gcx, 'container> { /// Asserts this is a struct and returns the struct's unique /// variant. pub fn struct_variant(&self) -> &VariantDefData<'gcx, 'container> { - let adt_kind = self.adt_kind(); - assert!(adt_kind == AdtKind::Struct || adt_kind == AdtKind::Union); + assert!(!self.is_enum()); &self.variants[0] } @@ -1832,7 +1860,7 @@ impl<'a, 'tcx> AdtDefData<'tcx, 'tcx> { } } - TyEnum(adt, substs) | TyStruct(adt, substs) | TyUnion(adt, substs) => { + TyAdt(adt, substs) => { // recursive case let adt = tcx.lookup_adt_def_master(adt.did); adt.calculate_sized_constraint_inner(tcx, stack); diff --git a/src/librustc/ty/outlives.rs b/src/librustc/ty/outlives.rs index a7bb0374b75b..a4edd3b93c94 100644 --- a/src/librustc/ty/outlives.rs +++ b/src/librustc/ty/outlives.rs @@ -172,9 +172,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { ty::TyUint(..) | // OutlivesScalar ty::TyFloat(..) | // OutlivesScalar ty::TyNever | // ... - ty::TyEnum(..) | // OutlivesNominalType - ty::TyStruct(..) | // OutlivesNominalType - ty::TyUnion(..) | // OutlivesNominalType + ty::TyAdt(..) | // OutlivesNominalType ty::TyBox(..) | // OutlivesNominalType (ish) ty::TyAnon(..) | // OutlivesNominalType (ish) ty::TyStr | // OutlivesScalar (ish) diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index dfae19487b6f..b10c731fe27d 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -414,11 +414,11 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R, Ok(a) } - (&ty::TyEnum(a_def, a_substs), &ty::TyEnum(b_def, b_substs)) + (&ty::TyAdt(a_def, a_substs), &ty::TyAdt(b_def, b_substs)) if a_def == b_def => { let substs = relate_item_substs(relation, a_def.did, a_substs, b_substs)?; - Ok(tcx.mk_enum(a_def, substs)) + Ok(tcx.mk_adt(a_def, substs)) } (&ty::TyTrait(ref a_obj), &ty::TyTrait(ref b_obj)) => @@ -440,20 +440,6 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R, })) } - (&ty::TyStruct(a_def, a_substs), &ty::TyStruct(b_def, b_substs)) - if a_def == b_def => - { - let substs = relate_item_substs(relation, a_def.did, a_substs, b_substs)?; - Ok(tcx.mk_struct(a_def, substs)) - } - - (&ty::TyUnion(a_def, a_substs), &ty::TyUnion(b_def, b_substs)) - if a_def == b_def => - { - let substs = relate_item_substs(relation, a_def.did, a_substs, b_substs)?; - Ok(tcx.mk_union(a_def, substs)) - } - (&ty::TyClosure(a_id, a_substs), &ty::TyClosure(b_id, b_substs)) if a_id == b_id => diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 952641f6832f..6c3dabfe113f 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -482,7 +482,7 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { ty::TyRawPtr(tm) => ty::TyRawPtr(tm.fold_with(folder)), ty::TyArray(typ, sz) => ty::TyArray(typ.fold_with(folder), sz), ty::TySlice(typ) => ty::TySlice(typ.fold_with(folder)), - ty::TyEnum(tid, substs) => ty::TyEnum(tid, substs.fold_with(folder)), + ty::TyAdt(tid, substs) => ty::TyAdt(tid, substs.fold_with(folder)), ty::TyTrait(ref trait_ty) => ty::TyTrait(trait_ty.fold_with(folder)), ty::TyTuple(ts) => ty::TyTuple(ts.fold_with(folder)), ty::TyFnDef(def_id, substs, f) => { @@ -494,8 +494,6 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { ty::TyRef(ref r, tm) => { ty::TyRef(r.fold_with(folder), tm.fold_with(folder)) } - ty::TyStruct(did, substs) => ty::TyStruct(did, substs.fold_with(folder)), - ty::TyUnion(did, substs) => ty::TyUnion(did, substs.fold_with(folder)), ty::TyClosure(did, substs) => ty::TyClosure(did, substs.fold_with(folder)), ty::TyProjection(ref data) => ty::TyProjection(data.fold_with(folder)), ty::TyAnon(did, substs) => ty::TyAnon(did, substs.fold_with(folder)), @@ -516,7 +514,7 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { ty::TyRawPtr(ref tm) => tm.visit_with(visitor), ty::TyArray(typ, _sz) => typ.visit_with(visitor), ty::TySlice(typ) => typ.visit_with(visitor), - ty::TyEnum(_tid, ref substs) => substs.visit_with(visitor), + ty::TyAdt(_, substs) => substs.visit_with(visitor), ty::TyTrait(ref trait_ty) => trait_ty.visit_with(visitor), ty::TyTuple(ts) => ts.visit_with(visitor), ty::TyFnDef(_, substs, ref f) => { @@ -524,8 +522,6 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { } ty::TyFnPtr(ref f) => f.visit_with(visitor), ty::TyRef(r, ref tm) => r.visit_with(visitor) || tm.visit_with(visitor), - ty::TyStruct(_did, ref substs) => substs.visit_with(visitor), - ty::TyUnion(_did, ref substs) => substs.visit_with(visitor), ty::TyClosure(_did, ref substs) => substs.visit_with(visitor), ty::TyProjection(ref data) => data.visit_with(visitor), ty::TyAnon(_, ref substs) => substs.visit_with(visitor), diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 7ded2b05f3b5..a755dd056cd8 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -106,24 +106,13 @@ pub enum TypeVariants<'tcx> { /// A primitive floating-point type. For example, `f64`. TyFloat(ast::FloatTy), - /// An enumerated type, defined with `enum`. + /// Structures, enumerations and unions. /// /// Substs here, possibly against intuition, *may* contain `TyParam`s. /// That is, even after substitution it is possible that there are type - /// variables. This happens when the `TyEnum` corresponds to an enum - /// definition and not a concrete use of it. This is true for `TyStruct` - /// and `TyUnion` as well. - TyEnum(AdtDef<'tcx>, &'tcx Substs<'tcx>), - - /// A structure type, defined with `struct`. - /// - /// See warning about substitutions for enumerated types. - TyStruct(AdtDef<'tcx>, &'tcx Substs<'tcx>), - - /// A union type, defined with `union`. - /// - /// See warning about substitutions for enumerated types. - TyUnion(AdtDef<'tcx>, &'tcx Substs<'tcx>), + /// variables. This happens when the `TyAdt` corresponds to an ADT + /// definition and not a concrete use of it. + TyAdt(AdtDef<'tcx>, &'tcx Substs<'tcx>), /// `Box`; this is nominally a struct in the documentation, but is /// special-cased internally. For example, it is possible to implicitly @@ -922,7 +911,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { // FIXME(#24885): be smarter here, the AdtDefData::is_empty method could easily be made // more complete. match self.sty { - TyEnum(def, _) | TyStruct(def, _) | TyUnion(def, _) => def.is_empty(), + TyAdt(def, _) => def.is_empty(), // FIXME(canndrew): There's no reason why these can't be uncommented, they're tested // and they don't break anything. But I'm keeping my changes small for now. @@ -950,7 +939,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { } pub fn is_phantom_data(&self) -> bool { - if let TyStruct(def, _) = self.sty { + if let TyAdt(def, _) = self.sty { def.is_phantom_data() } else { false @@ -985,8 +974,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { pub fn is_structural(&self) -> bool { match self.sty { - TyStruct(..) | TyUnion(..) | TyTuple(..) | TyEnum(..) | - TyArray(..) | TyClosure(..) => true, + TyAdt(..) | TyTuple(..) | TyArray(..) | TyClosure(..) => true, _ => self.is_slice() | self.is_trait() } } @@ -994,7 +982,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { #[inline] pub fn is_simd(&self) -> bool { match self.sty { - TyStruct(def, _) => def.is_simd(), + TyAdt(def, _) => def.is_simd(), _ => false } } @@ -1009,7 +997,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { pub fn simd_type(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> { match self.sty { - TyStruct(def, substs) => { + TyAdt(def, substs) => { def.struct_variant().fields[0].ty(tcx, substs) } _ => bug!("simd_type called on invalid type") @@ -1018,7 +1006,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { pub fn simd_size(&self, _cx: TyCtxt) -> usize { match self.sty { - TyStruct(def, _) => def.struct_variant().fields.len(), + TyAdt(def, _) => def.struct_variant().fields.len(), _ => bug!("simd_size called on invalid type") } } @@ -1203,9 +1191,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { pub fn ty_to_def_id(&self) -> Option { match self.sty { TyTrait(ref tt) => Some(tt.principal.def_id()), - TyStruct(def, _) | - TyUnion(def, _) | - TyEnum(def, _) => Some(def.did), + TyAdt(def, _) => Some(def.did), TyClosure(id, _) => Some(id), _ => None } @@ -1213,7 +1199,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { pub fn ty_adt_def(&self) -> Option> { match self.sty { - TyStruct(adt, _) | TyUnion(adt, _) | TyEnum(adt, _) => Some(adt), + TyAdt(adt, _) => Some(adt), _ => None } } @@ -1231,10 +1217,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { v.extend(obj.principal.skip_binder().substs.regions()); v } - TyEnum(_, substs) | - TyStruct(_, substs) | - TyUnion(_, substs) | - TyAnon(_, substs) => { + TyAdt(_, substs) | TyAnon(_, substs) => { substs.regions().collect() } TyClosure(_, ref substs) => { diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 51ca6bfeb5af..68de8d96f33d 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -14,7 +14,7 @@ use hir::def_id::DefId; use infer::InferCtxt; use hir::pat_util; use traits::{self, Reveal}; -use ty::{self, Ty, TyCtxt, TypeAndMut, TypeFlags, TypeFoldable}; +use ty::{self, Ty, AdtKind, TyCtxt, TypeAndMut, TypeFlags, TypeFoldable}; use ty::{Disr, ParameterEnvironment}; use ty::fold::TypeVisitor; use ty::layout::{Layout, LayoutError}; @@ -138,28 +138,30 @@ impl<'tcx> ParameterEnvironment<'tcx> { // FIXME: (@jroesch) float this code up tcx.infer_ctxt(None, Some(self.clone()), Reveal::ExactMatch).enter(|infcx| { let adt = match self_type.sty { - ty::TyStruct(struct_def, substs) | ty::TyUnion(struct_def, substs) => { - for field in struct_def.all_fields() { - let field_ty = field.ty(tcx, substs); - if infcx.type_moves_by_default(field_ty, span) { - return Err(CopyImplementationError::InfrigingField( - field.name)) - } - } - struct_def - } - ty::TyEnum(enum_def, substs) => { - for variant in &enum_def.variants { - for field in &variant.fields { + ty::TyAdt(adt, substs) => match adt.adt_kind() { + AdtKind::Struct | AdtKind::Union => { + for field in adt.all_fields() { let field_ty = field.ty(tcx, substs); if infcx.type_moves_by_default(field_ty, span) { - return Err(CopyImplementationError::InfrigingVariant( - variant.name)) + return Err(CopyImplementationError::InfrigingField( + field.name)) } } + adt } - enum_def - } + AdtKind::Enum => { + for variant in &adt.variants { + for field in &variant.fields { + let field_ty = field.ty(tcx, substs); + if infcx.type_moves_by_default(field_ty, span) { + return Err(CopyImplementationError::InfrigingVariant( + variant.name)) + } + } + } + adt + } + }, _ => return Err(CopyImplementationError::NotAnAdt) }; @@ -183,7 +185,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn has_error_field(self, ty: Ty<'tcx>) -> bool { match ty.sty { - ty::TyStruct(def, substs) | ty::TyUnion(def, substs) | ty::TyEnum(def, substs) => { + ty::TyAdt(def, substs) => { for field in def.all_fields() { let field_ty = field.ty(self, substs); if let TyError = field_ty.sty { @@ -203,16 +205,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { i: usize, variant: Option) -> Option> { match (&ty.sty, variant) { - (&TyStruct(def, substs), None) | - (&TyUnion(def, substs), None) => { - def.struct_variant().fields.get(i).map(|f| f.ty(self, substs)) + (&TyAdt(adt, substs), Some(vid)) => { + adt.variant_with_id(vid).fields.get(i).map(|f| f.ty(self, substs)) } - (&TyEnum(def, substs), Some(vid)) => { - def.variant_with_id(vid).fields.get(i).map(|f| f.ty(self, substs)) - } - (&TyEnum(def, substs), None) => { - assert!(def.is_univariant()); - def.variants[0].fields.get(i).map(|f| f.ty(self, substs)) + (&TyAdt(adt, substs), None) => { + // Don't use `struct_variant`, this may be a univariant enum. + adt.variants[0].fields.get(i).map(|f| f.ty(self, substs)) } (&TyTuple(ref v), None) => v.get(i).cloned(), _ => None @@ -226,12 +224,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { n: Name, variant: Option) -> Option> { match (&ty.sty, variant) { - (&TyStruct(def, substs), None) | - (&TyUnion(def, substs), None) => { - def.struct_variant().find_field_named(n).map(|f| f.ty(self, substs)) + (&TyAdt(adt, substs), Some(vid)) => { + adt.variant_with_id(vid).find_field_named(n).map(|f| f.ty(self, substs)) } - (&TyEnum(def, substs), Some(vid)) => { - def.variant_with_id(vid).find_field_named(n).map(|f| f.ty(self, substs)) + (&TyAdt(adt, substs), None) => { + adt.struct_variant().find_field_named(n).map(|f| f.ty(self, substs)) } _ => return None } @@ -256,10 +253,15 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// if not a structure at all. Corresponds to the only possible unsized /// field, and its type can be used to determine unsizing strategy. pub fn struct_tail(self, mut ty: Ty<'tcx>) -> Ty<'tcx> { - while let TyStruct(def, substs) = ty.sty { - match def.struct_variant().fields.last() { - Some(f) => ty = f.ty(self, substs), - None => break + loop { + match ty.sty { + TyAdt(def, substs) if def.is_struct() => { + match def.struct_variant().fields.last() { + Some(f) => ty = f.ty(self, substs), + None => break + } + } + _ => break } } ty @@ -275,15 +277,19 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { target: Ty<'tcx>) -> (Ty<'tcx>, Ty<'tcx>) { let (mut a, mut b) = (source, target); - while let (&TyStruct(a_def, a_substs), &TyStruct(b_def, b_substs)) = (&a.sty, &b.sty) { - if a_def != b_def { - break; - } - if let Some(f) = a_def.struct_variant().fields.last() { - a = f.ty(self, a_substs); - b = f.ty(self, b_substs); - } else { - break; + loop { + match (&a.sty, &b.sty) { + (&TyAdt(a_def, a_substs), &TyAdt(b_def, b_substs)) + if a_def == b_def && a_def.is_struct() => { + match a_def.struct_variant().fields.last() { + Some(f) => { + a = f.ty(self, a_substs); + b = f.ty(self, b_substs); + } + _ => break + } + } + _ => break } } (a, b) @@ -431,9 +437,7 @@ impl<'a, 'gcx, 'tcx> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tcx> { TyInt(i) => self.hash(i), TyUint(u) => self.hash(u), TyFloat(f) => self.hash(f), - TyStruct(d, _) | - TyUnion(d, _) | - TyEnum(d, _) => self.def_id(d.did), + TyAdt(d, _) => self.def_id(d.did), TyArray(_, n) => self.hash(n), TyRawPtr(m) | TyRef(_, m) => self.hash(m.mutbl), @@ -560,8 +564,8 @@ impl<'a, 'tcx> ty::TyS<'tcx> { mutbl: hir::MutMutable, .. }) => Some(true), - TyArray(..) | TySlice(_) | TyTrait(..) | TyTuple(..) | - TyClosure(..) | TyEnum(..) | TyStruct(..) | TyUnion(..) | TyAnon(..) | + TyArray(..) | TySlice(..) | TyTrait(..) | TyTuple(..) | + TyClosure(..) | TyAdt(..) | TyAnon(..) | TyProjection(..) | TyParam(..) | TyInfer(..) | TyError => None }.unwrap_or_else(|| !self.impls_bound(tcx, param_env, ty::BoundCopy, span)); @@ -601,7 +605,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> { TyStr | TyTrait(..) | TySlice(_) => Some(false), - TyEnum(..) | TyStruct(..) | TyUnion(..) | TyProjection(..) | TyParam(..) | + TyAdt(..) | TyProjection(..) | TyParam(..) | TyInfer(..) | TyAnon(..) | TyError => None }.unwrap_or_else(|| self.impls_bound(tcx, param_env, ty::BoundSized, span)); @@ -663,7 +667,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> { TyArray(ty, _) => { is_type_structurally_recursive(tcx, sp, seen, ty) } - TyStruct(def, substs) | TyUnion(def, substs) | TyEnum(def, substs) => { + TyAdt(def, substs) => { find_nonrepresentable(tcx, sp, seen, @@ -680,7 +684,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> { fn same_struct_or_enum<'tcx>(ty: Ty<'tcx>, def: ty::AdtDef<'tcx>) -> bool { match ty.sty { - TyStruct(ty_def, _) | TyUnion(ty_def, _) | TyEnum(ty_def, _) => { + TyAdt(ty_def, _) => { ty_def == def } _ => false @@ -689,9 +693,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> { fn same_type<'tcx>(a: Ty<'tcx>, b: Ty<'tcx>) -> bool { match (&a.sty, &b.sty) { - (&TyStruct(did_a, ref substs_a), &TyStruct(did_b, ref substs_b)) | - (&TyUnion(did_a, ref substs_a), &TyUnion(did_b, ref substs_b)) | - (&TyEnum(did_a, ref substs_a), &TyEnum(did_b, ref substs_b)) => { + (&TyAdt(did_a, substs_a), &TyAdt(did_b, substs_b)) => { if did_a != did_b { return false; } @@ -713,7 +715,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> { debug!("is_type_structurally_recursive: {:?}", ty); match ty.sty { - TyStruct(def, _) | TyUnion(def, _) | TyEnum(def, _) => { + TyAdt(def, _) => { { // Iterate through stack of previously seen types. let mut iter = seen.iter(); diff --git a/src/librustc/ty/walk.rs b/src/librustc/ty/walk.rs index cea3bd6348db..dd3a62f7cd2d 100644 --- a/src/librustc/ty/walk.rs +++ b/src/librustc/ty/walk.rs @@ -93,10 +93,7 @@ fn push_subtypes<'tcx>(stack: &mut Vec>, parent_ty: Ty<'tcx>) { pred.0.ty }).rev()); } - ty::TyEnum(_, ref substs) | - ty::TyStruct(_, ref substs) | - ty::TyUnion(_, ref substs) | - ty::TyAnon(_, ref substs) => { + ty::TyAdt(_, substs) | ty::TyAnon(_, substs) => { stack.extend(substs.types().rev()); } ty::TyClosure(_, ref substs) => { diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs index 599e2be4db24..0557660e98c2 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/ty/wf.rs @@ -336,9 +336,7 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { self.compute_projection(data); } - ty::TyEnum(def, substs) | - ty::TyStruct(def, substs) | - ty::TyUnion(def, substs) => { + ty::TyAdt(def, substs) => { // WfNominalType let obligations = self.nominal_obligations(def.did, substs); self.out.extend(obligations); diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index d0e02f2e8acd..3b84ff86ab9f 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -11,7 +11,7 @@ use hir::def_id::DefId; use ty::subst::{self, Subst, Substs}; use ty::{BrAnon, BrEnv, BrFresh, BrNamed}; -use ty::{TyBool, TyChar, TyStruct, TyUnion, TyEnum}; +use ty::{TyBool, TyChar, TyAdt}; use ty::{TyError, TyStr, TyArray, TySlice, TyFloat, TyFnDef, TyFnPtr}; use ty::{TyParam, TyRawPtr, TyRef, TyNever, TyTuple}; use ty::TyClosure; @@ -868,7 +868,7 @@ impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> { TyInfer(infer_ty) => write!(f, "{}", infer_ty), TyError => write!(f, "[type error]"), TyParam(ref param_ty) => write!(f, "{}", param_ty), - TyEnum(def, substs) | TyStruct(def, substs) | TyUnion(def, substs) => { + TyAdt(def, substs) => { ty::tls::with(|tcx| { if def.did.is_local() && !tcx.tcache.borrow().contains_key(&def.did) { diff --git a/src/librustc_borrowck/borrowck/check_loans.rs b/src/librustc_borrowck/borrowck/check_loans.rs index 6f4c48d632a7..089733da536d 100644 --- a/src/librustc_borrowck/borrowck/check_loans.rs +++ b/src/librustc_borrowck/borrowck/check_loans.rs @@ -796,9 +796,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { } LpExtend(ref lp_base, _, LpInterior(_, InteriorField(_))) => { match lp_base.to_type().sty { - ty::TyStruct(def, _) | - ty::TyUnion(def, _) | - ty::TyEnum(def, _) if def.has_dtor() => { + ty::TyAdt(def, _) if def.has_dtor() => { // In the case where the owner implements drop, then // the path must be initialized to prevent a case of // partial reinitialization diff --git a/src/librustc_borrowck/borrowck/fragments.rs b/src/librustc_borrowck/borrowck/fragments.rs index 45f5c3288a6d..515868c460d0 100644 --- a/src/librustc_borrowck/borrowck/fragments.rs +++ b/src/librustc_borrowck/borrowck/fragments.rs @@ -21,7 +21,7 @@ use borrowck::LoanPathElem::{LpDeref, LpInterior}; use borrowck::move_data::InvalidMovePathIndex; use borrowck::move_data::{MoveData, MovePathIndex}; use rustc::hir::def_id::{DefId}; -use rustc::ty::{self, TyCtxt}; +use rustc::ty::{self, AdtKind, TyCtxt}; use rustc::middle::mem_categorization as mc; use std::mem; @@ -422,8 +422,8 @@ fn add_fragment_siblings_for_extension<'a, 'tcx>(this: &MoveData<'tcx>, variant_did); }; - match (&parent_ty.sty, enum_variant_info) { - (&ty::TyTuple(ref v), None) => { + match parent_ty.sty { + ty::TyTuple(ref v) => { let tuple_idx = match *origin_field_name { mc::PositionalField(tuple_idx) => tuple_idx, mc::NamedField(_) => @@ -438,69 +438,68 @@ fn add_fragment_siblings_for_extension<'a, 'tcx>(this: &MoveData<'tcx>, } } - (&ty::TyStruct(def, _), None) => { - match *origin_field_name { - mc::NamedField(ast_name) => { - for f in &def.struct_variant().fields { - if f.name == ast_name { - continue; + ty::TyAdt(def, ..) => match def.adt_kind() { + AdtKind::Struct => { + match *origin_field_name { + mc::NamedField(ast_name) => { + for f in &def.struct_variant().fields { + if f.name == ast_name { + continue; + } + let field_name = mc::NamedField(f.name); + add_fragment_sibling_local(field_name, None); } - let field_name = mc::NamedField(f.name); - add_fragment_sibling_local(field_name, None); } - } - mc::PositionalField(tuple_idx) => { - for (i, _f) in def.struct_variant().fields.iter().enumerate() { - if i == tuple_idx { - continue + mc::PositionalField(tuple_idx) => { + for (i, _f) in def.struct_variant().fields.iter().enumerate() { + if i == tuple_idx { + continue + } + let field_name = mc::PositionalField(i); + add_fragment_sibling_local(field_name, None); } - let field_name = mc::PositionalField(i); - add_fragment_sibling_local(field_name, None); } } } - } - - (&ty::TyUnion(..), None) => { - // Do nothing, all union fields are moved/assigned together. - } - - (&ty::TyEnum(def, _), ref enum_variant_info) => { - let variant = match *enum_variant_info { - Some((vid, ref _lp2)) => def.variant_with_id(vid), - None => { - assert!(def.is_univariant()); - &def.variants[0] - } - }; - match *origin_field_name { - mc::NamedField(ast_name) => { - for field in &variant.fields { - if field.name == ast_name { - continue; - } - let field_name = mc::NamedField(field.name); - add_fragment_sibling_local(field_name, Some(variant.did)); + AdtKind::Union => { + // Do nothing, all union fields are moved/assigned together. + } + AdtKind::Enum => { + let variant = match enum_variant_info { + Some((vid, ref _lp2)) => def.variant_with_id(vid), + None => { + assert!(def.is_univariant()); + &def.variants[0] } - } - mc::PositionalField(tuple_idx) => { - for (i, _f) in variant.fields.iter().enumerate() { - if tuple_idx == i { - continue; + }; + match *origin_field_name { + mc::NamedField(ast_name) => { + for field in &variant.fields { + if field.name == ast_name { + continue; + } + let field_name = mc::NamedField(field.name); + add_fragment_sibling_local(field_name, Some(variant.did)); + } + } + mc::PositionalField(tuple_idx) => { + for (i, _f) in variant.fields.iter().enumerate() { + if tuple_idx == i { + continue; + } + let field_name = mc::PositionalField(i); + add_fragment_sibling_local(field_name, None); } - let field_name = mc::PositionalField(i); - add_fragment_sibling_local(field_name, None); } } } - } + }, - ref sty_and_variant_info => { + ref ty => { let opt_span = origin_id.and_then(|id|tcx.map.opt_span(id)); span_bug!(opt_span.unwrap_or(DUMMY_SP), "type {:?} ({:?}) is not fragmentable", - parent_ty, - sty_and_variant_info); + parent_ty, ty); } } } diff --git a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs index 5f2d6c406c4b..3e335dacc8ed 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs @@ -178,7 +178,7 @@ fn check_and_get_illegal_move_origin<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, Categorization::Interior(ref b, mc::InteriorField(_)) | Categorization::Interior(ref b, mc::InteriorElement(Kind::Pattern, _)) => { match b.ty.sty { - ty::TyStruct(def, _) | ty::TyUnion(def, _) | ty::TyEnum(def, _) => { + ty::TyAdt(def, _) => { if def.has_dtor() { Some(cmt.clone()) } else { diff --git a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs index bda68a1cd1ce..3fa7c252b842 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs @@ -148,9 +148,7 @@ fn report_cannot_move_out_of<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, Categorization::Downcast(ref b, _) | Categorization::Interior(ref b, mc::InteriorField(_)) => { match b.ty.sty { - ty::TyStruct(def, _) | - ty::TyUnion(def, _) | - ty::TyEnum(def, _) if def.has_dtor() => { + ty::TyAdt(def, _) if def.has_dtor() => { let mut err = struct_span_err!(bccx, move_from.span, E0509, "cannot move out of type `{}`, \ which implements the `Drop` trait", diff --git a/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs b/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs index c08dc9330b8f..fdcefdc0d430 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs @@ -103,8 +103,8 @@ impl<'a, 'tcx> RestrictionsContext<'a, 'tcx> { let base_ty = cmt_base.ty; let result = self.restrict(cmt_base); // Borrowing one union field automatically borrows all its fields. - if let ty::TyUnion(ref adt_def, _) = base_ty.sty { - match result { + match base_ty.sty { + ty::TyAdt(adt_def, _) if adt_def.is_union() => match result { RestrictionResult::Safe => RestrictionResult::Safe, RestrictionResult::SafeIf(base_lp, mut base_vec) => { for field in &adt_def.struct_variant().fields { @@ -124,9 +124,8 @@ impl<'a, 'tcx> RestrictionsContext<'a, 'tcx> { LpInterior(opt_variant_id, interior))); RestrictionResult::SafeIf(lp, base_vec) } - } - } else { - self.extend(result, &cmt, LpInterior(opt_variant_id, interior)) + }, + _ => self.extend(result, &cmt, LpInterior(opt_variant_id, interior)) } } diff --git a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs index c5d103453798..71274b7e0218 100644 --- a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs +++ b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs @@ -709,7 +709,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { fn open_drop<'a>(&mut self, c: &DropCtxt<'a, 'tcx>) -> BasicBlock { let ty = c.lvalue.ty(self.mir, self.tcx).to_ty(self.tcx); match ty.sty { - ty::TyStruct(def, substs) | ty::TyUnion(def, substs) | ty::TyEnum(def, substs) => { + ty::TyAdt(def, substs) => { self.open_drop_for_adt(c, def, substs) } ty::TyTuple(tys) | ty::TyClosure(_, ty::ClosureSubsts { @@ -893,7 +893,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { let ty = c.lvalue.ty(self.mir, self.tcx).to_ty(self.tcx); match ty.sty { - ty::TyStruct(def, _) | ty::TyUnion(def, _) | ty::TyEnum(def, _) => { + ty::TyAdt(def, _) => { if def.has_dtor() { self.tcx.sess.span_warn( c.source_info.span, diff --git a/src/librustc_borrowck/borrowck/mir/mod.rs b/src/librustc_borrowck/borrowck/mir/mod.rs index 9c462feeaadd..e035e268b1c4 100644 --- a/src/librustc_borrowck/borrowck/mir/mod.rs +++ b/src/librustc_borrowck/borrowck/mir/mod.rs @@ -261,7 +261,7 @@ fn lvalue_contents_drop_state_cannot_differ<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx lv, ty); true } - ty::TyStruct(def, _) | ty::TyUnion(def, _) | ty::TyEnum(def, _) if def.has_dtor() => { + ty::TyAdt(def, _) if def.has_dtor() => { debug!("lvalue_contents_drop_state_cannot_differ lv: {:?} ty: {:?} Drop => false", lv, ty); true diff --git a/src/librustc_borrowck/borrowck/move_data.rs b/src/librustc_borrowck/borrowck/move_data.rs index 0c9261df5487..e9ba406389f8 100644 --- a/src/librustc_borrowck/borrowck/move_data.rs +++ b/src/librustc_borrowck/borrowck/move_data.rs @@ -367,20 +367,22 @@ impl<'a, 'tcx> MoveData<'tcx> { kind: MoveKind) { // Moving one union field automatically moves all its fields. if let LpExtend(ref base_lp, mutbl, LpInterior(opt_variant_id, interior)) = lp.kind { - if let ty::TyUnion(ref adt_def, _) = base_lp.ty.sty { - for field in &adt_def.struct_variant().fields { - let field = InteriorKind::InteriorField(mc::NamedField(field.name)); - let field_ty = if field == interior { - lp.ty - } else { - tcx.types.err // Doesn't matter - }; - let sibling_lp_kind = LpExtend(base_lp.clone(), mutbl, - LpInterior(opt_variant_id, field)); - let sibling_lp = Rc::new(LoanPath::new(sibling_lp_kind, field_ty)); - self.add_move_helper(tcx, sibling_lp, id, kind); + if let ty::TyAdt(adt_def, _) = base_lp.ty.sty { + if adt_def.is_union() { + for field in &adt_def.struct_variant().fields { + let field = InteriorKind::InteriorField(mc::NamedField(field.name)); + let field_ty = if field == interior { + lp.ty + } else { + tcx.types.err // Doesn't matter + }; + let sibling_lp_kind = LpExtend(base_lp.clone(), mutbl, + LpInterior(opt_variant_id, field)); + let sibling_lp = Rc::new(LoanPath::new(sibling_lp_kind, field_ty)); + self.add_move_helper(tcx, sibling_lp, id, kind); + } + return; } - return; } } @@ -422,20 +424,23 @@ impl<'a, 'tcx> MoveData<'tcx> { mode: euv::MutateMode) { // Assigning to one union field automatically assigns to all its fields. if let LpExtend(ref base_lp, mutbl, LpInterior(opt_variant_id, interior)) = lp.kind { - if let ty::TyUnion(ref adt_def, _) = base_lp.ty.sty { - for field in &adt_def.struct_variant().fields { - let field = InteriorKind::InteriorField(mc::NamedField(field.name)); - let field_ty = if field == interior { - lp.ty - } else { - tcx.types.err // Doesn't matter - }; - let sibling_lp_kind = LpExtend(base_lp.clone(), mutbl, - LpInterior(opt_variant_id, field)); - let sibling_lp = Rc::new(LoanPath::new(sibling_lp_kind, field_ty)); - self.add_assignment_helper(tcx, sibling_lp, assign_id, span, assignee_id, mode); + if let ty::TyAdt(adt_def, _) = base_lp.ty.sty { + if adt_def.is_union() { + for field in &adt_def.struct_variant().fields { + let field = InteriorKind::InteriorField(mc::NamedField(field.name)); + let field_ty = if field == interior { + lp.ty + } else { + tcx.types.err // Doesn't matter + }; + let sibling_lp_kind = LpExtend(base_lp.clone(), mutbl, + LpInterior(opt_variant_id, field)); + let sibling_lp = Rc::new(LoanPath::new(sibling_lp_kind, field_ty)); + self.add_assignment_helper(tcx, sibling_lp, assign_id, + span, assignee_id, mode); + } + return; } - return; } } diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs index e49011d88737..da4445ef6894 100644 --- a/src/librustc_const_eval/check_match.rs +++ b/src/librustc_const_eval/check_match.rs @@ -245,21 +245,23 @@ fn check_for_bindings_named_the_same_as_variants(cx: &MatchCheckCtxt, pat: &Pat) pat.walk(|p| { if let PatKind::Binding(hir::BindByValue(hir::MutImmutable), name, None) = p.node { let pat_ty = cx.tcx.pat_ty(p); - if let ty::TyEnum(edef, _) = pat_ty.sty { - if let Def::Local(..) = cx.tcx.expect_def(p.id) { - if edef.variants.iter().any(|variant| { - variant.name == name.node && variant.kind == VariantKind::Unit - }) { - let ty_path = cx.tcx.item_path_str(edef.did); - let mut err = struct_span_warn!(cx.tcx.sess, p.span, E0170, - "pattern binding `{}` is named the same as one \ - of the variants of the type `{}`", - name.node, ty_path); - help!(err, - "if you meant to match on a variant, \ - consider making the path in the pattern qualified: `{}::{}`", - ty_path, name.node); - err.emit(); + if let ty::TyAdt(edef, _) = pat_ty.sty { + if edef.is_enum() { + if let Def::Local(..) = cx.tcx.expect_def(p.id) { + if edef.variants.iter().any(|variant| { + variant.name == name.node && variant.kind == VariantKind::Unit + }) { + let ty_path = cx.tcx.item_path_str(edef.did); + let mut err = struct_span_warn!(cx.tcx.sess, p.span, E0170, + "pattern binding `{}` is named the same as one \ + of the variants of the type `{}`", + name.node, ty_path); + help!(err, + "if you meant to match on a variant, \ + consider making the path in the pattern qualified: `{}::{}`", + ty_path, name.node); + err.emit(); + } } } } @@ -566,7 +568,7 @@ fn construct_witness<'a,'tcx>(cx: &MatchCheckCtxt<'a,'tcx>, ctor: &Constructor, let pat = match left_ty.sty { ty::TyTuple(..) => PatKind::Tuple(pats.collect(), None), - ty::TyEnum(adt, _) | ty::TyStruct(adt, _) | ty::TyUnion(adt, _) => { + ty::TyAdt(adt, _) => { let v = ctor.variant_for_adt(adt); match v.kind { VariantKind::Struct => { @@ -659,7 +661,8 @@ fn all_constructors(_cx: &MatchCheckCtxt, left_ty: Ty, [true, false].iter().map(|b| ConstantValue(ConstVal::Bool(*b))).collect(), ty::TySlice(_) => (0..max_slice_length+1).map(|length| Slice(length)).collect(), - ty::TyEnum(def, _) => def.variants.iter().map(|v| Variant(v.did)).collect(), + ty::TyAdt(def, _) if def.is_enum() => + def.variants.iter().map(|v| Variant(v.did)).collect(), _ => vec![Single] } } @@ -837,7 +840,7 @@ pub fn constructor_arity(_cx: &MatchCheckCtxt, ctor: &Constructor, ty: Ty) -> us _ => bug!() }, ty::TyRef(..) => 1, - ty::TyEnum(adt, _) | ty::TyStruct(adt, _) | ty::TyUnion(adt, _) => { + ty::TyAdt(adt, _) => { ctor.variant_for_adt(adt).fields.len() } ty::TyArray(_, n) => n, diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index 30e5a0cacf55..4f4c16d3f6a6 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -257,8 +257,11 @@ pub fn const_expr_to_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, span, format!("floating point constants cannot be used in patterns")); } - ty::TyEnum(adt_def, _) | - ty::TyStruct(adt_def, _) => { + ty::TyAdt(adt_def, _) if adt_def.is_union() => { + // Matching on union fields is unsafe, we can't hide it in constants + tcx.sess.span_err(span, "cannot use unions in constant patterns"); + } + ty::TyAdt(adt_def, _) => { if !tcx.has_attr(adt_def.did, "structural_match") { tcx.sess.add_lint( lint::builtin::ILLEGAL_STRUCT_OR_ENUM_CONSTANT_PATTERN, @@ -271,10 +274,6 @@ pub fn const_expr_to_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, tcx.item_path_str(adt_def.did))); } } - ty::TyUnion(..) => { - // Matching on union fields is unsafe, we can't hide it in constants - tcx.sess.span_err(span, "cannot use unions in constant patterns"); - } _ => { } } let pat = match expr.node { @@ -1039,7 +1038,7 @@ fn infer<'a, 'tcx>(i: ConstInt, (&ty::TyInt(ity), i) => Err(TypeMismatch(ity.to_string(), i)), (&ty::TyUint(ity), i) => Err(TypeMismatch(ity.to_string(), i)), - (&ty::TyEnum(ref adt, _), i) => { + (&ty::TyAdt(adt, _), i) if adt.is_enum() => { let hints = tcx.lookup_repr_hints(adt.did); let int_ty = tcx.enum_repr_type(hints.iter().next()); infer(i, tcx, &int_ty.to_ty(tcx).sty) @@ -1230,7 +1229,7 @@ fn lit_to_const<'a, 'tcx>(lit: &ast::LitKind, infer(Infer(n), tcx, &ty::TyUint(uty)).map(Integral) }, None => Ok(Integral(Infer(n))), - Some(&ty::TyEnum(ref adt, _)) => { + Some(&ty::TyAdt(adt, _)) => { let hints = tcx.lookup_repr_hints(adt.did); let int_ty = tcx.enum_repr_type(hints.iter().next()); infer(Infer(n), tcx, &int_ty.to_ty(tcx).sty).map(Integral) diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index a73930fa5251..b610a924a339 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -468,21 +468,21 @@ impl LateLintPass for MissingCopyImplementations { return; } let def = cx.tcx.lookup_adt_def(cx.tcx.map.local_def_id(item.id)); - (def, cx.tcx.mk_struct(def, Substs::empty(cx.tcx))) + (def, cx.tcx.mk_adt(def, Substs::empty(cx.tcx))) } hir::ItemUnion(_, ref ast_generics) => { if ast_generics.is_parameterized() { return; } let def = cx.tcx.lookup_adt_def(cx.tcx.map.local_def_id(item.id)); - (def, cx.tcx.mk_union(def, Substs::empty(cx.tcx))) + (def, cx.tcx.mk_adt(def, Substs::empty(cx.tcx))) } hir::ItemEnum(_, ref ast_generics) => { if ast_generics.is_parameterized() { return; } let def = cx.tcx.lookup_adt_def(cx.tcx.map.local_def_id(item.id)); - (def, cx.tcx.mk_enum(def, Substs::empty(cx.tcx))) + (def, cx.tcx.mk_adt(def, Substs::empty(cx.tcx))) } _ => return, }; diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index 54cec3fd7e13..a6049acdb10d 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -12,7 +12,7 @@ use rustc::hir::def_id::DefId; use rustc::ty::subst::Substs; -use rustc::ty::{self, Ty, TyCtxt}; +use rustc::ty::{self, AdtKind, Ty, TyCtxt}; use rustc::ty::layout::{Layout, Primitive}; use rustc::traits::Reveal; use middle::const_val::ConstVal; @@ -431,110 +431,112 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { } match ty.sty { - ty::TyStruct(def, substs) => { - if !cx.lookup_repr_hints(def.did).contains(&attr::ReprExtern) { - return FfiUnsafe( - "found struct without foreign-function-safe \ - representation annotation in foreign module, \ - consider adding a #[repr(C)] attribute to \ - the type"); - } - - // We can't completely trust repr(C) markings; make sure the - // fields are actually safe. - if def.struct_variant().fields.is_empty() { - return FfiUnsafe( - "found zero-size struct in foreign module, consider \ - adding a member to this struct"); - } - - for field in &def.struct_variant().fields { - let field_ty = cx.normalize_associated_type(&field.ty(cx, substs)); - let r = self.check_type_for_ffi(cache, field_ty); - match r { - FfiSafe => {} - FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => { return r; } - FfiUnsafe(s) => { return FfiBadStruct(def.did, s); } - } - } - FfiSafe - } - ty::TyUnion(def, substs) => { - if !cx.lookup_repr_hints(def.did).contains(&attr::ReprExtern) { - return FfiUnsafe( - "found union without foreign-function-safe \ - representation annotation in foreign module, \ - consider adding a #[repr(C)] attribute to \ - the type"); - } - - for field in &def.struct_variant().fields { - let field_ty = cx.normalize_associated_type(&field.ty(cx, substs)); - let r = self.check_type_for_ffi(cache, field_ty); - match r { - FfiSafe => {} - FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => { return r; } - FfiUnsafe(s) => { return FfiBadUnion(def.did, s); } - } - } - FfiSafe - } - ty::TyEnum(def, substs) => { - if def.variants.is_empty() { - // Empty enums are okay... although sort of useless. - return FfiSafe - } - - // Check for a repr() attribute to specify the size of the - // discriminant. - let repr_hints = cx.lookup_repr_hints(def.did); - match &repr_hints[..] { - &[] => { - // Special-case types like `Option`. - if !is_repr_nullable_ptr(cx, def, substs) { - return FfiUnsafe( - "found enum without foreign-function-safe \ - representation annotation in foreign module, \ - consider adding a #[repr(...)] attribute to \ - the type") - } - } - &[ref hint] => { - if !hint.is_ffi_safe() { - // FIXME: This shouldn't be reachable: we should check - // this earlier. - return FfiUnsafe( - "enum has unexpected #[repr(...)] attribute") - } - - // Enum with an explicitly sized discriminant; either - // a C-style enum or a discriminated union. - - // The layout of enum variants is implicitly repr(C). - // FIXME: Is that correct? - } - _ => { - // FIXME: This shouldn't be reachable: we should check - // this earlier. + ty::TyAdt(def, substs) => match def.adt_kind() { + AdtKind::Struct => { + if !cx.lookup_repr_hints(def.did).contains(&attr::ReprExtern) { return FfiUnsafe( - "enum has too many #[repr(...)] attributes"); + "found struct without foreign-function-safe \ + representation annotation in foreign module, \ + consider adding a #[repr(C)] attribute to \ + the type"); } - } - // Check the contained variants. - for variant in &def.variants { - for field in &variant.fields { - let arg = cx.normalize_associated_type(&field.ty(cx, substs)); - let r = self.check_type_for_ffi(cache, arg); + // We can't completely trust repr(C) markings; make sure the + // fields are actually safe. + if def.struct_variant().fields.is_empty() { + return FfiUnsafe( + "found zero-size struct in foreign module, consider \ + adding a member to this struct"); + } + + for field in &def.struct_variant().fields { + let field_ty = cx.normalize_associated_type(&field.ty(cx, substs)); + let r = self.check_type_for_ffi(cache, field_ty); match r { FfiSafe => {} FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => { return r; } - FfiUnsafe(s) => { return FfiBadEnum(def.did, s); } + FfiUnsafe(s) => { return FfiBadStruct(def.did, s); } } } + FfiSafe } - FfiSafe - } + AdtKind::Union => { + if !cx.lookup_repr_hints(def.did).contains(&attr::ReprExtern) { + return FfiUnsafe( + "found union without foreign-function-safe \ + representation annotation in foreign module, \ + consider adding a #[repr(C)] attribute to \ + the type"); + } + + for field in &def.struct_variant().fields { + let field_ty = cx.normalize_associated_type(&field.ty(cx, substs)); + let r = self.check_type_for_ffi(cache, field_ty); + match r { + FfiSafe => {} + FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => { return r; } + FfiUnsafe(s) => { return FfiBadUnion(def.did, s); } + } + } + FfiSafe + } + AdtKind::Enum => { + if def.variants.is_empty() { + // Empty enums are okay... although sort of useless. + return FfiSafe + } + + // Check for a repr() attribute to specify the size of the + // discriminant. + let repr_hints = cx.lookup_repr_hints(def.did); + match &repr_hints[..] { + &[] => { + // Special-case types like `Option`. + if !is_repr_nullable_ptr(cx, def, substs) { + return FfiUnsafe( + "found enum without foreign-function-safe \ + representation annotation in foreign module, \ + consider adding a #[repr(...)] attribute to \ + the type") + } + } + &[ref hint] => { + if !hint.is_ffi_safe() { + // FIXME: This shouldn't be reachable: we should check + // this earlier. + return FfiUnsafe( + "enum has unexpected #[repr(...)] attribute") + } + + // Enum with an explicitly sized discriminant; either + // a C-style enum or a discriminated union. + + // The layout of enum variants is implicitly repr(C). + // FIXME: Is that correct? + } + _ => { + // FIXME: This shouldn't be reachable: we should check + // this earlier. + return FfiUnsafe( + "enum has too many #[repr(...)] attributes"); + } + } + + // Check the contained variants. + for variant in &def.variants { + for field in &variant.fields { + let arg = cx.normalize_associated_type(&field.ty(cx, substs)); + let r = self.check_type_for_ffi(cache, arg); + match r { + FfiSafe => {} + FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => { return r; } + FfiUnsafe(s) => { return FfiBadEnum(def.did, s); } + } + } + } + FfiSafe + } + }, ty::TyChar => { FfiUnsafe("found Rust type `char` in foreign module, while \ diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index f07720f5202b..d31f16df6935 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -136,9 +136,7 @@ impl LateLintPass for UnusedResults { ty::TyTuple(ref tys) if tys.is_empty() => return, ty::TyNever => return, ty::TyBool => return, - ty::TyStruct(def, _) | - ty::TyUnion(def, _) | - ty::TyEnum(def, _) => { + ty::TyAdt(def, _) => { let attrs = cx.tcx.get_attrs(def.did); check_must_use(cx, &attrs[..], s.span) } diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 6b48b4dfabcf..4dc06f0d0249 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -36,7 +36,7 @@ use rustc::hir::def::Def; use rustc::hir::def_id::{DefId, DefIndex}; use middle::lang_items; use rustc::ty::{ImplContainer, TraitContainer}; -use rustc::ty::{self, Ty, TyCtxt, TypeFoldable, VariantKind}; +use rustc::ty::{self, AdtKind, Ty, TyCtxt, TypeFoldable, VariantKind}; use rustc_const_math::ConstInt; @@ -453,23 +453,19 @@ pub fn get_adt_def<'a, 'tcx>(cdata: Cmd, let mut ctor_did = None; let (kind, variants) = match item_family(doc) { Enum => { - (ty::AdtKind::Enum, - get_enum_variants(cdata, doc)) + (AdtKind::Enum, get_enum_variants(cdata, doc)) } Struct(..) => { // Use separate constructor id for unit/tuple structs and reuse did for braced structs. ctor_did = reader::maybe_get_doc(doc, tag_items_data_item_struct_ctor).map(|ctor_doc| { translated_def_id(cdata, ctor_doc) }); - (ty::AdtKind::Struct, - vec![get_struct_variant(cdata, doc, ctor_did.unwrap_or(did))]) + (AdtKind::Struct, vec![get_struct_variant(cdata, doc, ctor_did.unwrap_or(did))]) } Union => { - (ty::AdtKind::Union, - vec![get_struct_variant(cdata, doc, did)]) + (AdtKind::Union, vec![get_struct_variant(cdata, doc, did)]) } - _ => bug!("get_adt_def called on a non-ADT {:?} - {:?}", - item_family(doc), did) + _ => bug!("get_adt_def called on a non-ADT {:?} - {:?}", item_family(doc), did) }; let adt = tcx.intern_adt_def(did, kind, variants); @@ -481,8 +477,7 @@ pub fn get_adt_def<'a, 'tcx>(cdata: Cmd, // this needs to be done *after* the variant is interned, // to support recursive structures for variant in &adt.variants { - if variant.kind == ty::VariantKind::Tuple && - adt.adt_kind() == ty::AdtKind::Enum { + if variant.kind == ty::VariantKind::Tuple && adt.is_enum() { // tuple-like enum variant fields aren't real items - get the types // from the ctor. debug!("evaluating the ctor-type of {:?}", diff --git a/src/librustc_metadata/tydecode.rs b/src/librustc_metadata/tydecode.rs index 55ff4817683d..bcaf1640bc41 100644 --- a/src/librustc_metadata/tydecode.rs +++ b/src/librustc_metadata/tydecode.rs @@ -358,14 +358,6 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> { } } 'c' => return tcx.types.char, - 't' => { - assert_eq!(self.next(), '['); - let did = self.parse_def(); - let substs = self.parse_substs(); - assert_eq!(self.next(), ']'); - let def = self.tcx.lookup_adt_def(did); - return tcx.mk_enum(def, substs); - } 'x' => { assert_eq!(self.next(), '['); let trait_ref = ty::Binder(self.parse_existential_trait_ref()); @@ -470,15 +462,7 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> { let substs = self.parse_substs(); assert_eq!(self.next(), ']'); let def = self.tcx.lookup_adt_def(did); - return self.tcx.mk_struct(def, substs); - } - 'U' => { - assert_eq!(self.next(), '['); - let did = self.parse_def(); - let substs = self.parse_substs(); - assert_eq!(self.next(), ']'); - let def = self.tcx.lookup_adt_def(did); - return self.tcx.mk_union(def, substs); + return self.tcx.mk_adt(def, substs); } 'k' => { assert_eq!(self.next(), '['); diff --git a/src/librustc_metadata/tyencode.rs b/src/librustc_metadata/tyencode.rs index bef3cf3a1940..8030abf6330e 100644 --- a/src/librustc_metadata/tyencode.rs +++ b/src/librustc_metadata/tyencode.rs @@ -97,11 +97,6 @@ pub fn enc_ty<'a, 'tcx>(w: &mut Cursor>, cx: &ctxt<'a, 'tcx>, t: Ty<'tcx ast::FloatTy::F64 => write!(w, "MF"), }; } - ty::TyEnum(def, substs) => { - write!(w, "t[{}|", (cx.ds)(cx.tcx, def.did)); - enc_substs(w, cx, substs); - write!(w, "]"); - } ty::TyTrait(ref obj) => { write!(w, "x["); enc_existential_trait_ref(w, cx, obj.principal.0); @@ -165,16 +160,11 @@ pub fn enc_ty<'a, 'tcx>(w: &mut Cursor>, cx: &ctxt<'a, 'tcx>, t: Ty<'tcx ty::TyParam(p) => { write!(w, "p[{}|{}]", p.idx, p.name); } - ty::TyStruct(def, substs) => { + ty::TyAdt(def, substs) => { write!(w, "a[{}|", (cx.ds)(cx.tcx, def.did)); enc_substs(w, cx, substs); write!(w, "]"); } - ty::TyUnion(def, substs) => { - write!(w, "U[{}|", (cx.ds)(cx.tcx, def.did)); - enc_substs(w, cx, substs); - write!(w, "]"); - } ty::TyClosure(def, substs) => { write!(w, "k[{}|", (cx.ds)(cx.tcx, def)); enc_substs(w, cx, substs.func_substs); diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs index 6ea1fb503606..a40571c5d859 100644 --- a/src/librustc_mir/build/expr/as_rvalue.rs +++ b/src/librustc_mir/build/expr/as_rvalue.rs @@ -181,7 +181,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { ExprKind::Adt { adt_def, variant_index, substs, fields, base } => { // see (*) above - let is_union = adt_def.adt_kind() == ty::AdtKind::Union; + let is_union = adt_def.is_union(); let active_field_index = if is_union { Some(fields[0].name.index()) } else { None }; // first process the set of fields that were provided diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 8812287c3429..4518f8cb373f 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -19,7 +19,7 @@ use rustc::hir::def::Def; use rustc::middle::const_val::ConstVal; use rustc_const_eval as const_eval; use rustc::middle::region::CodeExtent; -use rustc::ty::{self, VariantDef, Ty}; +use rustc::ty::{self, AdtKind, VariantDef, Ty}; use rustc::ty::cast::CastKind as TyCastKind; use rustc::mir::repr::*; use rustc::hir; @@ -459,48 +459,50 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, hir::ExprStruct(_, ref fields, ref base) => { match expr_ty.sty { - ty::TyStruct(adt, substs) | ty::TyUnion(adt, substs) => { - let field_refs = field_refs(&adt.variants[0], fields); - ExprKind::Adt { - adt_def: adt, - variant_index: 0, - substs: substs, - fields: field_refs, - base: base.as_ref().map(|base| { - FruInfo { - base: base.to_ref(), - field_types: cx.tcx.tables - .borrow() - .fru_field_types[&expr.id] - .clone() - } - }) + ty::TyAdt(adt, substs) => match adt.adt_kind() { + AdtKind::Struct | AdtKind::Union => { + let field_refs = field_refs(&adt.variants[0], fields); + ExprKind::Adt { + adt_def: adt, + variant_index: 0, + substs: substs, + fields: field_refs, + base: base.as_ref().map(|base| { + FruInfo { + base: base.to_ref(), + field_types: cx.tcx.tables + .borrow() + .fru_field_types[&expr.id] + .clone() + } + }) + } } - } - ty::TyEnum(adt, substs) => { - match cx.tcx.expect_def(expr.id) { - Def::Variant(enum_id, variant_id) => { - debug_assert!(adt.did == enum_id); - assert!(base.is_none()); + AdtKind::Enum => { + match cx.tcx.expect_def(expr.id) { + Def::Variant(enum_id, variant_id) => { + debug_assert!(adt.did == enum_id); + assert!(base.is_none()); - let index = adt.variant_index_with_id(variant_id); - let field_refs = field_refs(&adt.variants[index], fields); - ExprKind::Adt { - adt_def: adt, - variant_index: index, - substs: substs, - fields: field_refs, - base: None + let index = adt.variant_index_with_id(variant_id); + let field_refs = field_refs(&adt.variants[index], fields); + ExprKind::Adt { + adt_def: adt, + variant_index: index, + substs: substs, + fields: field_refs, + base: None + } + } + ref def => { + span_bug!( + expr.span, + "unexpected def: {:?}", + def); } } - ref def => { - span_bug!( - expr.span, - "unexpected def: {:?}", - def); - } } - } + }, _ => { span_bug!( expr.span, @@ -579,13 +581,10 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, body: block::to_expr_ref(cx, body) }, hir::ExprField(ref source, name) => { let index = match cx.tcx.expr_ty_adjusted(source).sty { - ty::TyStruct(adt_def, _) | ty::TyUnion(adt_def, _) => + ty::TyAdt(adt_def, _) => adt_def.variants[0].index_of_field_named(name.node), ref ty => - span_bug!( - expr.span, - "field of non-struct: {:?}", - ty), + span_bug!(expr.span, "field of non-ADT: {:?}", ty), }; let index = index.unwrap_or_else(|| { span_bug!( @@ -680,7 +679,7 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, ty::TyFnDef(..) => def_id, // A unit struct which is used as a value. We return a completely different ExprKind // here to account for this special case. - ty::TyStruct(adt_def, substs) => return ExprKind::Adt { + ty::TyAdt(adt_def, substs) => return ExprKind::Adt { adt_def: adt_def, variant_index: 0, substs: substs, @@ -694,7 +693,7 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, // expression. ty::TyFnDef(..) => variant_id, // A unit variant, similar special case to the struct case above. - ty::TyEnum(adt_def, substs) => { + ty::TyAdt(adt_def, substs) => { debug_assert!(adt_def.did == enum_id); let index = adt_def.variant_index_with_id(variant_id); return ExprKind::Adt { diff --git a/src/librustc_mir/hair/cx/pattern.rs b/src/librustc_mir/hair/cx/pattern.rs index 30f79796aaa6..3639b165eb5a 100644 --- a/src/librustc_mir/hair/cx/pattern.rs +++ b/src/librustc_mir/hair/cx/pattern.rs @@ -198,8 +198,8 @@ impl<'patcx, 'cx, 'gcx, 'tcx> PatCx<'patcx, 'cx, 'gcx, 'tcx> { PatKind::TupleStruct(_, ref subpatterns, ddpos) => { let pat_ty = self.cx.tcx.node_id_to_type(pat.id); let adt_def = match pat_ty.sty { - ty::TyStruct(adt_def, _) | ty::TyEnum(adt_def, _) => adt_def, - _ => span_bug!(pat.span, "tuple struct pattern not applied to struct or enum"), + ty::TyAdt(adt_def, _) => adt_def, + _ => span_bug!(pat.span, "tuple struct pattern not applied to an ADT"), }; let variant_def = adt_def.variant_of_def(self.cx.tcx.expect_def(pat.id)); @@ -217,13 +217,11 @@ impl<'patcx, 'cx, 'gcx, 'tcx> PatCx<'patcx, 'cx, 'gcx, 'tcx> { PatKind::Struct(_, ref fields, _) => { let pat_ty = self.cx.tcx.node_id_to_type(pat.id); let adt_def = match pat_ty.sty { - ty::TyStruct(adt_def, _) | - ty::TyUnion(adt_def, _) | - ty::TyEnum(adt_def, _) => adt_def, + ty::TyAdt(adt_def, _) => adt_def, _ => { span_bug!( pat.span, - "struct pattern not applied to struct or enum"); + "struct pattern not applied to an ADT"); } }; let variant_def = adt_def.variant_of_def(self.cx.tcx.expect_def(pat.id)); diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs index e260b1d262ae..7fda658185e0 100644 --- a/src/librustc_mir/transform/type_check.rs +++ b/src/librustc_mir/transform/type_check.rs @@ -218,7 +218,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { } ProjectionElem::Downcast(adt_def1, index) => match base_ty.sty { - ty::TyEnum(adt_def, substs) if adt_def == adt_def1 => { + ty::TyAdt(adt_def, substs) if adt_def.is_enum() && adt_def == adt_def1 => { if index >= adt_def.variants.len() { LvalueTy::Ty { ty: span_mirbug_and_err!( @@ -281,10 +281,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { (&adt_def.variants[variant_index], substs) } LvalueTy::Ty { ty } => match ty.sty { - ty::TyStruct(adt_def, substs) | - ty::TyUnion(adt_def, substs) | - ty::TyEnum(adt_def, substs) - if adt_def.is_univariant() => { + ty::TyAdt(adt_def, substs) if adt_def.is_univariant() => { (&adt_def.variants[0], substs) } ty::TyTuple(tys) | ty::TyClosure(_, ty::ClosureSubsts { @@ -364,7 +361,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { StatementKind::SetDiscriminant{ ref lvalue, variant_index } => { let lvalue_type = lvalue.ty(mir, tcx).to_ty(tcx); let adt = match lvalue_type.sty { - TypeVariants::TyEnum(adt, _) => adt, + TypeVariants::TyAdt(adt, _) if adt.is_enum() => adt, _ => { span_bug!(stmt.source_info.span, "bad set discriminant ({:?} = {:?}): lhs is not an enum", @@ -444,9 +441,10 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { TerminatorKind::Switch { ref discr, adt_def, ref targets } => { let discr_ty = discr.ty(mir, tcx).to_ty(tcx); match discr_ty.sty { - ty::TyEnum(def, _) - if def == adt_def && adt_def.variants.len() == targets.len() - => {}, + ty::TyAdt(def, _) if def.is_enum() && + def == adt_def && + adt_def.variants.len() == targets.len() + => {}, _ => { span_mirbug!(self, term, "bad Switch ({:?} on {:?})", adt_def, discr_ty); diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs index d4e8eb51cde2..f919e42b6bd7 100644 --- a/src/librustc_passes/consts.rs +++ b/src/librustc_passes/consts.rs @@ -439,9 +439,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> { /// instead of producing errors. fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node_ty: Ty<'tcx>) { match node_ty.sty { - ty::TyStruct(def, _) | - ty::TyUnion(def, _) | - ty::TyEnum(def, _) if def.has_dtor() => { + ty::TyAdt(def, _) if def.has_dtor() => { v.add_qualif(ConstQualif::NEEDS_DROP); } _ => {} diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 8c72933c4ce4..4012c1cb3488 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -384,11 +384,9 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> { // Checks that a field is in scope. fn check_field(&mut self, span: Span, def: ty::AdtDef<'tcx>, field: ty::FieldDef<'tcx>) { - if def.adt_kind() != ty::AdtKind::Enum && - !field.vis.is_accessible_from(self.curitem, &self.tcx.map) { - let kind_descr = if def.adt_kind() == ty::AdtKind::Union { "union" } else { "struct" }; + if !def.is_enum() && !field.vis.is_accessible_from(self.curitem, &self.tcx.map) { struct_span_err!(self.tcx.sess, span, E0451, "field `{}` of {} `{}` is private", - field.name, kind_descr, self.tcx.item_path_str(def.did)) + field.name, def.variant_descr(), self.tcx.item_path_str(def.did)) .span_label(span, &format!("field `{}` is private", field.name)) .emit(); } @@ -438,7 +436,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> { // (i.e. `all_fields - fields`), just check them all, // unless the ADT is a union, then unmentioned fields // are not checked. - if adt.adt_kind() == ty::AdtKind::Union { + if adt.is_union() { for expr_field in expr_fields { self.check_field(expr.span, adt, variant.field_named(expr_field.name.node)); } @@ -511,7 +509,8 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> { } PatKind::TupleStruct(_, ref fields, ddpos) => { match self.tcx.pat_ty(pattern).sty { - ty::TyStruct(def, _) => { + // enum fields have no privacy at this time + ty::TyAdt(def, _) if !def.is_enum() => { let expected_len = def.struct_variant().fields.len(); for (i, field) in fields.iter().enumerate_and_adjust(expected_len, ddpos) { if let PatKind::Wild = field.node { @@ -520,9 +519,6 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> { self.check_field(field.span, def, &def.struct_variant().fields[i]); } } - ty::TyEnum(..) => { - // enum fields have no privacy at this time - } _ => {} } } diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index ebd0bdc71d7f..27ee5765c99f 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -1338,7 +1338,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D> }; let ty = &self.tcx.expr_ty_adjusted(&hir_node).sty; match *ty { - ty::TyStruct(def, _) => { + ty::TyAdt(def, _) => { let sub_span = self.span.sub_span_after_token(ex.span, token::Dot); if !self.span.filter_generated(sub_span, ex.span) { self.dumper.variable_ref(VariableRefData { diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 04cd72ac2d36..868e3bb1f1b7 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -420,7 +420,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { } }; match self.tcx.expr_ty_adjusted(&hir_node).sty { - ty::TyStruct(def, _) | ty::TyUnion(def, _) => { + ty::TyAdt(def, _) if !def.is_enum() => { let f = def.struct_variant().field_named(ident.node.name); let sub_span = self.span_utils.span_for_last_ident(expr.span); filter!(self.span_utils, sub_span, expr.span, None); @@ -432,14 +432,14 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { })); } _ => { - debug!("Expected struct type, found {:?}", ty); + debug!("Expected struct or union type, found {:?}", ty); None } } } ast::ExprKind::Struct(ref path, ..) => { match self.tcx.expr_ty_adjusted(&hir_node).sty { - ty::TyStruct(def, _) | ty::TyUnion(def, _) => { + ty::TyAdt(def, _) if !def.is_enum() => { let sub_span = self.span_utils.span_for_last_ident(path.span); filter!(self.span_utils, sub_span, path.span, None); Some(Data::TypeRefData(TypeRefData { @@ -450,9 +450,9 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { })) } _ => { - // FIXME ty could legitimately be a TyEnum, but then we will fail + // FIXME ty could legitimately be an enum, but then we will fail // later if we try to look up the fields. - debug!("expected TyStruct, found {:?}", ty); + debug!("expected struct or union, found {:?}", ty); None } } diff --git a/src/librustc_trans/adt.rs b/src/librustc_trans/adt.rs index 9eeefa079fb6..e8498363e45a 100644 --- a/src/librustc_trans/adt.rs +++ b/src/librustc_trans/adt.rs @@ -49,7 +49,7 @@ use std::rc::Rc; use llvm::{ValueRef, True, IntEQ, IntNE}; use rustc::ty::subst::Substs; -use rustc::ty::{self, Ty, TyCtxt}; +use rustc::ty::{self, AdtKind, Ty, TyCtxt}; use syntax::ast; use syntax::attr; use syntax::attr::IntType; @@ -179,172 +179,174 @@ fn represent_type_uncached<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, ty::TyTuple(ref elems) => { Univariant(mk_struct(cx, &elems[..], false, t)) } - ty::TyStruct(def, substs) => { - let ftys = def.struct_variant().fields.iter().map(|field| { - monomorphize::field_ty(cx.tcx(), substs, field) - }).collect::>(); - let packed = cx.tcx().lookup_packed(def.did); - - Univariant(mk_struct(cx, &ftys[..], packed, t)) - } - ty::TyUnion(def, substs) => { - let ftys = def.struct_variant().fields.iter().map(|field| { - monomorphize::field_ty(cx.tcx(), substs, field) - }).collect::>(); - let packed = cx.tcx().lookup_packed(def.did); - UntaggedUnion(mk_union(cx, &ftys[..], packed, t)) - } ty::TyClosure(_, ref substs) => { Univariant(mk_struct(cx, &substs.upvar_tys, false, t)) } - ty::TyEnum(def, substs) => { - let cases = get_cases(cx.tcx(), def, substs); - let hint = *cx.tcx().lookup_repr_hints(def.did).get(0) - .unwrap_or(&attr::ReprAny); + ty::TyAdt(def, substs) => match def.adt_kind() { + AdtKind::Struct => { + let ftys = def.struct_variant().fields.iter().map(|field| { + monomorphize::field_ty(cx.tcx(), substs, field) + }).collect::>(); + let packed = cx.tcx().lookup_packed(def.did); - if cases.is_empty() { - // Uninhabitable; represent as unit - // (Typechecking will reject discriminant-sizing attrs.) - assert_eq!(hint, attr::ReprAny); - return Univariant(mk_struct(cx, &[], false, t)); + Univariant(mk_struct(cx, &ftys[..], packed, t)) } - - if cases.iter().all(|c| c.tys.is_empty()) { - // All bodies empty -> intlike - let discrs: Vec<_> = cases.iter().map(|c| Disr::from(c.discr)).collect(); - let bounds = IntBounds { - ulo: discrs.iter().min().unwrap().0, - uhi: discrs.iter().max().unwrap().0, - slo: discrs.iter().map(|n| n.0 as i64).min().unwrap(), - shi: discrs.iter().map(|n| n.0 as i64).max().unwrap() - }; - return mk_cenum(cx, hint, &bounds); + AdtKind::Union => { + let ftys = def.struct_variant().fields.iter().map(|field| { + monomorphize::field_ty(cx.tcx(), substs, field) + }).collect::>(); + let packed = cx.tcx().lookup_packed(def.did); + UntaggedUnion(mk_union(cx, &ftys[..], packed, t)) } + AdtKind::Enum => { + let cases = get_cases(cx.tcx(), def, substs); + let hint = *cx.tcx().lookup_repr_hints(def.did).get(0) + .unwrap_or(&attr::ReprAny); - // Since there's at least one - // non-empty body, explicit discriminants should have - // been rejected by a checker before this point. - if !cases.iter().enumerate().all(|(i,c)| c.discr == Disr::from(i)) { - bug!("non-C-like enum {} with specified discriminants", - cx.tcx().item_path_str(def.did)); - } + if cases.is_empty() { + // Uninhabitable; represent as unit + // (Typechecking will reject discriminant-sizing attrs.) + assert_eq!(hint, attr::ReprAny); + return Univariant(mk_struct(cx, &[], false, t)); + } - if cases.len() == 1 && hint == attr::ReprAny { - // Equivalent to a struct/tuple/newtype. - return Univariant(mk_struct(cx, &cases[0].tys, false, t)); - } + if cases.iter().all(|c| c.tys.is_empty()) { + // All bodies empty -> intlike + let discrs: Vec<_> = cases.iter().map(|c| Disr::from(c.discr)).collect(); + let bounds = IntBounds { + ulo: discrs.iter().min().unwrap().0, + uhi: discrs.iter().max().unwrap().0, + slo: discrs.iter().map(|n| n.0 as i64).min().unwrap(), + shi: discrs.iter().map(|n| n.0 as i64).max().unwrap() + }; + return mk_cenum(cx, hint, &bounds); + } - if cases.len() == 2 && hint == attr::ReprAny { - // Nullable pointer optimization - let mut discr = 0; - while discr < 2 { - if cases[1 - discr].is_zerolen(cx, t) { - let st = mk_struct(cx, &cases[discr].tys, - false, t); - match cases[discr].find_ptr(cx) { - Some(ref df) if df.len() == 1 && st.fields.len() == 1 => { - return RawNullablePointer { - nndiscr: Disr::from(discr), - nnty: st.fields[0], - nullfields: cases[1 - discr].tys.clone() - }; + // Since there's at least one + // non-empty body, explicit discriminants should have + // been rejected by a checker before this point. + if !cases.iter().enumerate().all(|(i,c)| c.discr == Disr::from(i)) { + bug!("non-C-like enum {} with specified discriminants", + cx.tcx().item_path_str(def.did)); + } + + if cases.len() == 1 && hint == attr::ReprAny { + // Equivalent to a struct/tuple/newtype. + return Univariant(mk_struct(cx, &cases[0].tys, false, t)); + } + + if cases.len() == 2 && hint == attr::ReprAny { + // Nullable pointer optimization + let mut discr = 0; + while discr < 2 { + if cases[1 - discr].is_zerolen(cx, t) { + let st = mk_struct(cx, &cases[discr].tys, + false, t); + match cases[discr].find_ptr(cx) { + Some(ref df) if df.len() == 1 && st.fields.len() == 1 => { + return RawNullablePointer { + nndiscr: Disr::from(discr), + nnty: st.fields[0], + nullfields: cases[1 - discr].tys.clone() + }; + } + Some(mut discrfield) => { + discrfield.push(0); + discrfield.reverse(); + return StructWrappedNullablePointer { + nndiscr: Disr::from(discr), + nonnull: st, + discrfield: discrfield, + nullfields: cases[1 - discr].tys.clone() + }; + } + None => {} } - Some(mut discrfield) => { - discrfield.push(0); - discrfield.reverse(); - return StructWrappedNullablePointer { - nndiscr: Disr::from(discr), - nonnull: st, - discrfield: discrfield, - nullfields: cases[1 - discr].tys.clone() - }; - } - None => {} + } + discr += 1; + } + } + + // The general case. + assert!((cases.len() - 1) as i64 >= 0); + let bounds = IntBounds { ulo: 0, uhi: (cases.len() - 1) as u64, + slo: 0, shi: (cases.len() - 1) as i64 }; + let min_ity = range_to_inttype(cx, hint, &bounds); + + // Create the set of structs that represent each variant + // Use the minimum integer type we figured out above + let fields : Vec<_> = cases.iter().map(|c| { + let mut ftys = vec!(ty_of_inttype(cx.tcx(), min_ity)); + ftys.extend_from_slice(&c.tys); + mk_struct(cx, &ftys, false, t) + }).collect(); + + + // Check to see if we should use a different type for the + // discriminant. If the overall alignment of the type is + // the same as the first field in each variant, we can safely use + // an alignment-sized type. + // We increase the size of the discriminant to avoid LLVM copying + // padding when it doesn't need to. This normally causes unaligned + // load/stores and excessive memcpy/memset operations. By using a + // bigger integer size, LLVM can be sure about it's contents and + // won't be so conservative. + // This check is needed to avoid increasing the size of types when + // the alignment of the first field is smaller than the overall + // alignment of the type. + let (_, align) = union_size_and_align(&fields); + let mut use_align = true; + for st in &fields { + // Get the first non-zero-sized field + let field = st.fields.iter().skip(1).filter(|ty| { + let t = type_of::sizing_type_of(cx, **ty); + machine::llsize_of_real(cx, t) != 0 || + // This case is only relevant for zero-sized types with large alignment + machine::llalign_of_min(cx, t) != 1 + }).next(); + + if let Some(field) = field { + let field_align = type_of::align_of(cx, *field); + if field_align != align { + use_align = false; + break; } } - discr += 1; } - } - // The general case. - assert!((cases.len() - 1) as i64 >= 0); - let bounds = IntBounds { ulo: 0, uhi: (cases.len() - 1) as u64, - slo: 0, shi: (cases.len() - 1) as i64 }; - let min_ity = range_to_inttype(cx, hint, &bounds); + // If the alignment is smaller than the chosen discriminant size, don't use the + // alignment as the final size. + let min_ty = ll_inttype(&cx, min_ity); + let min_size = machine::llsize_of_real(cx, min_ty); + if (align as u64) < min_size { + use_align = false; + } - // Create the set of structs that represent each variant - // Use the minimum integer type we figured out above - let fields : Vec<_> = cases.iter().map(|c| { - let mut ftys = vec!(ty_of_inttype(cx.tcx(), min_ity)); - ftys.extend_from_slice(&c.tys); - mk_struct(cx, &ftys, false, t) - }).collect(); - - - // Check to see if we should use a different type for the - // discriminant. If the overall alignment of the type is - // the same as the first field in each variant, we can safely use - // an alignment-sized type. - // We increase the size of the discriminant to avoid LLVM copying - // padding when it doesn't need to. This normally causes unaligned - // load/stores and excessive memcpy/memset operations. By using a - // bigger integer size, LLVM can be sure about it's contents and - // won't be so conservative. - // This check is needed to avoid increasing the size of types when - // the alignment of the first field is smaller than the overall - // alignment of the type. - let (_, align) = union_size_and_align(&fields); - let mut use_align = true; - for st in &fields { - // Get the first non-zero-sized field - let field = st.fields.iter().skip(1).filter(|ty| { - let t = type_of::sizing_type_of(cx, **ty); - machine::llsize_of_real(cx, t) != 0 || - // This case is only relevant for zero-sized types with large alignment - machine::llalign_of_min(cx, t) != 1 - }).next(); - - if let Some(field) = field { - let field_align = type_of::align_of(cx, *field); - if field_align != align { - use_align = false; - break; + let ity = if use_align { + // Use the overall alignment + match align { + 1 => attr::UnsignedInt(ast::UintTy::U8), + 2 => attr::UnsignedInt(ast::UintTy::U16), + 4 => attr::UnsignedInt(ast::UintTy::U32), + 8 if machine::llalign_of_min(cx, Type::i64(cx)) == 8 => + attr::UnsignedInt(ast::UintTy::U64), + _ => min_ity // use min_ity as a fallback } - } + } else { + min_ity + }; + + let fields : Vec<_> = cases.iter().map(|c| { + let mut ftys = vec!(ty_of_inttype(cx.tcx(), ity)); + ftys.extend_from_slice(&c.tys); + mk_struct(cx, &ftys[..], false, t) + }).collect(); + + ensure_enum_fits_in_address_space(cx, &fields[..], t); + + General(ity, fields) } - - // If the alignment is smaller than the chosen discriminant size, don't use the - // alignment as the final size. - let min_ty = ll_inttype(&cx, min_ity); - let min_size = machine::llsize_of_real(cx, min_ty); - if (align as u64) < min_size { - use_align = false; - } - - let ity = if use_align { - // Use the overall alignment - match align { - 1 => attr::UnsignedInt(ast::UintTy::U8), - 2 => attr::UnsignedInt(ast::UintTy::U16), - 4 => attr::UnsignedInt(ast::UintTy::U32), - 8 if machine::llalign_of_min(cx, Type::i64(cx)) == 8 => - attr::UnsignedInt(ast::UintTy::U64), - _ => min_ity // use min_ity as a fallback - } - } else { - min_ity - }; - - let fields : Vec<_> = cases.iter().map(|c| { - let mut ftys = vec!(ty_of_inttype(cx.tcx(), ity)); - ftys.extend_from_slice(&c.tys); - mk_struct(cx, &ftys[..], false, t) - }).collect(); - - ensure_enum_fits_in_address_space(cx, &fields[..], t); - - General(ity, fields) - } + }, _ => bug!("adt::represent_type called on non-ADT type: {}", t) } } @@ -376,7 +378,7 @@ fn find_discr_field_candidate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty::TyFnPtr(_) => Some(path), // Is this the NonZero lang item wrapping a pointer or integer type? - ty::TyStruct(def, substs) if Some(def.did) == tcx.lang_items.non_zero() => { + ty::TyAdt(def, substs) if Some(def.did) == tcx.lang_items.non_zero() => { let nonzero_fields = &def.struct_variant().fields; assert_eq!(nonzero_fields.len(), 1); let field_ty = monomorphize::field_ty(tcx, substs, &nonzero_fields[0]); @@ -395,7 +397,7 @@ fn find_discr_field_candidate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // Perhaps one of the fields of this struct is non-zero // let's recurse and find out - ty::TyStruct(def, substs) => { + ty::TyAdt(def, substs) if def.is_struct() => { for (j, field) in def.struct_variant().fields.iter().enumerate() { let field_ty = monomorphize::field_ty(tcx, substs, field); if let Some(mut fpath) = find_discr_field_candidate(tcx, field_ty, path.clone()) { diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index ec8ab33c4ca5..a6581ae605b5 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -467,8 +467,7 @@ pub fn coerce_unsized_into<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, } // This can be extended to enums and tuples in the future. - // (&ty::TyEnum(def_id_a, _), &ty::TyEnum(def_id_b, _)) | - (&ty::TyStruct(def_a, _), &ty::TyStruct(def_b, _)) => { + (&ty::TyAdt(def_a, _), &ty::TyAdt(def_b, _)) => { assert_eq!(def_a, def_b); let src_repr = adt::represent_type(bcx.ccx(), src_ty); diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index 704fac5ce7e5..5a8ab62a2aa2 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -743,9 +743,7 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, // If the type implements Drop, also add a translation item for the // monomorphized Drop::drop() implementation. let destructor_did = match ty.sty { - ty::TyStruct(def, _) | - ty::TyUnion(def, _) | - ty::TyEnum(def, _) => def.destructor(), + ty::TyAdt(def, _) => def.destructor(), _ => None }; @@ -798,9 +796,7 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, ty::TyTrait(_) => { /* nothing to do */ } - ty::TyStruct(ref adt_def, substs) | - ty::TyUnion(ref adt_def, substs) | - ty::TyEnum(ref adt_def, substs) => { + ty::TyAdt(adt_def, substs) => { for field in adt_def.all_fields() { let field_type = monomorphize::apply_param_substs(scx, substs, @@ -989,8 +985,8 @@ fn find_vtable_types_for_unsizing<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, } } - (&ty::TyStruct(source_adt_def, source_substs), - &ty::TyStruct(target_adt_def, target_substs)) => { + (&ty::TyAdt(source_adt_def, source_substs), + &ty::TyAdt(target_adt_def, target_substs)) => { assert_eq!(source_adt_def, target_adt_def); let kind = custom_coerce_unsize_info(scx, source_ty, target_ty); diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index bd98eee8869b..e0de04d150ca 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -88,8 +88,7 @@ pub fn type_is_immediate<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) - return false; } match ty.sty { - ty::TyStruct(..) | ty::TyUnion(..) | ty::TyEnum(..) | - ty::TyTuple(..) | ty::TyArray(..) | ty::TyClosure(..) => { + ty::TyAdt(..) | ty::TyTuple(..) | ty::TyArray(..) | ty::TyClosure(..) => { let llty = sizing_type_of(ccx, ty); llsize_of_alloc(ccx, llty) <= llsize_of_alloc(ccx, ccx.int_type()) } @@ -101,7 +100,7 @@ pub fn type_is_immediate<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) - pub fn type_pair_fields<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> Option<[Ty<'tcx>; 2]> { match ty.sty { - ty::TyEnum(adt, substs) | ty::TyStruct(adt, substs) => { + ty::TyAdt(adt, substs) => { assert_eq!(adt.variants.len(), 1); let fields = &adt.variants[0].fields; if fields.len() != 2 { @@ -205,7 +204,7 @@ impl<'a, 'tcx> VariantInfo<'tcx> { -> Self { match ty.sty { - ty::TyStruct(adt, substs) | ty::TyUnion(adt, substs) | ty::TyEnum(adt, substs) => { + ty::TyAdt(adt, substs) => { let variant = match opt_def { None => adt.struct_variant(), Some(def) => adt.variant_of_def(def) diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index 2422b9f30069..b10129d1019a 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -223,13 +223,9 @@ impl<'gcx> DepTrackingMapConfig for ProjectionCache<'gcx> { let def_ids: Vec = key.walk() .filter_map(|t| match t.sty { - ty::TyStruct(adt_def, _) | - ty::TyEnum(adt_def, _) => - Some(adt_def.did), - ty::TyProjection(ref proj) => - Some(proj.trait_ref.def_id), - _ => - None + ty::TyAdt(adt_def, _) => Some(adt_def.did), + ty::TyProjection(ref proj) => Some(proj.trait_ref.def_id), + _ => None, }) .collect(); DepNode::TraitSelect(def_ids) diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index 1bf1023dcd89..31df49609cb8 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -30,7 +30,7 @@ use rustc::hir; use {type_of, adt, machine, monomorphize}; use common::CrateContext; use type_::Type; -use rustc::ty::{self, Ty}; +use rustc::ty::{self, AdtKind, Ty}; use session::config; use util::nodemap::FnvHashMap; use util::common::path2cstr; @@ -176,18 +176,10 @@ impl<'tcx> TypeMap<'tcx> { ty::TyFloat(_) => { push_debuginfo_type_name(cx, type_, false, &mut unique_type_id); }, - ty::TyEnum(def, substs) => { - unique_type_id.push_str("enum "); + ty::TyAdt(def, substs) => { + unique_type_id.push_str(&(String::from(def.descr()) + " ")); from_def_id_and_substs(self, cx, def.did, substs, &mut unique_type_id); - }, - ty::TyStruct(def, substs) => { - unique_type_id.push_str("struct "); - from_def_id_and_substs(self, cx, def.did, substs, &mut unique_type_id); - }, - ty::TyUnion(def, substs) => { - unique_type_id.push_str("union "); - from_def_id_and_substs(self, cx, def.did, substs, &mut unique_type_id); - }, + } ty::TyTuple(component_types) if component_types.is_empty() => { push_debuginfo_type_name(cx, type_, false, &mut unique_type_id); }, @@ -705,13 +697,6 @@ pub fn type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, ty::TyTuple(ref elements) if elements.is_empty() => { MetadataCreationResult::new(basic_type_metadata(cx, t), false) } - ty::TyEnum(def, _) => { - prepare_enum_metadata(cx, - t, - def.did, - unique_type_id, - usage_site_span).finalize(cx) - } ty::TyArray(typ, len) => { fixed_vec_metadata(cx, unique_type_id, typ, Some(len as u64), usage_site_span) } @@ -779,18 +764,27 @@ pub fn type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, unique_type_id, usage_site_span).finalize(cx) } - ty::TyStruct(..) => { - prepare_struct_metadata(cx, + ty::TyAdt(def, ..) => match def.adt_kind() { + AdtKind::Struct => { + prepare_struct_metadata(cx, + t, + unique_type_id, + usage_site_span).finalize(cx) + } + AdtKind::Union => { + prepare_union_metadata(cx, t, unique_type_id, usage_site_span).finalize(cx) - } - ty::TyUnion(..) => { - prepare_union_metadata(cx, - t, - unique_type_id, - usage_site_span).finalize(cx) - } + } + AdtKind::Enum => { + prepare_enum_metadata(cx, + t, + def.did, + unique_type_id, + usage_site_span).finalize(cx) + } + }, ty::TyTuple(ref elements) => { prepare_tuple_metadata(cx, t, @@ -1134,8 +1128,8 @@ fn prepare_struct_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let struct_llvm_type = type_of::in_memory_type_of(cx, struct_type); let (struct_def_id, variant, substs) = match struct_type.sty { - ty::TyStruct(def, substs) => (def.did, def.struct_variant(), substs), - _ => bug!("prepare_struct_metadata on a non-struct") + ty::TyAdt(def, substs) => (def.did, def.struct_variant(), substs), + _ => bug!("prepare_struct_metadata on a non-ADT") }; let (containing_scope, _) = get_namespace_and_span_for_item(cx, struct_def_id); @@ -1250,8 +1244,8 @@ fn prepare_union_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let union_llvm_type = type_of::in_memory_type_of(cx, union_type); let (union_def_id, variant, substs) = match union_type.sty { - ty::TyUnion(def, substs) => (def.did, def.struct_variant(), substs), - _ => bug!("prepare_union_metadata on a non-union") + ty::TyAdt(def, substs) => (def.did, def.struct_variant(), substs), + _ => bug!("prepare_union_metadata on a non-ADT") }; let (containing_scope, _) = get_namespace_and_span_for_item(cx, union_def_id); diff --git a/src/librustc_trans/debuginfo/mod.rs b/src/librustc_trans/debuginfo/mod.rs index 20a33498475a..bcd288671bc1 100644 --- a/src/librustc_trans/debuginfo/mod.rs +++ b/src/librustc_trans/debuginfo/mod.rs @@ -421,7 +421,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, // Only "class" methods are generally understood by LLVM, // so avoid methods on other types (e.g. `<*mut T>::null`). match impl_self_ty.sty { - ty::TyStruct(..) | ty::TyUnion(..) | ty::TyEnum(..) => { + ty::TyAdt(..) => { Some(type_metadata(cx, impl_self_ty, syntax_pos::DUMMY_SP)) } _ => None diff --git a/src/librustc_trans/debuginfo/type_names.rs b/src/librustc_trans/debuginfo/type_names.rs index 8291f84054d0..7f021bee3719 100644 --- a/src/librustc_trans/debuginfo/type_names.rs +++ b/src/librustc_trans/debuginfo/type_names.rs @@ -44,9 +44,7 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, ty::TyInt(int_ty) => output.push_str(int_ty.ty_to_string()), ty::TyUint(uint_ty) => output.push_str(uint_ty.ty_to_string()), ty::TyFloat(float_ty) => output.push_str(float_ty.ty_to_string()), - ty::TyStruct(def, substs) | - ty::TyUnion(def, substs) | - ty::TyEnum(def, substs) => { + ty::TyAdt(def, substs) => { push_item_name(cx, def.did, qualified, output); push_type_params(cx, substs, output); }, diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs index 34c92f334d0a..6c1c5ac2d10e 100644 --- a/src/librustc_trans/glue.rs +++ b/src/librustc_trans/glue.rs @@ -19,7 +19,7 @@ use llvm::{ValueRef, get_param}; use middle::lang_items::ExchangeFreeFnLangItem; use rustc::ty::subst::{Substs}; use rustc::traits; -use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; +use rustc::ty::{self, AdtKind, Ty, TyCtxt, TypeFoldable}; use adt; use base::*; use build::*; @@ -338,7 +338,7 @@ pub fn size_and_align_of_dst<'blk, 'tcx>(bcx: &BlockAndBuilder<'blk, 'tcx>, return (C_undef(llty), C_undef(llty)); } match t.sty { - ty::TyStruct(def, substs) => { + ty::TyAdt(def, substs) => { let ccx = bcx.ccx(); // First get the size of all statically known fields. // Don't use type_of::sizing_type_of because that expects t to be sized, @@ -487,16 +487,11 @@ fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, g: DropGlueK DebugLoc::None); bcx } - ty::TyStruct(def, _) | ty::TyEnum(def, _) - if def.dtor_kind().is_present() && !skip_dtor => { - trans_custom_dtor(bcx, t, v0, false) + ty::TyAdt(def, ..) if def.dtor_kind().is_present() && !skip_dtor => { + trans_custom_dtor(bcx, t, v0, def.is_union()) } - ty::TyUnion(def, _) => { - if def.dtor_kind().is_present() && !skip_dtor { - trans_custom_dtor(bcx, t, v0, true) - } else { - bcx - } + ty::TyAdt(def, ..) if def.is_union() => { + bcx } _ => { if bcx.fcx.type_needs_drop(t) { @@ -544,23 +539,6 @@ fn drop_structural_ty<'blk, 'tcx>(cx: Block<'blk, 'tcx>, let mut cx = cx; match t.sty { - ty::TyStruct(..) => { - let repr = adt::represent_type(cx.ccx(), t); - let VariantInfo { fields, discr } = VariantInfo::from_ty(cx.tcx(), t, None); - for (i, &Field(_, field_ty)) in fields.iter().enumerate() { - let llfld_a = adt::trans_field_ptr(cx, &repr, value, Disr::from(discr), i); - - let val = if type_is_sized(cx.tcx(), field_ty) { - llfld_a - } else { - let scratch = alloc_ty(cx, field_ty, "__fat_ptr_iter"); - Store(cx, llfld_a, get_dataptr(cx, scratch)); - Store(cx, value.meta, get_meta(cx, scratch)); - scratch - }; - cx = drop_ty(cx, val, field_ty, DebugLoc::None); - } - } ty::TyClosure(_, ref substs) => { let repr = adt::represent_type(cx.ccx(), t); for (i, upvar_ty) in substs.upvar_tys.iter().enumerate() { @@ -587,63 +565,86 @@ fn drop_structural_ty<'blk, 'tcx>(cx: Block<'blk, 'tcx>, cx = drop_ty(cx, llfld_a, *arg, DebugLoc::None); } } - ty::TyEnum(en, substs) => { - let fcx = cx.fcx; - let ccx = fcx.ccx; + ty::TyAdt(adt, substs) => match adt.adt_kind() { + AdtKind::Struct => { + let repr = adt::represent_type(cx.ccx(), t); + let VariantInfo { fields, discr } = VariantInfo::from_ty(cx.tcx(), t, None); + for (i, &Field(_, field_ty)) in fields.iter().enumerate() { + let llfld_a = adt::trans_field_ptr(cx, &repr, value, Disr::from(discr), i); - let repr = adt::represent_type(ccx, t); - let n_variants = en.variants.len(); - - // NB: we must hit the discriminant first so that structural - // comparison know not to proceed when the discriminants differ. - - match adt::trans_switch(cx, &repr, av, false) { - (adt::BranchKind::Single, None) => { - if n_variants != 0 { - assert!(n_variants == 1); - cx = iter_variant(cx, &repr, adt::MaybeSizedValue::sized(av), - &en.variants[0], substs); - } + let val = if type_is_sized(cx.tcx(), field_ty) { + llfld_a + } else { + let scratch = alloc_ty(cx, field_ty, "__fat_ptr_iter"); + Store(cx, llfld_a, get_dataptr(cx, scratch)); + Store(cx, value.meta, get_meta(cx, scratch)); + scratch + }; + cx = drop_ty(cx, val, field_ty, DebugLoc::None); } - (adt::BranchKind::Switch, Some(lldiscrim_a)) => { - cx = drop_ty(cx, lldiscrim_a, cx.tcx().types.isize, DebugLoc::None); - - // Create a fall-through basic block for the "else" case of - // the switch instruction we're about to generate. Note that - // we do **not** use an Unreachable instruction here, even - // though most of the time this basic block will never be hit. - // - // When an enum is dropped it's contents are currently - // overwritten to DTOR_DONE, which means the discriminant - // could have changed value to something not within the actual - // range of the discriminant. Currently this function is only - // used for drop glue so in this case we just return quickly - // from the outer function, and any other use case will only - // call this for an already-valid enum in which case the `ret - // void` will never be hit. - let ret_void_cx = fcx.new_block("enum-iter-ret-void"); - RetVoid(ret_void_cx, DebugLoc::None); - let llswitch = Switch(cx, lldiscrim_a, ret_void_cx.llbb, n_variants); - let next_cx = fcx.new_block("enum-iter-next"); - - for variant in &en.variants { - let variant_cx = fcx.new_block(&format!("enum-iter-variant-{}", - &variant.disr_val - .to_string())); - let case_val = adt::trans_case(cx, &repr, Disr::from(variant.disr_val)); - AddCase(llswitch, case_val, variant_cx.llbb); - let variant_cx = iter_variant(variant_cx, - &repr, - value, - variant, - substs); - Br(variant_cx, next_cx.llbb, DebugLoc::None); - } - cx = next_cx; - } - _ => ccx.sess().unimpl("value from adt::trans_switch in drop_structural_ty"), } - } + AdtKind::Union => { + bug!("Union in `glue::drop_structural_ty`"); + } + AdtKind::Enum => { + let fcx = cx.fcx; + let ccx = fcx.ccx; + + let repr = adt::represent_type(ccx, t); + let n_variants = adt.variants.len(); + + // NB: we must hit the discriminant first so that structural + // comparison know not to proceed when the discriminants differ. + + match adt::trans_switch(cx, &repr, av, false) { + (adt::BranchKind::Single, None) => { + if n_variants != 0 { + assert!(n_variants == 1); + cx = iter_variant(cx, &repr, adt::MaybeSizedValue::sized(av), + &adt.variants[0], substs); + } + } + (adt::BranchKind::Switch, Some(lldiscrim_a)) => { + cx = drop_ty(cx, lldiscrim_a, cx.tcx().types.isize, DebugLoc::None); + + // Create a fall-through basic block for the "else" case of + // the switch instruction we're about to generate. Note that + // we do **not** use an Unreachable instruction here, even + // though most of the time this basic block will never be hit. + // + // When an enum is dropped it's contents are currently + // overwritten to DTOR_DONE, which means the discriminant + // could have changed value to something not within the actual + // range of the discriminant. Currently this function is only + // used for drop glue so in this case we just return quickly + // from the outer function, and any other use case will only + // call this for an already-valid enum in which case the `ret + // void` will never be hit. + let ret_void_cx = fcx.new_block("enum-iter-ret-void"); + RetVoid(ret_void_cx, DebugLoc::None); + let llswitch = Switch(cx, lldiscrim_a, ret_void_cx.llbb, n_variants); + let next_cx = fcx.new_block("enum-iter-next"); + + for variant in &adt.variants { + let variant_cx = fcx.new_block(&format!("enum-iter-variant-{}", + &variant.disr_val + .to_string())); + let case_val = adt::trans_case(cx, &repr, Disr::from(variant.disr_val)); + AddCase(llswitch, case_val, variant_cx.llbb); + let variant_cx = iter_variant(variant_cx, + &repr, + value, + variant, + substs); + Br(variant_cx, next_cx.llbb, DebugLoc::None); + } + cx = next_cx; + } + _ => ccx.sess().unimpl("value from adt::trans_switch in drop_structural_ty"), + } + } + }, + _ => { cx.sess().unimpl(&format!("type in drop_structural_ty: {}", t)) } diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs index c0ff6c508bf3..2049696ee4f7 100644 --- a/src/librustc_trans/intrinsic.rs +++ b/src/librustc_trans/intrinsic.rs @@ -408,7 +408,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, (_, "discriminant_value") => { let val_ty = substs.type_at(0); match val_ty.sty { - ty::TyEnum(..) => { + ty::TyAdt(adt, ..) if adt.is_enum() => { let repr = adt::represent_type(ccx, val_ty); adt::trans_get_discr(bcx, &repr, llargs[0], Some(llret_ty), true) diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs index e078d46274d3..44e613c4c2b0 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -396,9 +396,7 @@ pub fn push_unique_type_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty::TyUint(ast::UintTy::U64) => output.push_str("u64"), ty::TyFloat(ast::FloatTy::F32) => output.push_str("f32"), ty::TyFloat(ast::FloatTy::F64) => output.push_str("f64"), - ty::TyStruct(adt_def, substs) | - ty::TyUnion(adt_def, substs) | - ty::TyEnum(adt_def, substs) => { + ty::TyAdt(adt_def, substs) => { push_item_name(tcx, adt_def.did, output); push_type_params(tcx, substs, &[], output); }, diff --git a/src/librustc_trans/type_of.rs b/src/librustc_trans/type_of.rs index b5565109306b..3873c24a9f67 100644 --- a/src/librustc_trans/type_of.rs +++ b/src/librustc_trans/type_of.rs @@ -89,7 +89,7 @@ pub fn sizing_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Typ Type::nil(cx) } - ty::TyStruct(..) if t.is_simd() => { + ty::TyAdt(..) if t.is_simd() => { let e = t.simd_type(cx.tcx()); if !e.is_machine() { cx.sess().fatal(&format!("monomorphising SIMD type `{}` with \ @@ -102,8 +102,7 @@ pub fn sizing_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Typ Type::vector(&llet, n) } - ty::TyTuple(..) | ty::TyStruct(..) | ty::TyUnion(..) | - ty::TyEnum(..) | ty::TyClosure(..) => { + ty::TyTuple(..) | ty::TyAdt(..) | ty::TyClosure(..) => { let repr = adt::represent_type(cx, t); adt::sizing_type_of(cx, &repr, false) } @@ -294,7 +293,7 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> let repr = adt::represent_type(cx, t); adt::type_of(cx, &repr) } - ty::TyStruct(..) if t.is_simd() => { + ty::TyAdt(..) if t.is_simd() => { let e = t.simd_type(cx.tcx()); if !e.is_machine() { cx.sess().fatal(&format!("monomorphising SIMD type `{}` with \ @@ -306,9 +305,7 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> ensure_array_fits_in_address_space(cx, llet, n, t); Type::vector(&llet, n) } - ty::TyStruct(def, ref substs) | - ty::TyUnion(def, ref substs) | - ty::TyEnum(def, ref substs) => { + ty::TyAdt(def, substs) => { // Only create the named struct, but don't fill it in. We // fill it in *after* placing it into the type cache. This // avoids creating more than one copy of the enum when one @@ -331,8 +328,7 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> // If this was an enum or struct, fill in the type now. match t.sty { - ty::TyEnum(..) | ty::TyStruct(..) | ty::TyUnion(..) | ty::TyClosure(..) - if !t.is_simd() => { + ty::TyAdt(..) | ty::TyClosure(..) if !t.is_simd() => { let repr = adt::represent_type(cx, t); adt::finish_type_of(cx, &repr, &mut llty); } diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 17fb68339198..dd3ac6ff2d45 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -617,7 +617,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if subpats.len() == variant.fields.len() || subpats.len() < variant.fields.len() && ddpos.is_some() { let substs = match pat_ty.sty { - ty::TyStruct(_, substs) | ty::TyEnum(_, substs) => substs, + ty::TyAdt(_, substs) => substs, ref ty => bug!("unexpected pattern type {:?}", ty), }; for (i, subpat) in subpats.iter().enumerate_and_adjust(variant.fields.len(), ddpos) { @@ -657,9 +657,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let tcx = self.tcx; let (substs, kind_name) = match adt_ty.sty { - ty::TyEnum(_, substs) => (substs, "variant"), - ty::TyStruct(_, substs) => (substs, "struct"), - ty::TyUnion(_, substs) => (substs, "union"), + ty::TyAdt(adt, substs) => (substs, adt.variant_descr()), _ => span_bug!(span, "struct pattern is not an ADT") }; diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index 0c9da86563ab..51a9b18392dc 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -79,7 +79,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { match t.sty { ty::TySlice(_) | ty::TyStr => Some(UnsizeKind::Length), ty::TyTrait(ref tty) => Some(UnsizeKind::Vtable(tty.principal.def_id())), - ty::TyStruct(def, substs) => { + ty::TyAdt(def, substs) if def.is_struct() => { // FIXME(arielb1): do some kind of normalization match def.struct_variant().fields.last() { None => None, diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index 88add66b7dcb..cc958fb3b234 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -16,7 +16,7 @@ use middle::free_region::FreeRegionMap; use rustc::infer; use middle::region; use rustc::ty::subst::{Subst, Substs}; -use rustc::ty::{self, Ty, TyCtxt}; +use rustc::ty::{self, AdtKind, Ty, TyCtxt}; use rustc::traits::{self, Reveal}; use util::nodemap::FnvHashSet; @@ -44,9 +44,7 @@ pub fn check_drop_impl(ccx: &CrateCtxt, drop_impl_did: DefId) -> Result<(), ()> let dtor_self_type = ccx.tcx.lookup_item_type(drop_impl_did).ty; let dtor_predicates = ccx.tcx.lookup_predicates(drop_impl_did); match dtor_self_type.sty { - ty::TyEnum(adt_def, self_to_impl_substs) | - ty::TyUnion(adt_def, self_to_impl_substs) | - ty::TyStruct(adt_def, self_to_impl_substs) => { + ty::TyAdt(adt_def, self_to_impl_substs) => { ensure_drop_params_and_item_params_correspond(ccx, drop_impl_did, dtor_self_type, @@ -301,13 +299,13 @@ pub fn check_safety_of_destructor_if_necessary<'a, 'gcx, 'tcx>( TypeContext::ADT { def_id, variant, field } => { let adt = tcx.lookup_adt_def(def_id); let variant_name = match adt.adt_kind() { - ty::AdtKind::Enum => format!("enum {} variant {}", - tcx.item_path_str(def_id), - variant), - ty::AdtKind::Struct => format!("struct {}", - tcx.item_path_str(def_id)), - ty::AdtKind::Union => format!("union {}", - tcx.item_path_str(def_id)), + AdtKind::Enum => format!("enum {} variant {}", + tcx.item_path_str(def_id), + variant), + AdtKind::Struct => format!("struct {}", + tcx.item_path_str(def_id)), + AdtKind::Union => format!("union {}", + tcx.item_path_str(def_id)), }; span_note!( &mut err, @@ -435,14 +433,14 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'b, 'gcx, 'tcx>( cx, context, ity, depth+1) } - ty::TyStruct(def, substs) if def.is_phantom_data() => { + ty::TyAdt(def, substs) if def.is_phantom_data() => { // PhantomData - behaves identically to T let ity = substs.type_at(0); iterate_over_potentially_unsafe_regions_in_type( cx, context, ity, depth+1) } - ty::TyStruct(def, substs) | ty::TyUnion(def, substs) | ty::TyEnum(def, substs) => { + ty::TyAdt(def, substs) => { let did = def.did; for variant in &def.variants { for field in variant.fields.iter() { @@ -497,7 +495,7 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'b, 'gcx, 'tcx>( fn has_dtor_of_interest<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, ty: Ty<'tcx>) -> bool { match ty.sty { - ty::TyEnum(def, _) | ty::TyStruct(def, _) | ty::TyUnion(def, _) => { + ty::TyAdt(def, _) => { def.is_dtorck(tcx) } ty::TyTrait(..) | ty::TyProjection(..) | ty::TyAnon(..) => { diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 058049992dc0..81e95c91e7ff 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -292,9 +292,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { self.assemble_inherent_candidates_from_object(self_ty, data.principal); self.assemble_inherent_impl_candidates_for_type(data.principal.def_id()); } - ty::TyEnum(def, _) | - ty::TyStruct(def, _) | - ty::TyUnion(def, _) => { + ty::TyAdt(def, _) => { self.assemble_inherent_impl_candidates_for_type(def.did); } ty::TyBox(_) => { diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index e4ea9bb407d9..3692d6fbf73d 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -165,7 +165,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let Some(expr) = rcvr_expr { for (ty, _) in self.autoderef(span, rcvr_ty) { match ty.sty { - ty::TyStruct(def, substs) | ty::TyUnion(def, substs) => { + ty::TyAdt(def, substs) if !def.is_enum() => { if let Some(field) = def.struct_variant(). find_field_named(item_name) { let snippet = tcx.sess.codemap().span_to_snippet(expr.span); @@ -359,9 +359,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { rcvr_expr: Option<&hir::Expr>) -> bool { fn is_local(ty: Ty) -> bool { match ty.sty { - ty::TyEnum(def, _) | ty::TyStruct(def, _) | ty::TyUnion(def, _) => { - def.did.is_local() - } + ty::TyAdt(def, _) => def.did.is_local(), ty::TyTrait(ref tr) => tr.principal.def_id().is_local(), diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index b059c2ab9f3a..005cd2e46b89 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1200,7 +1200,7 @@ fn check_representable<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, pub fn check_simd<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, sp: Span, id: ast::NodeId) { let t = tcx.node_id_to_type(id); match t.sty { - ty::TyStruct(def, substs) => { + ty::TyAdt(def, substs) if def.is_struct() => { let fields = &def.struct_variant().fields; if fields.is_empty() { span_err!(tcx.sess, sp, E0075, "SIMD vector cannot be empty"); @@ -2911,7 +2911,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let mut autoderef = self.autoderef(expr.span, expr_t); while let Some((base_t, autoderefs)) = autoderef.next() { match base_t.sty { - ty::TyStruct(base_def, substs) | ty::TyUnion(base_def, substs) => { + ty::TyAdt(base_def, substs) if !base_def.is_enum() => { debug!("struct named {:?}", base_t); if let Some(field) = base_def.struct_variant().find_field_named(field.node) { let field_ty = self.field_ty(expr.span, field, substs); @@ -2957,7 +2957,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { field.node, actual) }, expr_t); match expr_t.sty { - ty::TyStruct(def, _) | ty::TyUnion(def, _) => { + ty::TyAdt(def, _) if !def.is_enum() => { if let Some(suggested_field_name) = Self::suggest_field_name(def.struct_variant(), field, vec![]) { err.span_help(field.span, @@ -3009,7 +3009,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let mut autoderef = self.autoderef(expr.span, expr_t); while let Some((base_t, autoderefs)) = autoderef.next() { let field = match base_t.sty { - ty::TyStruct(base_def, substs) => { + ty::TyAdt(base_def, substs) if base_def.is_struct() => { tuple_like = base_def.struct_variant().kind == ty::VariantKind::Tuple; if !tuple_like { continue } @@ -3074,14 +3074,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { kind_name: &str) { let mut err = self.type_error_struct_with_diag( field.name.span, - |actual| if let ty::TyEnum(..) = ty.sty { - struct_span_err!(self.tcx.sess, field.name.span, E0559, - "{} `{}::{}` has no field named `{}`", - kind_name, actual, variant.name.as_str(), field.name.node) - } else { - struct_span_err!(self.tcx.sess, field.name.span, E0560, - "{} `{}` has no field named `{}`", - kind_name, actual, field.name.node) + |actual| match ty.sty { + ty::TyAdt(adt, ..) if adt.is_enum() => { + struct_span_err!(self.tcx.sess, field.name.span, E0559, + "{} `{}::{}` has no field named `{}`", + kind_name, actual, variant.name.as_str(), field.name.node) + } + _ => { + struct_span_err!(self.tcx.sess, field.name.span, E0560, + "{} `{}` has no field named `{}`", + kind_name, actual, field.name.node) + } }, ty); // prevent all specified fields from being suggested @@ -3102,9 +3105,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { check_completeness: bool) { let tcx = self.tcx; let (substs, kind_name) = match adt_ty.sty { - ty::TyEnum(_, substs) => (substs, "variant"), - ty::TyStruct(_, substs) => (substs, "struct"), - ty::TyUnion(_, substs) => (substs, "union"), + ty::TyAdt(adt, substs) => (substs, adt.variant_descr()), _ => span_bug!(span, "non-ADT passed to check_expr_struct_fields") }; @@ -3199,8 +3200,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } Def::TyAlias(did) => { match self.tcx.opt_lookup_item_type(did).map(|scheme| &scheme.ty.sty) { - Some(&ty::TyStruct(adt, _)) | - Some(&ty::TyUnion(adt, _)) => Some((did, adt.struct_variant())), + Some(&ty::TyAdt(adt, _)) if !adt.is_enum() => { + Some((did, adt.struct_variant())) + } _ => None, } } @@ -3246,7 +3248,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let &Some(ref base_expr) = base_expr { self.check_expr_has_type(base_expr, struct_ty); match struct_ty.sty { - ty::TyStruct(adt, substs) => { + ty::TyAdt(adt, substs) if adt.is_struct() => { self.tables.borrow_mut().fru_field_types.insert( expr.id, adt.struct_variant().fields.iter().map(|f| { diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index d2b7f07b9ce6..046ba5fb4523 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -22,9 +22,9 @@ use rustc::ty::{self, TyCtxt, TypeFoldable}; use rustc::traits::{self, Reveal}; use rustc::ty::{ImplOrTraitItemId, ConstTraitItemId}; use rustc::ty::{MethodTraitItemId, TypeTraitItemId, ParameterEnvironment}; -use rustc::ty::{Ty, TyBool, TyChar, TyEnum, TyError}; +use rustc::ty::{Ty, TyBool, TyChar, TyError}; use rustc::ty::{TyParam, TyRawPtr}; -use rustc::ty::{TyRef, TyStruct, TyUnion, TyTrait, TyNever, TyTuple}; +use rustc::ty::{TyRef, TyAdt, TyTrait, TyNever, TyTuple}; use rustc::ty::{TyStr, TyArray, TySlice, TyFloat, TyInfer, TyInt}; use rustc::ty::{TyUint, TyClosure, TyBox, TyFnDef, TyFnPtr}; use rustc::ty::{TyProjection, TyAnon}; @@ -69,9 +69,7 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { // Returns the def ID of the base type, if there is one. fn get_base_type_def_id(&self, span: Span, ty: Ty<'tcx>) -> Option { match ty.sty { - TyEnum(def, _) | - TyStruct(def, _) | - TyUnion(def, _) => { + TyAdt(def, _) => { Some(def.did) } @@ -241,9 +239,7 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { let self_type = tcx.lookup_item_type(impl_did); match self_type.ty.sty { - ty::TyEnum(type_def, _) | - ty::TyStruct(type_def, _) | - ty::TyUnion(type_def, _) => { + ty::TyAdt(type_def, _) => { type_def.set_destructor(method_def_id.def_id()); } _ => { @@ -426,7 +422,8 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ptr(ty)) } - (&ty::TyStruct(def_a, substs_a), &ty::TyStruct(def_b, substs_b)) => { + (&ty::TyAdt(def_a, substs_a), &ty::TyAdt(def_b, substs_b)) + if def_a.is_struct() && def_b.is_struct() => { if def_a != def_b { let source_path = tcx.item_path_str(def_a.did); let target_path = tcx.item_path_str(def_b.did); diff --git a/src/librustc_typeck/coherence/orphan.rs b/src/librustc_typeck/coherence/orphan.rs index cb424eb48e93..d1eb0f995de1 100644 --- a/src/librustc_typeck/coherence/orphan.rs +++ b/src/librustc_typeck/coherence/orphan.rs @@ -75,9 +75,7 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> { self.tcx.map.node_to_string(item.id)); let self_ty = self.tcx.lookup_item_type(def_id).ty; match self_ty.sty { - ty::TyEnum(def, _) | - ty::TyStruct(def, _) | - ty::TyUnion(def, _) => { + ty::TyAdt(def, _) => { self.check_def_id(item, def.did); } ty::TyTrait(ref data) => { @@ -294,14 +292,9 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> { { let self_ty = trait_ref.self_ty(); let opt_self_def_id = match self_ty.sty { - ty::TyStruct(self_def, _) | - ty::TyUnion(self_def, _) | - ty::TyEnum(self_def, _) => - Some(self_def.did), - ty::TyBox(..) => - self.tcx.lang_items.owned_box(), - _ => - None + ty::TyAdt(self_def, _) => Some(self_def.did), + ty::TyBox(..) => self.tcx.lang_items.owned_box(), + _ => None, }; let msg = match opt_self_def_id { diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index fcc0b09e31ac..082690149c9d 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -67,7 +67,7 @@ use rustc_const_eval::EvalHint::UncheckedExprHint; use rustc_const_eval::{eval_const_expr_partial, report_const_eval_err}; use rustc::ty::subst::Substs; use rustc::ty::{ToPredicate, ImplContainer, ImplOrTraitItemContainer, TraitContainer}; -use rustc::ty::{self, ToPolyTraitRef, Ty, TyCtxt, TypeScheme}; +use rustc::ty::{self, AdtKind, ToPolyTraitRef, Ty, TyCtxt, TypeScheme}; use rustc::ty::{VariantKind}; use rustc::ty::util::IntTypeExt; use rscope::*; @@ -1062,7 +1062,7 @@ fn convert_struct_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let ctor_id = if !def.is_struct() { Some(ccx.tcx.map.local_def_id(def.id())) } else { None }; let variants = vec![convert_struct_variant(ccx, ctor_id.unwrap_or(did), it.name, ConstInt::Infer(0), def)]; - let adt = ccx.tcx.intern_adt_def(did, ty::AdtKind::Struct, variants); + let adt = ccx.tcx.intern_adt_def(did, AdtKind::Struct, variants); if let Some(ctor_id) = ctor_id { // Make adt definition available through constructor id as well. ccx.tcx.insert_adt_def(ctor_id, adt); @@ -1077,7 +1077,7 @@ fn convert_union_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, { let did = ccx.tcx.map.local_def_id(it.id); let variants = vec![convert_struct_variant(ccx, did, it.name, ConstInt::Infer(0), def)]; - ccx.tcx.intern_adt_def(did, ty::AdtKind::Union, variants) + ccx.tcx.intern_adt_def(did, AdtKind::Union, variants) } fn evaluate_disr_expr(ccx: &CrateCtxt, repr_ty: attr::IntType, e: &hir::Expr) @@ -1157,7 +1157,7 @@ fn convert_enum_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let did = tcx.map.local_def_id(v.node.data.id()); convert_struct_variant(ccx, did, v.node.name, disr, &v.node.data) }).collect(); - tcx.intern_adt_def(tcx.map.local_def_id(it.id), ty::AdtKind::Enum, variants) + tcx.intern_adt_def(tcx.map.local_def_id(it.id), AdtKind::Enum, variants) } /// Ensures that the super-predicates of the trait with def-id @@ -1581,17 +1581,17 @@ fn type_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, ItemEnum(ref ei, ref generics) => { let def = convert_enum_def(ccx, item, ei); let substs = mk_item_substs(&ccx.icx(generics), item.span, def_id); - ccx.tcx.mk_enum(def, substs) + ccx.tcx.mk_adt(def, substs) } ItemStruct(ref si, ref generics) => { let def = convert_struct_def(ccx, item, si); let substs = mk_item_substs(&ccx.icx(generics), item.span, def_id); - ccx.tcx.mk_struct(def, substs) + ccx.tcx.mk_adt(def, substs) } ItemUnion(ref un, ref generics) => { let def = convert_union_def(ccx, item, un); let substs = mk_item_substs(&ccx.icx(generics), item.span, def_id); - ccx.tcx.mk_union(def, substs) + ccx.tcx.mk_adt(def, substs) } ItemDefaultImpl(..) | ItemTrait(..) | diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs index 1e38f464651b..b18792d89428 100644 --- a/src/librustc_typeck/variance/constraints.rs +++ b/src/librustc_typeck/variance/constraints.rs @@ -344,9 +344,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { } } - ty::TyEnum(def, substs) | - ty::TyStruct(def, substs) | - ty::TyUnion(def, substs) => { + ty::TyAdt(def, substs) => { let item_type = self.tcx().lookup_item_type(def.did); // This edge is actually implied by the call to diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 18c12f98fb42..f1b907e70d74 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -238,7 +238,7 @@ fn build_type<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>, let t = tcx.lookup_item_type(did); let predicates = tcx.lookup_predicates(did); match t.ty.sty { - ty::TyEnum(edef, _) if !tcx.sess.cstore.is_typedef(did) => { + ty::TyAdt(edef, _) if edef.is_enum() && !tcx.sess.cstore.is_typedef(did) => { return clean::EnumItem(clean::Enum { generics: (t.generics, &predicates).clean(cx), variants_stripped: false, diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 79c66be5e57d..b9dc75cdd9f1 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -41,7 +41,7 @@ use rustc::hir::def_id::{DefId, DefIndex, CRATE_DEF_INDEX}; use rustc::hir::fold::Folder; use rustc::hir::print as pprust; use rustc::ty::subst::Substs; -use rustc::ty; +use rustc::ty::{self, AdtKind}; use rustc::middle::stability; use rustc::util::nodemap::{FnvHashMap, FnvHashSet}; @@ -1811,14 +1811,12 @@ impl<'tcx> Clean for ty::Ty<'tcx> { decl: (cx.map.local_def_id(0), &fty.sig).clean(cx), abi: fty.abi, }), - ty::TyStruct(def, substs) | - ty::TyUnion(def, substs) | - ty::TyEnum(def, substs) => { + ty::TyAdt(def, substs) => { let did = def.did; - let kind = match self.sty { - ty::TyStruct(..) => TypeStruct, - ty::TyUnion(..) => TypeUnion, - _ => TypeEnum, + let kind = match def.adt_kind() { + AdtKind::Struct => TypeStruct, + AdtKind::Union => TypeUnion, + AdtKind::Enum => TypeEnum, }; inline::record_extern_fqn(cx, did, kind); let path = external_path(cx, &cx.tcx().item_name(did).as_str(), diff --git a/src/test/run-pass/auxiliary/issue13507.rs b/src/test/run-pass/auxiliary/issue13507.rs index 4cb846b51868..ca1027b11adc 100644 --- a/src/test/run-pass/auxiliary/issue13507.rs +++ b/src/test/run-pass/auxiliary/issue13507.rs @@ -75,13 +75,13 @@ pub mod testtypes { fn foo_method(&self) -> usize; } - // Tests TyStruct + // Tests struct pub struct FooStruct { pub pub_foo_field: usize, foo_field: usize } - // Tests TyEnum + // Tests enum pub enum FooEnum { VarA(usize), VarB(usize, usize) From 553d5f0a38a1ce79e78e7216b493e95b63d29563 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Tue, 6 Sep 2016 01:26:02 +0300 Subject: [PATCH 267/443] Address comments --- src/librustc/ty/layout.rs | 446 ++++++++++++++++++-------------------- src/librustc/ty/util.rs | 35 ++- 2 files changed, 231 insertions(+), 250 deletions(-) diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 3c0aa041d2dd..e3f3da916a0a 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -15,7 +15,7 @@ pub use self::Primitive::*; use infer::InferCtxt; use session::Session; use traits; -use ty::{self, AdtKind, Ty, TyCtxt, TypeFoldable}; +use ty::{self, Ty, TyCtxt, TypeFoldable}; use syntax::ast::{FloatTy, IntTy, UintTy}; use syntax::attr; @@ -555,7 +555,7 @@ impl<'a, 'gcx, 'tcx> Struct { } // Is this the NonZero lang item wrapping a pointer or integer type? - (&Univariant { non_zero: true, .. }, &ty::TyAdt(def, substs)) if def.is_struct() => { + (&Univariant { non_zero: true, .. }, &ty::TyAdt(def, substs)) => { let fields = &def.struct_variant().fields; assert_eq!(fields.len(), 1); match *fields[0].ty(tcx, substs).layout(infcx)? { @@ -918,243 +918,229 @@ impl<'a, 'gcx, 'tcx> Layout { Univariant { variant: st, non_zero: false } } + // SIMD vector types. + ty::TyAdt(def, ..) if def.is_simd() => { + let element = ty.simd_type(tcx); + match *element.layout(infcx)? { + Scalar { value, .. } => { + return success(Vector { + element: value, + count: ty.simd_size(tcx) as u64 + }); + } + _ => { + tcx.sess.fatal(&format!("monomorphising SIMD type `{}` with \ + a non-machine element type `{}`", + ty, element)); + } + } + } + // ADTs. - ty::TyAdt(def, substs) => match def.adt_kind() { - AdtKind::Struct => { - if ty.is_simd() { - // SIMD vector types. - let element = ty.simd_type(tcx); - match *element.layout(infcx)? { - Scalar { value, .. } => { - return success(Vector { - element: value, - count: ty.simd_size(tcx) as u64 - }); - } - _ => { - tcx.sess.fatal(&format!("monomorphising SIMD type `{}` with \ - a non-machine element type `{}`", - ty, element)); - } - } + ty::TyAdt(def, substs) => { + let hint = *tcx.lookup_repr_hints(def.did).get(0) + .unwrap_or(&attr::ReprAny); + + if def.variants.is_empty() { + // Uninhabitable; represent as unit + // (Typechecking will reject discriminant-sizing attrs.) + assert_eq!(hint, attr::ReprAny); + + return success(Univariant { + variant: Struct::new(dl, false), + non_zero: false + }); + } + + if def.is_enum() && def.variants.iter().all(|v| v.fields.is_empty()) { + // All bodies empty -> intlike + let (mut min, mut max) = (i64::MAX, i64::MIN); + for v in &def.variants { + let x = v.disr_val.to_u64_unchecked() as i64; + if x < min { min = x; } + if x > max { max = x; } } - let fields = def.struct_variant().fields.iter().map(|field| { + + let (discr, signed) = Integer::repr_discr(tcx, hint, min, max); + return success(CEnum { + discr: discr, + signed: signed, + min: min as u64, + max: max as u64 + }); + } + + if def.variants.len() == 1 { + // Struct, or union, or univariant enum equivalent to a struct. + // (Typechecking will reject discriminant-sizing attrs.) + assert!(!def.is_enum() || hint == attr::ReprAny); + let fields = def.variants[0].fields.iter().map(|field| { field.ty(tcx, substs).layout(infcx) }); let packed = tcx.lookup_packed(def.did); - let mut st = Struct::new(dl, packed); - st.extend(dl, fields, ty)?; - - Univariant { - variant: st, - non_zero: Some(def.did) == tcx.lang_items.non_zero() - } - } - AdtKind::Union => { - let fields = def.struct_variant().fields.iter().map(|field| { - field.ty(tcx, substs).layout(infcx) - }); - let packed = tcx.lookup_packed(def.did); - let mut un = Union::new(dl, packed); - un.extend(dl, fields, ty)?; - UntaggedUnion { variants: un } - } - AdtKind::Enum => { - let hint = *tcx.lookup_repr_hints(def.did).get(0) - .unwrap_or(&attr::ReprAny); - - if def.variants.is_empty() { - // Uninhabitable; represent as unit - // (Typechecking will reject discriminant-sizing attrs.) - assert_eq!(hint, attr::ReprAny); - - return success(Univariant { - variant: Struct::new(dl, false), - non_zero: false - }); - } - - if def.variants.iter().all(|v| v.fields.is_empty()) { - // All bodies empty -> intlike - let (mut min, mut max) = (i64::MAX, i64::MIN); - for v in &def.variants { - let x = v.disr_val.to_u64_unchecked() as i64; - if x < min { min = x; } - if x > max { max = x; } - } - - let (discr, signed) = Integer::repr_discr(tcx, hint, min, max); - return success(CEnum { - discr: discr, - signed: signed, - min: min as u64, - max: max as u64 - }); - } - - // Since there's at least one - // non-empty body, explicit discriminants should have - // been rejected by a checker before this point. - for (i, v) in def.variants.iter().enumerate() { - if i as u64 != v.disr_val.to_u64_unchecked() { - bug!("non-C-like enum {} with specified discriminants", - tcx.item_path_str(def.did)); - } - } - - if def.variants.len() == 1 { - // Equivalent to a struct/tuple/newtype. - // (Typechecking will reject discriminant-sizing attrs.) - assert_eq!(hint, attr::ReprAny); - let fields = def.variants[0].fields.iter().map(|field| { - field.ty(tcx, substs).layout(infcx) - }); - let mut st = Struct::new(dl, false); - st.extend(dl, fields, ty)?; - return success(Univariant { variant: st, non_zero: false }); - } - - // Cache the substituted and normalized variant field types. - let variants = def.variants.iter().map(|v| { - v.fields.iter().map(|field| field.ty(tcx, substs)).collect::>() - }).collect::>(); - - if variants.len() == 2 && hint == attr::ReprAny { - // Nullable pointer optimization - for discr in 0..2 { - let other_fields = variants[1 - discr].iter().map(|ty| { - ty.layout(infcx) - }); - if !Struct::would_be_zero_sized(dl, other_fields)? { - continue; - } - let path = Struct::non_zero_field_path(infcx, - variants[discr].iter().cloned())?; - let mut path = if let Some(p) = path { p } else { continue }; - - // FIXME(eddyb) should take advantage of a newtype. - if path == &[0] && variants[discr].len() == 1 { - match *variants[discr][0].layout(infcx)? { - Scalar { value, .. } => { - return success(RawNullablePointer { - nndiscr: discr as u64, - value: value - }); - } - _ => { - bug!("Layout::compute: `{}`'s non-zero \ - `{}` field not scalar?!", - ty, variants[discr][0]) - } - } - } - - path.push(0); // For GEP through a pointer. - path.reverse(); - let mut st = Struct::new(dl, false); - st.extend(dl, variants[discr].iter().map(|ty| ty.layout(infcx)), ty)?; - return success(StructWrappedNullablePointer { - nndiscr: discr as u64, - nonnull: st, - discrfield: path - }); - } - } - - // The general case. - let discr_max = (variants.len() - 1) as i64; - assert!(discr_max >= 0); - let (min_ity, _) = Integer::repr_discr(tcx, hint, 0, discr_max); - - let mut align = dl.aggregate_align; - let mut size = Size::from_bytes(0); - - // We're interested in the smallest alignment, so start large. - let mut start_align = Align::from_bytes(256, 256).unwrap(); - - // Create the set of structs that represent each variant - // Use the minimum integer type we figured out above - let discr = Some(Scalar { value: Int(min_ity), non_zero: false }); - let mut variants = variants.into_iter().map(|fields| { - let mut found_start = false; - let fields = fields.into_iter().map(|field| { - let field = field.layout(infcx)?; - if !found_start { - // Find the first field we can't move later - // to make room for a larger discriminant. - let field_align = field.align(dl); - if field.size(dl).bytes() != 0 || field_align.abi() != 1 { - start_align = start_align.min(field_align); - found_start = true; - } - } - Ok(field) - }); - let mut st = Struct::new(dl, false); - st.extend(dl, discr.iter().map(Ok).chain(fields), ty)?; - size = cmp::max(size, st.min_size()); - align = align.max(st.align); - Ok(st) - }).collect::, _>>()?; - - // Align the maximum variant size to the largest alignment. - size = size.abi_align(align); - - if size.bytes() >= dl.obj_size_bound() { - return Err(LayoutError::SizeOverflow(ty)); - } - - // Check to see if we should use a different type for the - // discriminant. We can safely use a type with the same size - // as the alignment of the first field of each variant. - // We increase the size of the discriminant to avoid LLVM copying - // padding when it doesn't need to. This normally causes unaligned - // load/stores and excessive memcpy/memset operations. By using a - // bigger integer size, LLVM can be sure about it's contents and - // won't be so conservative. - - // Use the initial field alignment - let wanted = start_align.abi(); - let mut ity = min_ity; - for &candidate in &[I16, I32, I64] { - let ty = Int(candidate); - if wanted == ty.align(dl).abi() && wanted == ty.size(dl).bytes() { - ity = candidate; - break; - } - } - - // FIXME(eddyb) conservative only to avoid diverging from trans::adt. - if align.abi() != start_align.abi() { - ity = min_ity; - } - - // If the alignment is not larger than the chosen discriminant size, - // don't use the alignment as the final size. - if ity <= min_ity { - ity = min_ity; + let layout = if def.is_union() { + let mut un = Union::new(dl, packed); + un.extend(dl, fields, ty)?; + UntaggedUnion { variants: un } } else { - // Patch up the variants' first few fields. - let old_ity_size = Int(min_ity).size(dl); - let new_ity_size = Int(ity).size(dl); - for variant in &mut variants { - for offset in &mut variant.offset_after_field { - if *offset > old_ity_size { - break; - } - *offset = new_ity_size; - } - } - } + let mut st = Struct::new(dl, packed); + st.extend(dl, fields, ty)?; + let non_zero = Some(def.did) == tcx.lang_items.non_zero(); + Univariant { variant: st, non_zero: non_zero } + }; + return success(layout); + } - General { - discr: ity, - variants: variants, - size: size, - align: align + // Since there's at least one + // non-empty body, explicit discriminants should have + // been rejected by a checker before this point. + for (i, v) in def.variants.iter().enumerate() { + if i as u64 != v.disr_val.to_u64_unchecked() { + bug!("non-C-like enum {} with specified discriminants", + tcx.item_path_str(def.did)); } } - }, + + // Cache the substituted and normalized variant field types. + let variants = def.variants.iter().map(|v| { + v.fields.iter().map(|field| field.ty(tcx, substs)).collect::>() + }).collect::>(); + + if variants.len() == 2 && hint == attr::ReprAny { + // Nullable pointer optimization + for discr in 0..2 { + let other_fields = variants[1 - discr].iter().map(|ty| { + ty.layout(infcx) + }); + if !Struct::would_be_zero_sized(dl, other_fields)? { + continue; + } + let path = Struct::non_zero_field_path(infcx, + variants[discr].iter().cloned())?; + let mut path = if let Some(p) = path { p } else { continue }; + + // FIXME(eddyb) should take advantage of a newtype. + if path == &[0] && variants[discr].len() == 1 { + match *variants[discr][0].layout(infcx)? { + Scalar { value, .. } => { + return success(RawNullablePointer { + nndiscr: discr as u64, + value: value + }); + } + _ => { + bug!("Layout::compute: `{}`'s non-zero \ + `{}` field not scalar?!", + ty, variants[discr][0]) + } + } + } + + path.push(0); // For GEP through a pointer. + path.reverse(); + let mut st = Struct::new(dl, false); + st.extend(dl, variants[discr].iter().map(|ty| ty.layout(infcx)), ty)?; + return success(StructWrappedNullablePointer { + nndiscr: discr as u64, + nonnull: st, + discrfield: path + }); + } + } + + // The general case. + let discr_max = (variants.len() - 1) as i64; + assert!(discr_max >= 0); + let (min_ity, _) = Integer::repr_discr(tcx, hint, 0, discr_max); + + let mut align = dl.aggregate_align; + let mut size = Size::from_bytes(0); + + // We're interested in the smallest alignment, so start large. + let mut start_align = Align::from_bytes(256, 256).unwrap(); + + // Create the set of structs that represent each variant + // Use the minimum integer type we figured out above + let discr = Some(Scalar { value: Int(min_ity), non_zero: false }); + let mut variants = variants.into_iter().map(|fields| { + let mut found_start = false; + let fields = fields.into_iter().map(|field| { + let field = field.layout(infcx)?; + if !found_start { + // Find the first field we can't move later + // to make room for a larger discriminant. + let field_align = field.align(dl); + if field.size(dl).bytes() != 0 || field_align.abi() != 1 { + start_align = start_align.min(field_align); + found_start = true; + } + } + Ok(field) + }); + let mut st = Struct::new(dl, false); + st.extend(dl, discr.iter().map(Ok).chain(fields), ty)?; + size = cmp::max(size, st.min_size()); + align = align.max(st.align); + Ok(st) + }).collect::, _>>()?; + + // Align the maximum variant size to the largest alignment. + size = size.abi_align(align); + + if size.bytes() >= dl.obj_size_bound() { + return Err(LayoutError::SizeOverflow(ty)); + } + + // Check to see if we should use a different type for the + // discriminant. We can safely use a type with the same size + // as the alignment of the first field of each variant. + // We increase the size of the discriminant to avoid LLVM copying + // padding when it doesn't need to. This normally causes unaligned + // load/stores and excessive memcpy/memset operations. By using a + // bigger integer size, LLVM can be sure about it's contents and + // won't be so conservative. + + // Use the initial field alignment + let wanted = start_align.abi(); + let mut ity = min_ity; + for &candidate in &[I16, I32, I64] { + let ty = Int(candidate); + if wanted == ty.align(dl).abi() && wanted == ty.size(dl).bytes() { + ity = candidate; + break; + } + } + + // FIXME(eddyb) conservative only to avoid diverging from trans::adt. + if align.abi() != start_align.abi() { + ity = min_ity; + } + + // If the alignment is not larger than the chosen discriminant size, + // don't use the alignment as the final size. + if ity <= min_ity { + ity = min_ity; + } else { + // Patch up the variants' first few fields. + let old_ity_size = Int(min_ity).size(dl); + let new_ity_size = Int(ity).size(dl); + for variant in &mut variants { + for offset in &mut variant.offset_after_field { + if *offset > old_ity_size { + break; + } + *offset = new_ity_size; + } + } + } + + General { + discr: ity, + variants: variants, + size: size, + align: align + } + } // Types with no meaningful known layout. ty::TyProjection(_) | ty::TyAnon(..) => { diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 68de8d96f33d..6b3ebaa895fa 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -253,15 +253,13 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// if not a structure at all. Corresponds to the only possible unsized /// field, and its type can be used to determine unsizing strategy. pub fn struct_tail(self, mut ty: Ty<'tcx>) -> Ty<'tcx> { - loop { - match ty.sty { - TyAdt(def, substs) if def.is_struct() => { - match def.struct_variant().fields.last() { - Some(f) => ty = f.ty(self, substs), - None => break - } - } - _ => break + while let TyAdt(def, substs) = ty.sty { + if !def.is_struct() { + break + } + match def.struct_variant().fields.last() { + Some(f) => ty = f.ty(self, substs), + None => break } } ty @@ -277,17 +275,14 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { target: Ty<'tcx>) -> (Ty<'tcx>, Ty<'tcx>) { let (mut a, mut b) = (source, target); - loop { - match (&a.sty, &b.sty) { - (&TyAdt(a_def, a_substs), &TyAdt(b_def, b_substs)) - if a_def == b_def && a_def.is_struct() => { - match a_def.struct_variant().fields.last() { - Some(f) => { - a = f.ty(self, a_substs); - b = f.ty(self, b_substs); - } - _ => break - } + while let (&TyAdt(a_def, a_substs), &TyAdt(b_def, b_substs)) = (&a.sty, &b.sty) { + if a_def != b_def || !a_def.is_struct() { + break + } + match a_def.struct_variant().fields.last() { + Some(f) => { + a = f.ty(self, a_substs); + b = f.ty(self, b_substs); } _ => break } From 76a2f9f4542ccb15d6eb2426b162ce91094f04e2 Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Thu, 8 Sep 2016 22:59:21 +0200 Subject: [PATCH 268/443] fix feature error, test fallout --- src/librustc_typeck/rscope.rs | 18 +++++++++--------- src/test/compile-fail/const-unsized.rs | 2 -- src/test/compile-fail/issue-24446.rs | 1 - 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/src/librustc_typeck/rscope.rs b/src/librustc_typeck/rscope.rs index be44dce8a8ac..131ecfc6e0c7 100644 --- a/src/librustc_typeck/rscope.rs +++ b/src/librustc_typeck/rscope.rs @@ -229,17 +229,9 @@ impl<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> StaticRscope<'a, 'gcx, 'tcx> { impl<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> RegionScope for StaticRscope<'a, 'gcx, 'tcx> { fn anon_regions(&self, - _span: Span, + span: Span, count: usize) -> Result, Option>> { - Ok(vec![ty::ReStatic; count]) - } - - fn object_lifetime_default(&self, span: Span) -> Option { - Some(self.base_object_lifetime_default(span)) - } - - fn base_object_lifetime_default(&self, span: Span) -> ty::Region { if !self.tcx.sess.features.borrow().static_in_const { self.tcx .sess @@ -248,6 +240,14 @@ impl<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> RegionScope for StaticRscope<'a, 'gcx, 'tcx> `static_in_const` feature, see #35897") .emit(); } + Ok(vec![ty::ReStatic; count]) + } + + fn object_lifetime_default(&self, span: Span) -> Option { + Some(self.base_object_lifetime_default(span)) + } + + fn base_object_lifetime_default(&self, _span: Span) -> ty::Region { ty::ReStatic } } diff --git a/src/test/compile-fail/const-unsized.rs b/src/test/compile-fail/const-unsized.rs index d3c0bf002135..a73164b957c8 100644 --- a/src/test/compile-fail/const-unsized.rs +++ b/src/test/compile-fail/const-unsized.rs @@ -15,7 +15,6 @@ const CONST_0: Debug+Sync = *(&0 as &(Debug+Sync)); //~| NOTE `std::fmt::Debug + Sync + 'static: std::marker::Sized` not satisfied //~| NOTE does not have a constant size known at compile-time //~| NOTE constant expressions must have a statically known size -//~| ERROR this needs a `'static` lifetime or the `static_in_const` feature const CONST_FOO: str = *"foo"; //~^ ERROR `str: std::marker::Sized` is not satisfied @@ -28,7 +27,6 @@ static STATIC_1: Debug+Sync = *(&1 as &(Debug+Sync)); //~| NOTE `std::fmt::Debug + Sync + 'static: std::marker::Sized` not satisfied //~| NOTE does not have a constant size known at compile-time //~| NOTE constant expressions must have a statically known size -//~| ERROR this needs a `'static` lifetime or the `static_in_const` feature static STATIC_BAR: str = *"bar"; //~^ ERROR `str: std::marker::Sized` is not satisfied diff --git a/src/test/compile-fail/issue-24446.rs b/src/test/compile-fail/issue-24446.rs index bcc1d3c3e42d..acd50bcf9e11 100644 --- a/src/test/compile-fail/issue-24446.rs +++ b/src/test/compile-fail/issue-24446.rs @@ -12,7 +12,6 @@ fn main() { static foo: Fn() -> u32 = || -> u32 { //~^ ERROR: mismatched types //~| ERROR: `std::ops::Fn() -> u32 + 'static: std::marker::Sized` is not satisfied - //~| ERROR: this needs a `'static` lifetime or the `static_in_const` feature 0 }; } From aadbcffb7c59718834c63c20ab7ce6276aef430c Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 26 Aug 2016 19:23:42 +0300 Subject: [PATCH 269/443] Issue deprecation warnings for safe accesses to extern statics --- src/doc/book/ffi.md | 2 +- src/libpanic_unwind/seh.rs | 4 +- src/librustc/lint/builtin.rs | 9 ++++- src/librustc/middle/effect.rs | 40 ++++++++++++++----- src/librustc_lint/lib.rs | 4 ++ .../compile-fail/auxiliary/extern-statics.rs | 14 +++++++ src/test/compile-fail/linkage2.rs | 2 +- src/test/compile-fail/linkage3.rs | 2 +- .../compile-fail/safe-extern-statics-mut.rs | 28 +++++++++++++ src/test/compile-fail/safe-extern-statics.rs | 32 +++++++++++++++ .../check-static-recursion-foreign.rs | 2 +- 11 files changed, 123 insertions(+), 16 deletions(-) create mode 100644 src/test/compile-fail/auxiliary/extern-statics.rs create mode 100644 src/test/compile-fail/safe-extern-statics-mut.rs create mode 100644 src/test/compile-fail/safe-extern-statics.rs diff --git a/src/doc/book/ffi.md b/src/doc/book/ffi.md index 1dea15311ce8..8709c3f4b7b1 100644 --- a/src/doc/book/ffi.md +++ b/src/doc/book/ffi.md @@ -471,7 +471,7 @@ extern { fn main() { println!("You have readline version {} installed.", - rl_readline_version as i32); + unsafe { rl_readline_version as i32 }); } ``` diff --git a/src/libpanic_unwind/seh.rs b/src/libpanic_unwind/seh.rs index dd6e92fe9ae1..589642149300 100644 --- a/src/libpanic_unwind/seh.rs +++ b/src/libpanic_unwind/seh.rs @@ -232,13 +232,13 @@ extern "C" { // Again, I'm not entirely sure what this is describing, it just seems to work. #[cfg_attr(not(test), lang = "msvc_try_filter")] static mut TYPE_DESCRIPTOR1: _TypeDescriptor = _TypeDescriptor { - pVFTable: &TYPE_INFO_VTABLE as *const _ as *const _, + pVFTable: unsafe { &TYPE_INFO_VTABLE } as *const _ as *const _, spare: 0 as *mut _, name: imp::NAME1, }; static mut TYPE_DESCRIPTOR2: _TypeDescriptor = _TypeDescriptor { - pVFTable: &TYPE_INFO_VTABLE as *const _ as *const _, + pVFTable: unsafe { &TYPE_INFO_VTABLE } as *const _ as *const _, spare: 0 as *mut _, name: imp::NAME2, }; diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index ed94e5fe377c..fa77c911b465 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -192,6 +192,12 @@ declare_lint! { "lifetimes or labels named `'_` were erroneously allowed" } +declare_lint! { + pub SAFE_EXTERN_STATICS, + Warn, + "safe access to extern statics was erroneously allowed" +} + /// Does nothing as a lint pass, but registers some `Lint`s /// which are used by other parts of the compiler. #[derive(Copy, Clone)] @@ -228,7 +234,8 @@ impl LintPass for HardwiredLints { RENAMED_AND_REMOVED_LINTS, SUPER_OR_SELF_IN_GLOBAL_PATH, HR_LIFETIME_IN_ASSOC_TYPE, - LIFETIME_UNDERSCORE + LIFETIME_UNDERSCORE, + SAFE_EXTERN_STATICS ) } } diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs index a7af0b50b849..082db569e18c 100644 --- a/src/librustc/middle/effect.rs +++ b/src/librustc/middle/effect.rs @@ -15,6 +15,7 @@ use self::RootUnsafeContext::*; use dep_graph::DepNode; use ty::{self, Ty, TyCtxt}; use ty::MethodCall; +use lint; use syntax::ast; use syntax_pos::Span; @@ -57,16 +58,25 @@ struct EffectCheckVisitor<'a, 'tcx: 'a> { } impl<'a, 'tcx> EffectCheckVisitor<'a, 'tcx> { - fn require_unsafe(&mut self, span: Span, description: &str) { + fn require_unsafe_ext(&mut self, node_id: ast::NodeId, span: Span, + description: &str, is_lint: bool) { if self.unsafe_context.push_unsafe_count > 0 { return; } match self.unsafe_context.root { SafeContext => { - // Report an error. - struct_span_err!( - self.tcx.sess, span, E0133, - "{} requires unsafe function or block", description) - .span_label(span, &description) - .emit(); + if is_lint { + self.tcx.sess.add_lint(lint::builtin::SAFE_EXTERN_STATICS, + node_id, + span, + format!("{} requires unsafe function or \ + block (error E0133)", description)); + } else { + // Report an error. + struct_span_err!( + self.tcx.sess, span, E0133, + "{} requires unsafe function or block", description) + .span_label(span, &description) + .emit(); + } } UnsafeBlock(block_id) => { // OK, but record this. @@ -76,6 +86,10 @@ impl<'a, 'tcx> EffectCheckVisitor<'a, 'tcx> { UnsafeFn => {} } } + + fn require_unsafe(&mut self, span: Span, description: &str) { + self.require_unsafe_ext(ast::DUMMY_NODE_ID, span, description, false) + } } impl<'a, 'tcx, 'v> Visitor<'v> for EffectCheckVisitor<'a, 'tcx> { @@ -173,8 +187,16 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EffectCheckVisitor<'a, 'tcx> { self.require_unsafe(expr.span, "use of inline assembly"); } hir::ExprPath(..) => { - if let Def::Static(_, true) = self.tcx.expect_def(expr.id) { - self.require_unsafe(expr.span, "use of mutable static"); + if let Def::Static(def_id, mutbl) = self.tcx.expect_def(expr.id) { + if mutbl { + self.require_unsafe(expr.span, "use of mutable static"); + } else if match self.tcx.map.get_if_local(def_id) { + Some(hir::map::NodeForeignItem(..)) => true, + Some(..) => false, + None => self.tcx.sess.cstore.is_foreign_item(def_id), + } { + self.require_unsafe_ext(expr.id, expr.span, "use of extern static", true); + } } } hir::ExprField(ref base_expr, field) => { diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs index b9817cc6ff45..bc2979c806f6 100644 --- a/src/librustc_lint/lib.rs +++ b/src/librustc_lint/lib.rs @@ -201,6 +201,10 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) { id: LintId::of(LIFETIME_UNDERSCORE), reference: "RFC 1177 ", }, + FutureIncompatibleInfo { + id: LintId::of(SAFE_EXTERN_STATICS), + reference: "issue 36247 ", + }, ]); // Register renamed and removed lints diff --git a/src/test/compile-fail/auxiliary/extern-statics.rs b/src/test/compile-fail/auxiliary/extern-statics.rs new file mode 100644 index 000000000000..07f70b177b3b --- /dev/null +++ b/src/test/compile-fail/auxiliary/extern-statics.rs @@ -0,0 +1,14 @@ +// 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. + +extern { + pub static XA: u8; + pub static mut XB: u8; +} diff --git a/src/test/compile-fail/linkage2.rs b/src/test/compile-fail/linkage2.rs index 2a127d937eaa..afae4a451d69 100644 --- a/src/test/compile-fail/linkage2.rs +++ b/src/test/compile-fail/linkage2.rs @@ -16,5 +16,5 @@ extern { } fn main() { - println!("{}", foo); + println!("{}", unsafe { foo }); } diff --git a/src/test/compile-fail/linkage3.rs b/src/test/compile-fail/linkage3.rs index 8343f718902d..c222989ed667 100644 --- a/src/test/compile-fail/linkage3.rs +++ b/src/test/compile-fail/linkage3.rs @@ -16,5 +16,5 @@ extern { } fn main() { - println!("{:?}", foo); + println!("{:?}", unsafe { foo }); } diff --git a/src/test/compile-fail/safe-extern-statics-mut.rs b/src/test/compile-fail/safe-extern-statics-mut.rs new file mode 100644 index 000000000000..b5f3b4535df9 --- /dev/null +++ b/src/test/compile-fail/safe-extern-statics-mut.rs @@ -0,0 +1,28 @@ +// 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. + +// aux-build:extern-statics.rs + +#![allow(unused)] +#![deny(safe_extern_statics)] + +extern crate extern_statics; +use extern_statics::*; + +extern { + static mut B: u8; +} + +fn main() { + let b = B; //~ ERROR use of mutable static requires unsafe function or block + let rb = &B; //~ ERROR use of mutable static requires unsafe function or block + let xb = XB; //~ ERROR use of mutable static requires unsafe function or block + let xrb = &XB; //~ ERROR use of mutable static requires unsafe function or block +} diff --git a/src/test/compile-fail/safe-extern-statics.rs b/src/test/compile-fail/safe-extern-statics.rs new file mode 100644 index 000000000000..7e96897ee882 --- /dev/null +++ b/src/test/compile-fail/safe-extern-statics.rs @@ -0,0 +1,32 @@ +// 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. + +// aux-build:extern-statics.rs + +#![allow(unused)] +#![deny(safe_extern_statics)] + +extern crate extern_statics; +use extern_statics::*; + +extern { + static A: u8; +} + +fn main() { + let a = A; //~ ERROR use of extern static requires unsafe function or block + //~^ WARN this was previously accepted by the compiler + let ra = &A; //~ ERROR use of extern static requires unsafe function or block + //~^ WARN this was previously accepted by the compiler + let xa = XA; //~ ERROR use of extern static requires unsafe function or block + //~^ WARN this was previously accepted by the compiler + let xra = &XA; //~ ERROR use of extern static requires unsafe function or block + //~^ WARN this was previously accepted by the compiler +} diff --git a/src/test/run-pass/check-static-recursion-foreign.rs b/src/test/run-pass/check-static-recursion-foreign.rs index 554853ade5be..8e718f328ff9 100644 --- a/src/test/run-pass/check-static-recursion-foreign.rs +++ b/src/test/run-pass/check-static-recursion-foreign.rs @@ -27,6 +27,6 @@ extern "C" { static test_static: c_int; } -static B: &'static c_int = &test_static; +static B: &'static c_int = unsafe { &test_static }; pub fn main() {} From 765700ba7a3743b9af5cb12092ea1293dbe07068 Mon Sep 17 00:00:00 2001 From: Ulrik Sverdrup Date: Thu, 8 Sep 2016 23:48:08 +0200 Subject: [PATCH 270/443] Work around pointer aliasing issue in Vec::extend_from_slice, extend_with_element Due to missing noalias annotations for &mut T in general (issue #31681), in larger programs extend_from_slice and extend_with_element may both compile very poorly. What is observed is that the .set_len() calls are not lifted out of the loop, even for `Vec`. Use a local length variable for the Vec length instead, and use a scope guard to write this value back to self.len when the scope ends or on panic. Then the alias analysis is easy. This affects extend_from_slice, extend_with_element, the vec![x; n] macro, Write impls for Vec, BufWriter, etc (but may / may not have triggered since inlining can be enough for the compiler to get it right). --- src/libcollections/vec.rs | 66 ++++++++++++++++++++++++++++++++------- 1 file changed, 54 insertions(+), 12 deletions(-) diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index 876314613f52..7388e8834343 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -1046,21 +1046,27 @@ impl Vec { self.reserve(n); unsafe { - let len = self.len(); - let mut ptr = self.as_mut_ptr().offset(len as isize); + let mut ptr = self.as_mut_ptr().offset(self.len() as isize); + // Use SetLenOnDrop to work around bug where compiler + // may not realize the store through `ptr` trough self.set_len() + // don't alias. + let mut local_len = SetLenOnDrop::new(&mut self.len); + // Write all elements except the last one - for i in 1..n { + for _ in 1..n { ptr::write(ptr, value.clone()); ptr = ptr.offset(1); // Increment the length in every step in case clone() panics - self.set_len(len + i); + local_len.increment_len(1); } if n > 0 { // We can write the last element directly without cloning needlessly ptr::write(ptr, value); - self.set_len(len + n); + local_len.increment_len(1); } + + // len set by scope guard } } @@ -1085,20 +1091,56 @@ impl Vec { pub fn extend_from_slice(&mut self, other: &[T]) { self.reserve(other.len()); - for i in 0..other.len() { + // Unsafe code so this can be optimised to a memcpy (or something + // similarly fast) when T is Copy. LLVM is easily confused, so any + // extra operations during the loop can prevent this optimisation. + unsafe { let len = self.len(); + let ptr = self.get_unchecked_mut(len) as *mut T; + // Use SetLenOnDrop to work around bug where compiler + // may not realize the store through `ptr` trough self.set_len() + // don't alias. + let mut local_len = SetLenOnDrop::new(&mut self.len); - // Unsafe code so this can be optimised to a memcpy (or something - // similarly fast) when T is Copy. LLVM is easily confused, so any - // extra operations during the loop can prevent this optimisation. - unsafe { - ptr::write(self.get_unchecked_mut(len), other.get_unchecked(i).clone()); - self.set_len(len + 1); + for i in 0..other.len() { + ptr::write(ptr.offset(i as isize), other.get_unchecked(i).clone()); + local_len.increment_len(1); } + + // len set by scope guard } } } +// Set the length of the vec when the `SetLenOnDrop` value goes out of scope. +// +// The idea is: The length field in SetLenOnDrop is a local variable +// that the optimizer will see does not alias with any stores through the Vec's data +// pointer. This is a workaround for alias analysis issue #32155 +struct SetLenOnDrop<'a> { + len: &'a mut usize, + local_len: usize, +} + +impl<'a> SetLenOnDrop<'a> { + #[inline] + fn new(len: &'a mut usize) -> Self { + SetLenOnDrop { local_len: *len, len: len } + } + + #[inline] + fn increment_len(&mut self, increment: usize) { + self.local_len += increment; + } +} + +impl<'a> Drop for SetLenOnDrop<'a> { + #[inline] + fn drop(&mut self) { + *self.len = self.local_len; + } +} + impl Vec { /// Removes consecutive repeated elements in the vector. /// From 8154a6bc69b42813ffda91adcefd9f277338acf3 Mon Sep 17 00:00:00 2001 From: Oliver Middleton Date: Sun, 14 Aug 2016 18:01:25 +0100 Subject: [PATCH 271/443] rustdoc: Don't add extra newlines for fully opaque structs Changes the definition for opaque structs to look like `pub struct Vec { /* fields omitted */ }` to save space on the page. Also only use one line for empty braced structs. --- src/librustdoc/html/render.rs | 21 +++++++++++++++------ src/test/rustdoc/structfields.rs | 10 ++++++++++ 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 2be6177ea344..d01a5e312a3a 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -2509,19 +2509,28 @@ fn render_struct(w: &mut fmt::Formatter, it: &clean::Item, if let Some(g) = g { write!(w, "{}", WhereClause(g))? } - write!(w, " {{\n{}", tab)?; + let mut has_visible_fields = false; + write!(w, " {{")?; for field in fields { if let clean::StructFieldItem(ref ty) = field.inner { - write!(w, " {}{}: {},\n{}", + write!(w, "\n{} {}{}: {},", + tab, VisSpace(&field.visibility), field.name.as_ref().unwrap(), - *ty, - tab)?; + *ty)?; + has_visible_fields = true; } } - if it.has_stripped_fields().unwrap() { - write!(w, " // some fields omitted\n{}", tab)?; + if has_visible_fields { + if it.has_stripped_fields().unwrap() { + write!(w, "\n{} // some fields omitted", tab)?; + } + write!(w, "\n{}", tab)?; + } else if it.has_stripped_fields().unwrap() { + // If there are no visible fields we can just display + // `{ /* fields omitted */ }` to save space. + write!(w, " /* fields omitted */ ")?; } write!(w, "}}")?; } diff --git a/src/test/rustdoc/structfields.rs b/src/test/rustdoc/structfields.rs index c0bfe3ffe3cf..75d9be856d74 100644 --- a/src/test/rustdoc/structfields.rs +++ b/src/test/rustdoc/structfields.rs @@ -48,3 +48,13 @@ pub enum Qux { // @has - //pre "// some fields omitted" }, } + +// @has structfields/struct.Baz.html //pre "pub struct Baz { /* fields omitted */ }" +pub struct Baz { + x: u8, + #[doc(hidden)] + pub y: u8, +} + +// @has structfields/struct.Quux.html //pre "pub struct Quux {}" +pub struct Quux {} From 89bc13c37d0fc58b583f07a5902f62e598c69b0e Mon Sep 17 00:00:00 2001 From: Jake Goldsborough Date: Thu, 8 Sep 2016 17:51:06 -0700 Subject: [PATCH 272/443] tweaking the nodejs cmd sanity check --- src/bootstrap/sanity.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bootstrap/sanity.rs b/src/bootstrap/sanity.rs index c345893954f4..e5e66f1035d1 100644 --- a/src/bootstrap/sanity.rs +++ b/src/bootstrap/sanity.rs @@ -77,8 +77,8 @@ pub fn check(build: &mut Build) { // If a manual nodejs was added to the config, // of if a nodejs install is detected through config, use it. - if build.config.nodejs.is_some() { - need_cmd("nodejs".as_ref()) + if let Some(ref s) = build.config.nodejs { + need_cmd(s.as_ref()); } // We're gonna build some custom C code here and there, host triples From 93cdce4cf36bbc3419d586b8cbab17885b449d5f Mon Sep 17 00:00:00 2001 From: Liigo Date: Tue, 6 Sep 2016 15:59:16 +0800 Subject: [PATCH 273/443] rustdoc: don't collapse `docblock-short` --- src/librustdoc/html/render.rs | 2 +- src/librustdoc/html/static/rustdoc.css | 8 ++++---- src/test/rustdoc/issue-32374.rs | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 2be6177ea344..fb7a11fc8cff 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -1834,7 +1834,7 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context, {name} - + {stab_docs} {docs} ", diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index c97cacd10c38..a27f92177f49 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -239,23 +239,23 @@ nav.sub { } .line-numbers span { cursor: pointer; } -.docblock.short p { +.docblock-short p { display: inline; } -.docblock.short.nowrap { +.docblock-short.nowrap { display: block; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; } -.docblock.short p { +.docblock-short p { overflow: hidden; text-overflow: ellipsis; margin: 0; } -.docblock.short code { white-space: nowrap; } +.docblock-short code { white-space: nowrap; } .docblock h1, .docblock h2, .docblock h3, .docblock h4, .docblock h5 { border-bottom: 1px solid; diff --git a/src/test/rustdoc/issue-32374.rs b/src/test/rustdoc/issue-32374.rs index cdb4094ffe05..262a1ffce747 100644 --- a/src/test/rustdoc/issue-32374.rs +++ b/src/test/rustdoc/issue-32374.rs @@ -13,7 +13,7 @@ #![unstable(feature="test", issue = "32374")] -// @has issue_32374/index.html '//*[@class="docblock short"]' \ +// @has issue_32374/index.html '//*[@class="docblock-short"]' \ // '[Deprecated] [Unstable]' // @has issue_32374/struct.T.html '//*[@class="stab deprecated"]' \ From 26d5f99ec061e439a00a85110135953a3d5c35ae Mon Sep 17 00:00:00 2001 From: Liigo Date: Fri, 9 Sep 2016 11:54:12 +0800 Subject: [PATCH 274/443] rustdoc: more docblock-short styles --- src/librustdoc/html/static/rustdoc.css | 6 +++--- src/librustdoc/html/static/styles/main.css | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index a27f92177f49..9f86f5d9d20f 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -130,11 +130,11 @@ code, pre { font-family: "Source Code Pro", Menlo, Monaco, Consolas, "DejaVu Sans Mono", Inconsolata, monospace; white-space: pre-wrap; } -.docblock code { +.docblock code, .docblock-short code { border-radius: 3px; padding: 0 0.2em; } -.docblock pre code { +.docblock pre code, .docblock-short pre code { padding: 0; } pre { @@ -409,7 +409,7 @@ a { background: transparent; } -.docblock a:hover, .stability a { +.docblock a:hover, .docblock-short a:hover, .stability a { text-decoration: underline; } diff --git a/src/librustdoc/html/static/styles/main.css b/src/librustdoc/html/static/styles/main.css index c64fb1b67f3d..fceea85cc704 100644 --- a/src/librustdoc/html/static/styles/main.css +++ b/src/librustdoc/html/static/styles/main.css @@ -34,7 +34,7 @@ div.stability > em > code { background-color: initial; } -.docblock code { +.docblock code, .docblock-short code { background-color: #F5F5F5; } pre { @@ -113,7 +113,7 @@ a { color: #000; } -.docblock a, .stability a { +.docblock a, .docblock-short a, .stability a { color: #3873AD; } From 5e9149d73f7d2912079f08e48eb257e8a6d4f0b3 Mon Sep 17 00:00:00 2001 From: orbea Date: Thu, 8 Sep 2016 23:18:20 -0700 Subject: [PATCH 275/443] Allow setting --docdir --- configure | 3 +++ mk/install.mk | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/configure b/configure index 71fb164f8912..6b822f6bc485 100755 --- a/configure +++ b/configure @@ -671,6 +671,7 @@ valopt_nosave local-rust-root "/usr/local" "set prefix for local rust binary" valopt_nosave host "${CFG_BUILD}" "GNUs ./configure syntax LLVM host triples" valopt_nosave target "${CFG_HOST}" "GNUs ./configure syntax LLVM target triples" valopt_nosave mandir "${CFG_PREFIX}/share/man" "install man pages in PATH" +valopt_nosave docdir "${CFG_PREFIX}/share/doc/rust" "install man pages in PATH" # On Windows this determines root of the subtree for target libraries. # Host runtime libs always go to 'bin'. @@ -1116,6 +1117,7 @@ putvar CFG_STDCPP_NAME # a little post-processing of various config values CFG_PREFIX=${CFG_PREFIX%/} CFG_MANDIR=${CFG_MANDIR%/} +CFG_DOCDIR=${CFG_DOCDIR%/} CFG_HOST="$(echo $CFG_HOST | tr ',' ' ')" CFG_TARGET="$(echo $CFG_TARGET | tr ',' ' ')" CFG_SUPPORTED_TARGET="" @@ -1797,6 +1799,7 @@ putvar CFG_ARMV7_LINUX_ANDROIDEABI_NDK putvar CFG_I686_LINUX_ANDROID_NDK putvar CFG_NACL_CROSS_PATH putvar CFG_MANDIR +putvar CFG_DOCDIR putvar CFG_USING_LIBCPP # Avoid spurious warnings from clang by feeding it original source on diff --git a/mk/install.mk b/mk/install.mk index d2e5449a2f51..be212869f010 100644 --- a/mk/install.mk +++ b/mk/install.mk @@ -12,7 +12,8 @@ RUN_INSTALLER = cd tmp/empty_dir && \ sh ../../tmp/dist/$(1)/install.sh \ --prefix="$(DESTDIR)$(CFG_PREFIX)" \ --libdir="$(DESTDIR)$(CFG_LIBDIR)" \ - --mandir="$(DESTDIR)$(CFG_MANDIR)" + --mandir="$(DESTDIR)$(CFG_MANDIR)" \ + --docdir="$(DESTDIR)$(CFG_DOCDIR)" install: ifeq (root user, $(USER) $(patsubst %,user,$(SUDO_USER))) From 0e32d1186830c8ad201dd79f1312a71e324eb98e Mon Sep 17 00:00:00 2001 From: Jared Wyles Date: Sat, 6 Aug 2016 08:26:09 +1000 Subject: [PATCH 276/443] Update the wording for E0063. This will truncate the fields to 3. Instead of listing every field it will now show missing `a`, `z`, `b`, and 1 other field --- src/librustc_typeck/check/mod.rs | 38 ++++++++++++++++++++------ src/test/compile-fail/E0063.rs | 46 ++++++++++++++++++++++++++++---- 2 files changed, 71 insertions(+), 13 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index b059c2ab9f3a..8d121eeb5897 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3158,14 +3158,36 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { tcx.sess.span_err(span, "union expressions should have exactly one field"); } } else if check_completeness && !error_happened && !remaining_fields.is_empty() { - span_err!(tcx.sess, span, E0063, - "missing field{} {} in initializer of `{}`", - if remaining_fields.len() == 1 {""} else {"s"}, - remaining_fields.keys() - .map(|n| format!("`{}`", n)) - .collect::>() - .join(", "), - adt_ty); + let len = remaining_fields.len(); + + let mut displayable_field_names = remaining_fields + .keys() + .map(|x| x.as_str()) + .collect::>(); + + displayable_field_names.sort(); + + let truncated_fields_error = if len <= 3 { + "".to_string() + } else { + format!(" and {} other field{}", (len - 3), if len - 3 == 1 {""} else {"s"}) + }; + + let remaining_fields_names = displayable_field_names.iter().take(3) + .map(|n| format!("`{}`", n)) + .collect::>() + .join(", "); + + struct_span_err!(tcx.sess, span, E0063, + "missing field{} {}{} in initializer of `{}`", + if remaining_fields.len() == 1 {""} else {"s"}, + remaining_fields_names, + truncated_fields_error, + adt_ty) + .span_label(span, &format!("missing {}{}", + remaining_fields_names, + truncated_fields_error)) + .emit(); } } diff --git a/src/test/compile-fail/E0063.rs b/src/test/compile-fail/E0063.rs index c94f807d807c..e7044102abc7 100644 --- a/src/test/compile-fail/E0063.rs +++ b/src/test/compile-fail/E0063.rs @@ -8,11 +8,47 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -struct Foo { - x: i32, - y: i32 +// ignore-tidy-linelength + +struct SingleFoo { + x: i32 } -fn main() { - let x = Foo { x: 0 }; //~ ERROR E0063 +struct PluralFoo { + x: i32, + y: i32, + z: i32 +} + +struct TruncatedFoo { + a: i32, + b: i32, + x: i32, + y: i32, + z: i32 +} + +struct TruncatedPluralFoo { + a: i32, + b: i32, + c: i32, + x: i32, + y: i32, + z: i32 +} + + +fn main() { + let w = SingleFoo { }; + //~^ ERROR missing field `x` in initializer of `SingleFoo` + //~| NOTE missing `x` + let x = PluralFoo {x: 1}; + //~^ ERROR missing fields `y`, `z` in initializer of `PluralFoo` + //~| NOTE missing `y`, `z` + let y = TruncatedFoo{x:1}; + //~^ missing fields `a`, `b`, `y` and 1 other field in initializer of `TruncatedFoo` + //~| NOTE `a`, `b`, `y` and 1 other field + let z = TruncatedPluralFoo{x:1}; + //~^ ERROR missing fields `a`, `b`, `c` and 2 other fields in initializer of `TruncatedPluralFoo` + //~| NOTE missing `a`, `b`, `c` and 2 other fields } From 19b84088d76b8ded63cbaf12991213f4f437e689 Mon Sep 17 00:00:00 2001 From: Ulrich Weigand Date: Fri, 9 Sep 2016 23:00:23 +0200 Subject: [PATCH 277/443] Add s390x support This adds support for building the Rust compiler and standard library for s390x-linux, allowing a full cross-bootstrap sequence to complete. This includes: - Makefile/configure changes to allow native s390x builds - Full Rust compiler support for the s390x C ABI (only the non-vector ABI is supported at this point) - Port of the standard library to s390x - Update the liblibc submodule to a version including s390x support - Testsuite fixes to allow clean "make check" on s390x Caveats: - Resets base cpu to "z10" to bring support in sync with the default behaviour of other compilers on the platforms. (Usually, upstream supports all older processors; a distribution build may then chose to require a more recent base version.) (Also, using zEC12 causes failures in the valgrind tests since valgrind doesn't fully support this CPU yet.) - z13 vector ABI is not yet supported. To ensure compatible code generation, the -vector feature is passed to LLVM. Note that this means that even when compiling for z13, no vector instructions will be used. In the future, support for the vector ABI should be added (this will require common code support for different ABIs that need different data_layout strings on the same platform). - Two test cases are (temporarily) ignored on s390x to allow passing the test suite. The underlying issues still need to be fixed: * debuginfo/simd.rs fails because of incorrect debug information. This seems to be a LLVM bug (also seen with C code). * run-pass/union/union-basic.rs simply seems to be incorrect for all big-endian platforms. Signed-off-by: Ulrich Weigand --- configure | 4 + mk/cfg/s390x-unknown-linux-gnu.mk | 25 ++- src/liballoc_jemalloc/lib.rs | 3 +- src/liballoc_system/lib.rs | 3 +- src/liblibc | 2 +- src/libpanic_unwind/gcc.rs | 3 + .../target/s390x_unknown_linux_gnu.rs | 8 +- src/librustc_trans/abi.rs | 9 +- src/librustc_trans/cabi_s390x.rs | 150 ++++++++++++++++++ src/librustc_trans/lib.rs | 1 + src/libstd/env.rs | 6 + src/libstd/os/linux/raw.rs | 5 + src/libstd/os/raw.rs | 6 +- src/libstd/sys/unix/rand.rs | 14 +- src/libunwind/libunwind.rs | 3 + src/test/compile-fail/asm-bad-clobber.rs | 1 + src/test/compile-fail/asm-in-bad-modifier.rs | 2 + src/test/compile-fail/asm-misplaced-option.rs | 1 + src/test/compile-fail/asm-out-assign-imm.rs | 2 + src/test/compile-fail/asm-out-no-modifier.rs | 2 + src/test/compile-fail/asm-out-read-uninit.rs | 2 + src/test/debuginfo/simd.rs | 5 + src/test/run-make/atomic-lock-free/Makefile | 2 + src/test/run-pass/conditional-compile-arch.rs | 3 + src/test/run-pass/union/union-basic.rs | 3 + src/tools/compiletest/src/util.rs | 2 +- 26 files changed, 253 insertions(+), 14 deletions(-) create mode 100644 src/librustc_trans/cabi_s390x.rs diff --git a/configure b/configure index 71fb164f8912..792a1ed9c3cb 100755 --- a/configure +++ b/configure @@ -524,6 +524,10 @@ case $CFG_CPUTYPE in CFG_CPUTYPE=powerpc64le ;; + s390x) + CFG_CPUTYPE=s390x + ;; + x86_64 | x86-64 | x64 | amd64) CFG_CPUTYPE=x86_64 ;; diff --git a/mk/cfg/s390x-unknown-linux-gnu.mk b/mk/cfg/s390x-unknown-linux-gnu.mk index 34aee77ae210..eb1cb2329c4f 100644 --- a/mk/cfg/s390x-unknown-linux-gnu.mk +++ b/mk/cfg/s390x-unknown-linux-gnu.mk @@ -1 +1,24 @@ -# rustbuild-only target +# s390x-unknown-linux-gnu configuration +CROSS_PREFIX_s390x-unknown-linux-gnu=s390x-linux-gnu- +CC_s390x-unknown-linux-gnu=$(CC) +CXX_s390x-unknown-linux-gnu=$(CXX) +CPP_s390x-unknown-linux-gnu=$(CPP) +AR_s390x-unknown-linux-gnu=$(AR) +CFG_LIB_NAME_s390x-unknown-linux-gnu=lib$(1).so +CFG_STATIC_LIB_NAME_s390x-unknown-linux-gnu=lib$(1).a +CFG_LIB_GLOB_s390x-unknown-linux-gnu=lib$(1)-*.so +CFG_LIB_DSYM_GLOB_s390x-unknown-linux-gnu=lib$(1)-*.dylib.dSYM +CFG_CFLAGS_s390x-unknown-linux-gnu := -m64 $(CFLAGS) +CFG_GCCISH_CFLAGS_s390x-unknown-linux-gnu := -g -fPIC -m64 $(CFLAGS) +CFG_GCCISH_CXXFLAGS_s390x-unknown-linux-gnu := -fno-rtti $(CXXFLAGS) +CFG_GCCISH_LINK_FLAGS_s390x-unknown-linux-gnu := -shared -fPIC -ldl -pthread -lrt -g -m64 +CFG_GCCISH_DEF_FLAG_s390x-unknown-linux-gnu := -Wl,--export-dynamic,--dynamic-list= +CFG_LLC_FLAGS_s390x-unknown-linux-gnu := +CFG_INSTALL_NAME_s390x-unknown-linux-gnu = +CFG_EXE_SUFFIX_s390x-unknown-linux-gnu = +CFG_WINDOWSY_s390x-unknown-linux-gnu := +CFG_UNIXY_s390x-unknown-linux-gnu := 1 +CFG_LDPATH_s390x-unknown-linux-gnu := +CFG_RUN_s390x-unknown-linux-gnu=$(2) +CFG_RUN_TARG_s390x-unknown-linux-gnu=$(call CFG_RUN_s390x-unknown-linux-gnu,,$(2)) +CFG_GNU_TRIPLE_s390x-unknown-linux-gnu := s390x-unknown-linux-gnu diff --git a/src/liballoc_jemalloc/lib.rs b/src/liballoc_jemalloc/lib.rs index aae0528e42cc..5bbf1c35e0dd 100644 --- a/src/liballoc_jemalloc/lib.rs +++ b/src/liballoc_jemalloc/lib.rs @@ -78,7 +78,8 @@ const MIN_ALIGN: usize = 8; target_arch = "x86_64", target_arch = "aarch64", target_arch = "powerpc64", - target_arch = "mips64")))] + target_arch = "mips64", + target_arch = "s390x")))] const MIN_ALIGN: usize = 16; // MALLOCX_ALIGN(a) macro diff --git a/src/liballoc_system/lib.rs b/src/liballoc_system/lib.rs index 2c0c6d068caa..01407d1acd2e 100644 --- a/src/liballoc_system/lib.rs +++ b/src/liballoc_system/lib.rs @@ -33,7 +33,8 @@ const MIN_ALIGN: usize = 8; #[cfg(all(any(target_arch = "x86_64", target_arch = "aarch64", - target_arch = "mips64")))] + target_arch = "mips64", + target_arch = "s390x")))] const MIN_ALIGN: usize = 16; #[no_mangle] diff --git a/src/liblibc b/src/liblibc index 49d64cae0699..d4f6a19c55a0 160000 --- a/src/liblibc +++ b/src/liblibc @@ -1 +1 @@ -Subproject commit 49d64cae0699ed9d9ed84810d737a26b0b519da8 +Subproject commit d4f6a19c55a03e3f9f6fb7377911b37ed807eb6c diff --git a/src/libpanic_unwind/gcc.rs b/src/libpanic_unwind/gcc.rs index c2e8eccbd22a..33b24fbaa265 100644 --- a/src/libpanic_unwind/gcc.rs +++ b/src/libpanic_unwind/gcc.rs @@ -130,6 +130,9 @@ const UNWIND_DATA_REG: (i32, i32) = (4, 5); // A0, A1 #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] const UNWIND_DATA_REG: (i32, i32) = (3, 4); // R3, R4 / X3, X4 +#[cfg(target_arch = "s390x")] +const UNWIND_DATA_REG: (i32, i32) = (6, 7); // R6, R7 + // The following code is based on GCC's C and C++ personality routines. For reference, see: // https://github.com/gcc-mirror/gcc/blob/master/libstdc++-v3/libsupc++/eh_personality.cc // https://github.com/gcc-mirror/gcc/blob/trunk/libgcc/unwind-c.c diff --git a/src/librustc_back/target/s390x_unknown_linux_gnu.rs b/src/librustc_back/target/s390x_unknown_linux_gnu.rs index 895d33d8d755..79f2d290e376 100644 --- a/src/librustc_back/target/s390x_unknown_linux_gnu.rs +++ b/src/librustc_back/target/s390x_unknown_linux_gnu.rs @@ -12,8 +12,12 @@ use target::{Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::linux_base::opts(); - // NOTE(zEC12) matches C toolchain - base.cpu = "zEC12".to_string(); + // z10 is the oldest CPU supported by LLVM + base.cpu = "z10".to_string(); + // FIXME: The data_layout string below and the ABI implementation in + // cabi_s390x.rs are for now hard-coded to assume the no-vector ABI. + // Pass the -vector feature string to LLVM to respect this assumption. + base.features = "-vector".to_string(); base.max_atomic_width = 64; Ok(Target { diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs index 42289ec094f3..1a6c34b55af6 100644 --- a/src/librustc_trans/abi.rs +++ b/src/librustc_trans/abi.rs @@ -20,6 +20,7 @@ use cabi_arm; use cabi_aarch64; use cabi_powerpc; use cabi_powerpc64; +use cabi_s390x; use cabi_mips; use cabi_mips64; use cabi_asmjs; @@ -301,6 +302,9 @@ impl FnType { let win_x64_gnu = target.target_os == "windows" && target.arch == "x86_64" && target.target_env == "gnu"; + let linux_s390x = target.target_os == "linux" + && target.arch == "s390x" + && target.target_env == "gnu"; let rust_abi = match abi { RustIntrinsic | PlatformIntrinsic | Rust | RustCall => true, _ => false @@ -326,7 +330,9 @@ impl FnType { if llsize_of_real(ccx, arg.ty) == 0 { // For some forsaken reason, x86_64-pc-windows-gnu // doesn't ignore zero-sized struct arguments. - if is_return || rust_abi || !win_x64_gnu { + // The same is true for s390x-unknown-linux-gnu. + if is_return || rust_abi || + (!win_x64_gnu && !linux_s390x) { arg.ignore(); } } @@ -511,6 +517,7 @@ impl FnType { "mips64" => cabi_mips64::compute_abi_info(ccx, self), "powerpc" => cabi_powerpc::compute_abi_info(ccx, self), "powerpc64" => cabi_powerpc64::compute_abi_info(ccx, self), + "s390x" => cabi_s390x::compute_abi_info(ccx, self), "asmjs" => cabi_asmjs::compute_abi_info(ccx, self), a => ccx.sess().fatal(&format!("unrecognized arch \"{}\" in target specification", a)) } diff --git a/src/librustc_trans/cabi_s390x.rs b/src/librustc_trans/cabi_s390x.rs new file mode 100644 index 000000000000..19404b667e1f --- /dev/null +++ b/src/librustc_trans/cabi_s390x.rs @@ -0,0 +1,150 @@ +// 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. + +// FIXME: The assumes we're using the non-vector ABI, i.e. compiling +// for a pre-z13 machine or using -mno-vx. + +use llvm::{Integer, Pointer, Float, Double, Struct, Array, Vector}; +use abi::{FnType, ArgType}; +use context::CrateContext; +use type_::Type; + +use std::cmp; + +fn align_up_to(off: usize, a: usize) -> usize { + return (off + a - 1) / a * a; +} + +fn align(off: usize, ty: Type) -> usize { + let a = ty_align(ty); + return align_up_to(off, a); +} + +fn ty_align(ty: Type) -> usize { + match ty.kind() { + Integer => ((ty.int_width() as usize) + 7) / 8, + Pointer => 8, + Float => 4, + Double => 8, + Struct => { + if ty.is_packed() { + 1 + } else { + let str_tys = ty.field_types(); + str_tys.iter().fold(1, |a, t| cmp::max(a, ty_align(*t))) + } + } + Array => { + let elt = ty.element_type(); + ty_align(elt) + } + Vector => ty_size(ty), + _ => bug!("ty_align: unhandled type") + } +} + +fn ty_size(ty: Type) -> usize { + match ty.kind() { + Integer => ((ty.int_width() as usize) + 7) / 8, + Pointer => 8, + Float => 4, + Double => 8, + Struct => { + if ty.is_packed() { + let str_tys = ty.field_types(); + str_tys.iter().fold(0, |s, t| s + ty_size(*t)) + } else { + let str_tys = ty.field_types(); + let size = str_tys.iter().fold(0, |s, t| align(s, *t) + ty_size(*t)); + align(size, ty) + } + } + Array => { + let len = ty.array_length(); + let elt = ty.element_type(); + let eltsz = ty_size(elt); + len * eltsz + } + Vector => { + let len = ty.vector_length(); + let elt = ty.element_type(); + let eltsz = ty_size(elt); + len * eltsz + } + _ => bug!("ty_size: unhandled type") + } +} + +fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) { + if is_reg_ty(ret.ty) { + ret.extend_integer_width_to(64); + } else { + ret.make_indirect(ccx); + } +} + +fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType) { + if arg.ty.kind() == Struct { + fn is_single_fp_element(tys: &[Type]) -> bool { + if tys.len() != 1 { + return false; + } + match tys[0].kind() { + Float | Double => true, + Struct => is_single_fp_element(&tys[0].field_types()), + _ => false + } + } + + if is_single_fp_element(&arg.ty.field_types()) { + match ty_size(arg.ty) { + 4 => arg.cast = Some(Type::f32(ccx)), + 8 => arg.cast = Some(Type::f64(ccx)), + _ => arg.make_indirect(ccx) + } + } else { + match ty_size(arg.ty) { + 1 => arg.cast = Some(Type::i8(ccx)), + 2 => arg.cast = Some(Type::i16(ccx)), + 4 => arg.cast = Some(Type::i32(ccx)), + 8 => arg.cast = Some(Type::i64(ccx)), + _ => arg.make_indirect(ccx) + } + } + return; + } + + if is_reg_ty(arg.ty) { + arg.extend_integer_width_to(64); + } else { + arg.make_indirect(ccx); + } +} + +fn is_reg_ty(ty: Type) -> bool { + match ty.kind() { + Integer + | Pointer + | Float + | Double => ty_size(ty) <= 8, + _ => false + } +} + +pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) { + if !fty.ret.is_ignore() { + classify_ret_ty(ccx, &mut fty.ret); + } + + for arg in &mut fty.args { + if arg.is_ignore() { continue; } + classify_arg_ty(ccx, arg); + } +} diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index 6f5bac840a1d..3e60369acbff 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -102,6 +102,7 @@ mod cabi_mips; mod cabi_mips64; mod cabi_powerpc; mod cabi_powerpc64; +mod cabi_s390x; mod cabi_x86; mod cabi_x86_64; mod cabi_x86_win64; diff --git a/src/libstd/env.rs b/src/libstd/env.rs index 9fcc3a80b98b..63bf051c9bcd 100644 --- a/src/libstd/env.rs +++ b/src/libstd/env.rs @@ -662,6 +662,7 @@ pub mod consts { /// - mips64 /// - powerpc /// - powerpc64 + /// - s390x #[stable(feature = "env", since = "1.0.0")] pub const ARCH: &'static str = super::arch::ARCH; @@ -942,6 +943,11 @@ mod arch { pub const ARCH: &'static str = "powerpc64"; } +#[cfg(target_arch = "s390x")] +mod arch { + pub const ARCH: &'static str = "s390x"; +} + #[cfg(target_arch = "le32")] mod arch { pub const ARCH: &'static str = "le32"; diff --git a/src/libstd/os/linux/raw.rs b/src/libstd/os/linux/raw.rs index 0f62877500b2..1c19e58818d7 100644 --- a/src/libstd/os/linux/raw.rs +++ b/src/libstd/os/linux/raw.rs @@ -160,6 +160,11 @@ mod arch { pub use libc::{off_t, ino_t, nlink_t, blksize_t, blkcnt_t, stat, time_t}; } +#[cfg(target_arch = "s390x")] +mod arch { + pub use libc::{off_t, ino_t, nlink_t, blksize_t, blkcnt_t, stat, time_t}; +} + #[cfg(target_arch = "aarch64")] mod arch { use os::raw::{c_long, c_int}; diff --git a/src/libstd/os/raw.rs b/src/libstd/os/raw.rs index 55d8ad17460d..6c5c1b90a4a9 100644 --- a/src/libstd/os/raw.rs +++ b/src/libstd/os/raw.rs @@ -17,14 +17,16 @@ all(target_os = "linux", any(target_arch = "aarch64", target_arch = "arm", target_arch = "powerpc", - target_arch = "powerpc64"))))] + target_arch = "powerpc64", + target_arch = "s390x"))))] #[stable(feature = "raw_os", since = "1.1.0")] pub type c_char = u8; #[cfg(not(any(target_os = "android", target_os = "emscripten", all(target_os = "linux", any(target_arch = "aarch64", target_arch = "arm", target_arch = "powerpc", - target_arch = "powerpc64")))))] + target_arch = "powerpc64", + target_arch = "s390x")))))] #[stable(feature = "raw_os", since = "1.1.0")] pub type c_char = i8; #[stable(feature = "raw_os", since = "1.1.0")] pub type c_schar = i8; #[stable(feature = "raw_os", since = "1.1.0")] pub type c_uchar = u8; diff --git a/src/libstd/sys/unix/rand.rs b/src/libstd/sys/unix/rand.rs index e4ca8344ee28..6b50ca9bcdf6 100644 --- a/src/libstd/sys/unix/rand.rs +++ b/src/libstd/sys/unix/rand.rs @@ -45,7 +45,8 @@ mod imp { target_arch = "arm", target_arch = "aarch64", target_arch = "powerpc", - target_arch = "powerpc64")))] + target_arch = "powerpc64", + target_arch = "s390x")))] fn getrandom(buf: &mut [u8]) -> libc::c_long { #[cfg(target_arch = "x86_64")] const NR_GETRANDOM: libc::c_long = 318; @@ -53,6 +54,8 @@ mod imp { const NR_GETRANDOM: libc::c_long = 355; #[cfg(target_arch = "arm")] const NR_GETRANDOM: libc::c_long = 384; + #[cfg(target_arch = "s390x")] + const NR_GETRANDOM: libc::c_long = 349; #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] const NR_GETRANDOM: libc::c_long = 359; #[cfg(target_arch = "aarch64")] @@ -71,7 +74,8 @@ mod imp { target_arch = "arm", target_arch = "aarch64", target_arch = "powerpc", - target_arch = "powerpc64"))))] + target_arch = "powerpc64", + target_arch = "s390x"))))] fn getrandom(_buf: &mut [u8]) -> libc::c_long { -1 } fn getrandom_fill_bytes(v: &mut [u8]) { @@ -110,7 +114,8 @@ mod imp { target_arch = "arm", target_arch = "aarch64", target_arch = "powerpc", - target_arch = "powerpc64")))] + target_arch = "powerpc64", + target_arch = "s390x")))] fn is_getrandom_available() -> bool { use sync::atomic::{AtomicBool, Ordering}; use sync::Once; @@ -139,7 +144,8 @@ mod imp { target_arch = "arm", target_arch = "aarch64", target_arch = "powerpc", - target_arch = "powerpc64"))))] + target_arch = "powerpc64", + target_arch = "s390x"))))] fn is_getrandom_available() -> bool { false } pub struct OsRng { diff --git a/src/libunwind/libunwind.rs b/src/libunwind/libunwind.rs index 8292a6841781..3900ba65293c 100644 --- a/src/libunwind/libunwind.rs +++ b/src/libunwind/libunwind.rs @@ -62,6 +62,9 @@ pub const unwinder_private_data_size: usize = 2; #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] pub const unwinder_private_data_size: usize = 2; +#[cfg(target_arch = "s390x")] +pub const unwinder_private_data_size: usize = 2; + #[cfg(target_arch = "asmjs")] pub const unwinder_private_data_size: usize = 20; diff --git a/src/test/compile-fail/asm-bad-clobber.rs b/src/test/compile-fail/asm-bad-clobber.rs index 714343a372d0..85832ddefe25 100644 --- a/src/test/compile-fail/asm-bad-clobber.rs +++ b/src/test/compile-fail/asm-bad-clobber.rs @@ -11,6 +11,7 @@ // ignore-android // ignore-arm // ignore-aarch64 +// ignore-s390x #![feature(asm, rustc_attrs)] diff --git a/src/test/compile-fail/asm-in-bad-modifier.rs b/src/test/compile-fail/asm-in-bad-modifier.rs index 3cb608a9c5ed..a4d076fc90da 100644 --- a/src/test/compile-fail/asm-in-bad-modifier.rs +++ b/src/test/compile-fail/asm-in-bad-modifier.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-s390x + #![feature(asm)] fn foo(x: isize) { println!("{}", x); } diff --git a/src/test/compile-fail/asm-misplaced-option.rs b/src/test/compile-fail/asm-misplaced-option.rs index 1020a5ba8a42..fbfc20f8d048 100644 --- a/src/test/compile-fail/asm-misplaced-option.rs +++ b/src/test/compile-fail/asm-misplaced-option.rs @@ -11,6 +11,7 @@ // ignore-android // ignore-arm // ignore-aarch64 +// ignore-s390x #![feature(asm, rustc_attrs)] diff --git a/src/test/compile-fail/asm-out-assign-imm.rs b/src/test/compile-fail/asm-out-assign-imm.rs index 0541faa02135..1329959fe493 100644 --- a/src/test/compile-fail/asm-out-assign-imm.rs +++ b/src/test/compile-fail/asm-out-assign-imm.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-s390x + #![feature(asm)] fn foo(x: isize) { println!("{}", x); } diff --git a/src/test/compile-fail/asm-out-no-modifier.rs b/src/test/compile-fail/asm-out-no-modifier.rs index 9cf43bebe65a..d610f9e34402 100644 --- a/src/test/compile-fail/asm-out-no-modifier.rs +++ b/src/test/compile-fail/asm-out-no-modifier.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-s390x + #![feature(asm)] fn foo(x: isize) { println!("{}", x); } diff --git a/src/test/compile-fail/asm-out-read-uninit.rs b/src/test/compile-fail/asm-out-read-uninit.rs index 5e71a2c731dd..360f89dda9ce 100644 --- a/src/test/compile-fail/asm-out-read-uninit.rs +++ b/src/test/compile-fail/asm-out-read-uninit.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// ignore-s390x + #![feature(asm)] fn foo(x: isize) { println!("{}", x); } diff --git a/src/test/debuginfo/simd.rs b/src/test/debuginfo/simd.rs index 620e1a73b4d6..80ac901b60fd 100644 --- a/src/test/debuginfo/simd.rs +++ b/src/test/debuginfo/simd.rs @@ -12,6 +12,11 @@ // ignore-lldb // ignore-tidy-linelength +// FIXME: LLVM generates invalid debug info for variables requiring +// dynamic stack realignment, which is the case on s390x for vector +// types with with non-vector ABI. +// ignore-s390x + // compile-flags:-g // gdb-command:run diff --git a/src/test/run-make/atomic-lock-free/Makefile b/src/test/run-make/atomic-lock-free/Makefile index 78e7bb231372..e2ccbe2ad147 100644 --- a/src/test/run-make/atomic-lock-free/Makefile +++ b/src/test/run-make/atomic-lock-free/Makefile @@ -27,4 +27,6 @@ ifeq ($(UNAME),Linux) nm "$(TMPDIR)/libatomic_lock_free.rlib" | grep -vq __atomic_fetch_add $(RUSTC) --target=powerpc64le-unknown-linux-gnu atomic_lock_free.rs nm "$(TMPDIR)/libatomic_lock_free.rlib" | grep -vq __atomic_fetch_add + $(RUSTC) --target=s390x-unknown-linux-gnu atomic_lock_free.rs + nm "$(TMPDIR)/libatomic_lock_free.rlib" | grep -vq __atomic_fetch_add endif diff --git a/src/test/run-pass/conditional-compile-arch.rs b/src/test/run-pass/conditional-compile-arch.rs index 44971e9252ed..368ffe6e713f 100644 --- a/src/test/run-pass/conditional-compile-arch.rs +++ b/src/test/run-pass/conditional-compile-arch.rs @@ -25,5 +25,8 @@ pub fn main() { } #[cfg(target_arch = "powerpc64")] pub fn main() { } +#[cfg(target_arch = "s390x")] +pub fn main() { } + #[cfg(target_arch = "asmjs")] pub fn main() { } diff --git a/src/test/run-pass/union/union-basic.rs b/src/test/run-pass/union/union-basic.rs index d23af4b41b73..dc14c12b6a22 100644 --- a/src/test/run-pass/union/union-basic.rs +++ b/src/test/run-pass/union/union-basic.rs @@ -10,6 +10,9 @@ // aux-build:union.rs +// FIXME: This test case makes little-endian assumptions. +// ignore-s390x + #![feature(untagged_unions)] extern crate union; diff --git a/src/tools/compiletest/src/util.rs b/src/tools/compiletest/src/util.rs index d2872a0a2b7c..2db53947d881 100644 --- a/src/tools/compiletest/src/util.rs +++ b/src/tools/compiletest/src/util.rs @@ -38,7 +38,7 @@ const ARCH_TABLE: &'static [(&'static str, &'static str)] = &[("aarch64", "aarch ("msp430", "msp430"), ("powerpc", "powerpc"), ("powerpc64", "powerpc64"), - ("s390x", "systemz"), + ("s390x", "s390x"), ("sparc", "sparc"), ("x86_64", "x86_64"), ("xcore", "xcore"), From fe41520fceb00427e797cc0b42f449f54967b104 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 9 Sep 2016 14:53:15 -0700 Subject: [PATCH 278/443] Add ExpnId to expanded procedural macro code --- src/libsyntax_ext/deriving/custom.rs | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/libsyntax_ext/deriving/custom.rs b/src/libsyntax_ext/deriving/custom.rs index 716cf3a94b51..465fc0016e5e 100644 --- a/src/libsyntax_ext/deriving/custom.rs +++ b/src/libsyntax_ext/deriving/custom.rs @@ -10,12 +10,14 @@ use std::panic; +use errors::FatalError; use rustc_macro::{TokenStream, __internal}; use syntax::ast::{self, ItemKind}; -use syntax::codemap::Span; +use syntax::codemap::{ExpnInfo, MacroAttribute, NameAndSpan, Span}; use syntax::ext::base::*; use syntax::fold::{self, Folder}; -use errors::FatalError; +use syntax::parse::token::intern; +use syntax::print::pprust; pub struct CustomDerive { inner: fn(TokenStream) -> TokenStream, @@ -31,7 +33,7 @@ impl MultiItemModifier for CustomDerive { fn expand(&self, ecx: &mut ExtCtxt, span: Span, - _meta_item: &ast::MetaItem, + meta_item: &ast::MetaItem, item: Annotatable) -> Vec { let item = match item { @@ -53,7 +55,17 @@ impl MultiItemModifier for CustomDerive { } } - let input_span = item.span; + let input_span = Span { + expn_id: ecx.codemap().record_expansion(ExpnInfo { + call_site: span, + callee: NameAndSpan { + format: MacroAttribute(intern(&pprust::meta_item_to_string(meta_item))), + span: Some(span), + allow_internal_unstable: true, + }, + }), + ..item.span + }; let input = __internal::new_token_stream(item); let res = __internal::set_parse_sess(&ecx.parse_sess, || { let inner = self.inner; From fb85dd398bad8043f73a349d42a1d8180b1048c4 Mon Sep 17 00:00:00 2001 From: Mikhail Modin Date: Thu, 8 Sep 2016 22:02:49 +0300 Subject: [PATCH 279/443] fix span for errors E0537, E0535 & E0536 --- src/libsyntax/parse/attr.rs | 10 +++++----- src/test/{compile-fail => ui/span}/E0535.rs | 0 src/test/ui/span/E0535.stderr | 8 ++++++++ src/test/{compile-fail => ui/span}/E0536.rs | 0 src/test/ui/span/E0536.stderr | 8 ++++++++ src/test/{compile-fail => ui/span}/E0537.rs | 0 src/test/ui/span/E0537.stderr | 8 ++++++++ 7 files changed, 29 insertions(+), 5 deletions(-) rename src/test/{compile-fail => ui/span}/E0535.rs (100%) create mode 100644 src/test/ui/span/E0535.stderr rename src/test/{compile-fail => ui/span}/E0536.rs (100%) create mode 100644 src/test/ui/span/E0536.stderr rename src/test/{compile-fail => ui/span}/E0537.rs (100%) create mode 100644 src/test/ui/span/E0537.stderr diff --git a/src/libsyntax/parse/attr.rs b/src/libsyntax/parse/attr.rs index 27dd055cd3ae..a0defbc09dc0 100644 --- a/src/libsyntax/parse/attr.rs +++ b/src/libsyntax/parse/attr.rs @@ -125,7 +125,7 @@ impl<'a> Parser<'a> { self.expect(&token::OpenDelim(token::Bracket))?; let meta_item = self.parse_meta_item()?; - let hi = self.span.hi; + let hi = self.last_span.hi; self.expect(&token::CloseDelim(token::Bracket))?; (mk_sp(lo, hi), meta_item, style) @@ -231,12 +231,12 @@ impl<'a> Parser<'a> { token::Eq => { self.bump(); let lit = self.parse_unsuffixed_lit()?; - let hi = self.span.hi; + let hi = self.last_span.hi; Ok(P(spanned(lo, hi, ast::MetaItemKind::NameValue(name, lit)))) } token::OpenDelim(token::Paren) => { let inner_items = self.parse_meta_seq()?; - let hi = self.span.hi; + let hi = self.last_span.hi; Ok(P(spanned(lo, hi, ast::MetaItemKind::List(name, inner_items)))) } _ => { @@ -253,14 +253,14 @@ impl<'a> Parser<'a> { match self.parse_unsuffixed_lit() { Ok(lit) => { - return Ok(spanned(lo, self.span.hi, ast::NestedMetaItemKind::Literal(lit))) + return Ok(spanned(lo, self.last_span.hi, ast::NestedMetaItemKind::Literal(lit))) } Err(ref mut err) => self.diagnostic().cancel(err) } match self.parse_meta_item() { Ok(mi) => { - return Ok(spanned(lo, self.span.hi, ast::NestedMetaItemKind::MetaItem(mi))) + return Ok(spanned(lo, self.last_span.hi, ast::NestedMetaItemKind::MetaItem(mi))) } Err(ref mut err) => self.diagnostic().cancel(err) } diff --git a/src/test/compile-fail/E0535.rs b/src/test/ui/span/E0535.rs similarity index 100% rename from src/test/compile-fail/E0535.rs rename to src/test/ui/span/E0535.rs diff --git a/src/test/ui/span/E0535.stderr b/src/test/ui/span/E0535.stderr new file mode 100644 index 000000000000..23070e1555b9 --- /dev/null +++ b/src/test/ui/span/E0535.stderr @@ -0,0 +1,8 @@ +error[E0535]: invalid argument + --> $DIR/E0535.rs:11:10 + | +11 | #[inline(unknown)] //~ ERROR E0535 + | ^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/compile-fail/E0536.rs b/src/test/ui/span/E0536.rs similarity index 100% rename from src/test/compile-fail/E0536.rs rename to src/test/ui/span/E0536.rs diff --git a/src/test/ui/span/E0536.stderr b/src/test/ui/span/E0536.stderr new file mode 100644 index 000000000000..c33b89953e27 --- /dev/null +++ b/src/test/ui/span/E0536.stderr @@ -0,0 +1,8 @@ +error[E0536]: expected 1 cfg-pattern + --> $DIR/E0536.rs:11:7 + | +11 | #[cfg(not())] //~ ERROR E0536 + | ^^^^^ + +error: aborting due to previous error + diff --git a/src/test/compile-fail/E0537.rs b/src/test/ui/span/E0537.rs similarity index 100% rename from src/test/compile-fail/E0537.rs rename to src/test/ui/span/E0537.rs diff --git a/src/test/ui/span/E0537.stderr b/src/test/ui/span/E0537.stderr new file mode 100644 index 000000000000..9d66ddbaae31 --- /dev/null +++ b/src/test/ui/span/E0537.stderr @@ -0,0 +1,8 @@ +error[E0537]: invalid predicate `unknown` + --> $DIR/E0537.rs:11:7 + | +11 | #[cfg(unknown())] //~ ERROR E0537 + | ^^^^^^^^^ + +error: aborting due to previous error + From b693a2e0adfd4c7b366d0ab147ca9f6fade51051 Mon Sep 17 00:00:00 2001 From: dangcheng Date: Sat, 10 Sep 2016 16:30:59 +0800 Subject: [PATCH 280/443] fix mistake (File::open -> File::create) --- src/doc/book/traits.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/book/traits.md b/src/doc/book/traits.md index 9cbb514e2806..605dc2a152df 100644 --- a/src/doc/book/traits.md +++ b/src/doc/book/traits.md @@ -275,7 +275,7 @@ won’t have its methods: [write]: ../std/io/trait.Write.html ```rust,ignore -let mut f = std::fs::File::open("foo.txt").expect("Couldn’t open foo.txt"); +let mut f = std::fs::File::create("foo.txt").expect("Couldn’t open foo.txt"); let buf = b"whatever"; // byte string literal. buf: &[u8; 8] let result = f.write(buf); # result.unwrap(); // ignore the error @@ -294,7 +294,7 @@ We need to `use` the `Write` trait first: ```rust,ignore use std::io::Write; -let mut f = std::fs::File::open("foo.txt").expect("Couldn’t open foo.txt"); +let mut f = std::fs::File::create("foo.txt").expect("Couldn’t open foo.txt"); let buf = b"whatever"; let result = f.write(buf); # result.unwrap(); // ignore the error From 38009bfa91d9e928babb03e749b33b2476288227 Mon Sep 17 00:00:00 2001 From: Kylo Ginsberg Date: Sat, 10 Sep 2016 07:58:30 -0700 Subject: [PATCH 281/443] book: fix a typo --- src/doc/book/references-and-borrowing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/book/references-and-borrowing.md b/src/doc/book/references-and-borrowing.md index 57bfbce8b84d..2ec3a00c0df5 100644 --- a/src/doc/book/references-and-borrowing.md +++ b/src/doc/book/references-and-borrowing.md @@ -152,7 +152,7 @@ the thing `y` points at. You’ll notice that `x` had to be marked `mut` as well If it wasn’t, we couldn’t take a mutable borrow to an immutable value. You'll also notice we added an asterisk (`*`) in front of `y`, making it `*y`, -this is because `y` is a `&mut` reference. You'll need to use astrisks to +this is because `y` is a `&mut` reference. You'll need to use asterisks to access the contents of a reference as well. Otherwise, `&mut` references are like references. There _is_ a large From 2a2c9d38c78ece0a6c5de80e382a136173e64b14 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 26 Aug 2016 19:23:42 +0300 Subject: [PATCH 282/443] Improve shallow `Clone` deriving --- src/libcore/clone.rs | 19 +- src/libsyntax_ext/deriving/clone.rs | 181 +++++++++++------- src/libsyntax_ext/deriving/generic/mod.rs | 27 ++- .../borrowck/borrowck-union-borrow-nested.rs | 6 +- .../borrowck/borrowck-union-borrow.rs | 6 +- src/test/compile-fail/union/union-copy.rs | 4 +- .../compile-fail/union/union-derive-clone.rs | 41 ++++ src/test/compile-fail/union/union-derive.rs | 1 - src/test/run-pass/union/union-c-interop.rs | 7 +- src/test/run-pass/union/union-derive.rs | 9 +- 10 files changed, 200 insertions(+), 101 deletions(-) create mode 100644 src/test/compile-fail/union/union-derive-clone.rs diff --git a/src/libcore/clone.rs b/src/libcore/clone.rs index 748bb62a1f3e..3333cbfc1fc4 100644 --- a/src/libcore/clone.rs +++ b/src/libcore/clone.rs @@ -106,10 +106,23 @@ pub trait Clone : Sized { } } -// FIXME(aburka): this method is used solely by #[derive] to -// assert that every component of a type implements Clone. +// FIXME(aburka): these structs are used solely by #[derive] to +// assert that every component of a type implements Clone or Copy. // -// This should never be called by user code. +// These structs should never appear in user code. +#[doc(hidden)] +#[allow(missing_debug_implementations)] +#[unstable(feature = "derive_clone_copy", + reason = "deriving hack, should not be public", + issue = "0")] +pub struct AssertParamIsClone { _field: ::marker::PhantomData } +#[doc(hidden)] +#[allow(missing_debug_implementations)] +#[unstable(feature = "derive_clone_copy", + reason = "deriving hack, should not be public", + issue = "0")] +pub struct AssertParamIsCopy { _field: ::marker::PhantomData } +#[cfg(stage0)] #[doc(hidden)] #[inline(always)] #[unstable(feature = "derive_clone_copy", diff --git a/src/libsyntax_ext/deriving/clone.rs b/src/libsyntax_ext/deriving/clone.rs index c7afaaf4796a..aa7c2c301dd7 100644 --- a/src/libsyntax_ext/deriving/clone.rs +++ b/src/libsyntax_ext/deriving/clone.rs @@ -11,20 +11,14 @@ use deriving::generic::*; use deriving::generic::ty::*; -use syntax::ast::{Expr, Generics, ItemKind, MetaItem, VariantData}; +use syntax::ast::{self, Expr, Generics, ItemKind, MetaItem, VariantData}; use syntax::attr; use syntax::ext::base::{Annotatable, ExtCtxt}; use syntax::ext::build::AstBuilder; -use syntax::parse::token::InternedString; +use syntax::parse::token::{keywords, InternedString}; use syntax::ptr::P; use syntax_pos::Span; -#[derive(PartialEq)] -enum Mode { - Deep, - Shallow, -} - pub fn expand_deriving_clone(cx: &mut ExtCtxt, span: Span, mitem: &MetaItem, @@ -40,29 +34,38 @@ pub fn expand_deriving_clone(cx: &mut ExtCtxt, // if we used the short form with generics, we'd have to bound the generics with // Clone + Copy, and then there'd be no Clone impl at all if the user fills in something // that is Clone but not Copy. and until specialization we can't write both impls. + // - the item is a union with Copy fields + // Unions with generic parameters still can derive Clone because they require Copy + // for deriving, Clone alone is not enough. + // Whever Clone is implemented for fields is irrelevant so we don't assert it. let bounds; - let unify_fieldless_variants; let substructure; + let is_shallow; match *item { Annotatable::Item(ref annitem) => { match annitem.node { ItemKind::Struct(_, Generics { ref ty_params, .. }) | ItemKind::Enum(_, Generics { ref ty_params, .. }) - if ty_params.is_empty() && - attr::contains_name(&annitem.attrs, "rustc_copy_clone_marker") => { - - bounds = vec![Literal(path_std!(cx, core::marker::Copy))]; - unify_fieldless_variants = true; + if attr::contains_name(&annitem.attrs, "rustc_copy_clone_marker") && + ty_params.is_empty() => { + bounds = vec![]; + is_shallow = true; substructure = combine_substructure(Box::new(|c, s, sub| { - cs_clone("Clone", c, s, sub, Mode::Shallow) + cs_clone_shallow("Clone", c, s, sub, false) + })); + } + ItemKind::Union(..) => { + bounds = vec![Literal(path_std!(cx, core::marker::Copy))]; + is_shallow = true; + substructure = combine_substructure(Box::new(|c, s, sub| { + cs_clone_shallow("Clone", c, s, sub, true) })); } - _ => { bounds = vec![]; - unify_fieldless_variants = false; + is_shallow = false; substructure = combine_substructure(Box::new(|c, s, sub| { - cs_clone("Clone", c, s, sub, Mode::Deep) + cs_clone("Clone", c, s, sub) })); } } @@ -80,7 +83,7 @@ pub fn expand_deriving_clone(cx: &mut ExtCtxt, additional_bounds: bounds, generics: LifetimeBounds::empty(), is_unsafe: false, - supports_unions: false, + supports_unions: true, methods: vec![MethodDef { name: "clone", generics: LifetimeBounds::empty(), @@ -89,37 +92,85 @@ pub fn expand_deriving_clone(cx: &mut ExtCtxt, ret_ty: Self_, attributes: attrs, is_unsafe: false, - unify_fieldless_variants: unify_fieldless_variants, + unify_fieldless_variants: false, combine_substructure: substructure, }], associated_types: Vec::new(), }; - trait_def.expand(cx, mitem, item, push) + trait_def.expand_ext(cx, mitem, item, push, is_shallow) +} + +fn cs_clone_shallow(name: &str, + cx: &mut ExtCtxt, + trait_span: Span, + substr: &Substructure, + is_union: bool) + -> P { + fn assert_ty_bounds(cx: &mut ExtCtxt, stmts: &mut Vec, + ty: P, span: Span, helper_name: &str) { + // Generate statement `let _: helper_name;`, + // set the expn ID so we can use the unstable struct. + let span = super::allow_unstable(cx, span, "derive(Clone)"); + let assert_path = cx.path_all(span, true, + cx.std_path(&["clone", helper_name]), + vec![], vec![ty], vec![]); + let local = P(ast::Local { + pat: cx.pat_wild(span), + ty: Some(cx.ty_path(assert_path)), + init: None, + id: ast::DUMMY_NODE_ID, + span: span, + attrs: ast::ThinVec::new(), + }); + let stmt = ast::Stmt { + id: ast::DUMMY_NODE_ID, + node: ast::StmtKind::Local(local), + span: span, + }; + stmts.push(stmt); + } + fn process_variant(cx: &mut ExtCtxt, stmts: &mut Vec, variant: &VariantData) { + for field in variant.fields() { + // let _: AssertParamIsClone; + assert_ty_bounds(cx, stmts, field.ty.clone(), field.span, "AssertParamIsClone"); + } + } + + let mut stmts = Vec::new(); + if is_union { + // let _: AssertParamIsCopy; + let self_ty = cx.ty_path(cx.path_ident(trait_span, keywords::SelfType.ident())); + assert_ty_bounds(cx, &mut stmts, self_ty, trait_span, "AssertParamIsCopy"); + } else { + match *substr.fields { + StaticStruct(vdata, ..) => { + process_variant(cx, &mut stmts, vdata); + } + StaticEnum(enum_def, ..) => { + for variant in &enum_def.variants { + process_variant(cx, &mut stmts, &variant.node.data); + } + } + _ => cx.span_bug(trait_span, &format!("unexpected substructure in \ + shallow `derive({})`", name)) + } + } + stmts.push(cx.stmt_expr(cx.expr_deref(trait_span, cx.expr_self(trait_span)))); + cx.expr_block(cx.block(trait_span, stmts)) } fn cs_clone(name: &str, cx: &mut ExtCtxt, trait_span: Span, - substr: &Substructure, - mode: Mode) + substr: &Substructure) -> P { let ctor_path; let all_fields; - let fn_path = match mode { - Mode::Shallow => cx.std_path(&["clone", "assert_receiver_is_clone"]), - Mode::Deep => cx.std_path(&["clone", "Clone", "clone"]), - }; + let fn_path = cx.std_path(&["clone", "Clone", "clone"]); let subcall = |cx: &mut ExtCtxt, field: &FieldInfo| { let args = vec![cx.expr_addr_of(field.span, field.self_.clone())]; - - let span = if mode == Mode::Shallow { - // set the expn ID so we can call the unstable method - super::allow_unstable(cx, field.span, "derive(Clone)") - } else { - field.span - }; - cx.expr_call_global(span, fn_path.clone(), args) + cx.expr_call_global(field.span, fn_path.clone(), args) }; let vdata; @@ -145,43 +196,31 @@ fn cs_clone(name: &str, } } - match mode { - Mode::Shallow => { - let mut stmts = all_fields.iter().map(|f| { - let call = subcall(cx, f); - cx.stmt_expr(call) - }).collect::>(); - stmts.push(cx.stmt_expr(cx.expr_deref(trait_span, cx.expr_self(trait_span)))); - cx.expr_block(cx.block(trait_span, stmts)) - } - Mode::Deep => { - match *vdata { - VariantData::Struct(..) => { - let fields = all_fields.iter() - .map(|field| { - let ident = match field.name { - Some(i) => i, - None => { - cx.span_bug(trait_span, - &format!("unnamed field in normal struct in \ - `derive({})`", - name)) - } - }; - let call = subcall(cx, field); - cx.field_imm(field.span, ident, call) - }) - .collect::>(); + match *vdata { + VariantData::Struct(..) => { + let fields = all_fields.iter() + .map(|field| { + let ident = match field.name { + Some(i) => i, + None => { + cx.span_bug(trait_span, + &format!("unnamed field in normal struct in \ + `derive({})`", + name)) + } + }; + let call = subcall(cx, field); + cx.field_imm(field.span, ident, call) + }) + .collect::>(); - cx.expr_struct(trait_span, ctor_path, fields) - } - VariantData::Tuple(..) => { - let subcalls = all_fields.iter().map(|f| subcall(cx, f)).collect(); - let path = cx.expr_path(ctor_path); - cx.expr_call(trait_span, path, subcalls) - } - VariantData::Unit(..) => cx.expr_path(ctor_path), - } + cx.expr_struct(trait_span, ctor_path, fields) } + VariantData::Tuple(..) => { + let subcalls = all_fields.iter().map(|f| subcall(cx, f)).collect(); + let path = cx.expr_path(ctor_path); + cx.expr_call(trait_span, path, subcalls) + } + VariantData::Unit(..) => cx.expr_path(ctor_path), } } diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index 600f5d335c47..339a6c477ccd 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -401,18 +401,29 @@ impl<'a> TraitDef<'a> { mitem: &ast::MetaItem, item: &'a Annotatable, push: &mut FnMut(Annotatable)) { + self.expand_ext(cx, mitem, item, push, false); + } + + pub fn expand_ext(&self, + cx: &mut ExtCtxt, + mitem: &ast::MetaItem, + item: &'a Annotatable, + push: &mut FnMut(Annotatable), + from_scratch: bool) { match *item { Annotatable::Item(ref item) => { let newitem = match item.node { ast::ItemKind::Struct(ref struct_def, ref generics) => { - self.expand_struct_def(cx, &struct_def, item.ident, generics) + self.expand_struct_def(cx, &struct_def, item.ident, generics, from_scratch) } ast::ItemKind::Enum(ref enum_def, ref generics) => { - self.expand_enum_def(cx, enum_def, &item.attrs, item.ident, generics) + self.expand_enum_def(cx, enum_def, &item.attrs, + item.ident, generics, from_scratch) } ast::ItemKind::Union(ref struct_def, ref generics) => { if self.supports_unions { - self.expand_struct_def(cx, &struct_def, item.ident, generics) + self.expand_struct_def(cx, &struct_def, item.ident, + generics, from_scratch) } else { cx.span_err(mitem.span, "this trait cannot be derived for unions"); @@ -661,7 +672,8 @@ impl<'a> TraitDef<'a> { cx: &mut ExtCtxt, struct_def: &'a VariantData, type_ident: Ident, - generics: &Generics) + generics: &Generics, + from_scratch: bool) -> P { let field_tys: Vec> = struct_def.fields() .iter() @@ -674,7 +686,7 @@ impl<'a> TraitDef<'a> { let (explicit_self, self_args, nonself_args, tys) = method_def.split_self_nonself_args(cx, self, type_ident, generics); - let body = if method_def.is_static() { + let body = if from_scratch || method_def.is_static() { method_def.expand_static_struct_method_body(cx, self, struct_def, @@ -709,7 +721,8 @@ impl<'a> TraitDef<'a> { enum_def: &'a EnumDef, type_attrs: &[ast::Attribute], type_ident: Ident, - generics: &Generics) + generics: &Generics, + from_scratch: bool) -> P { let mut field_tys = Vec::new(); @@ -727,7 +740,7 @@ impl<'a> TraitDef<'a> { let (explicit_self, self_args, nonself_args, tys) = method_def.split_self_nonself_args(cx, self, type_ident, generics); - let body = if method_def.is_static() { + let body = if from_scratch || method_def.is_static() { method_def.expand_static_enum_method_body(cx, self, enum_def, diff --git a/src/test/compile-fail/borrowck/borrowck-union-borrow-nested.rs b/src/test/compile-fail/borrowck/borrowck-union-borrow-nested.rs index 19975d79b60b..8b6b8d9ecb08 100644 --- a/src/test/compile-fail/borrowck/borrowck-union-borrow-nested.rs +++ b/src/test/compile-fail/borrowck/borrowck-union-borrow-nested.rs @@ -18,16 +18,12 @@ struct S { b: u16, } +#[derive(Clone, Copy)] union U { s: S, c: u32, } -impl Clone for U { - fn clone(&self) -> Self { *self } -} -impl Copy for U {} - fn main() { unsafe { { diff --git a/src/test/compile-fail/borrowck/borrowck-union-borrow.rs b/src/test/compile-fail/borrowck/borrowck-union-borrow.rs index e8989a3c2d49..ecc698acc317 100644 --- a/src/test/compile-fail/borrowck/borrowck-union-borrow.rs +++ b/src/test/compile-fail/borrowck/borrowck-union-borrow.rs @@ -12,16 +12,12 @@ #![feature(untagged_unions)] +#[derive(Clone, Copy)] union U { a: u8, b: u64, } -impl Clone for U { - fn clone(&self) -> Self { *self } -} -impl Copy for U {} - fn main() { unsafe { let mut u = U { b: 0 }; diff --git a/src/test/compile-fail/union/union-copy.rs b/src/test/compile-fail/union/union-copy.rs index 6e08ae0074d4..9014b3f2956b 100644 --- a/src/test/compile-fail/union/union-copy.rs +++ b/src/test/compile-fail/union/union-copy.rs @@ -10,16 +10,16 @@ #![feature(untagged_unions)] +#[derive(Clone)] union U { a: u8 } +#[derive(Clone)] union W { a: String } -impl Clone for U { fn clone(&self) { panic!(); } } -impl Clone for W { fn clone(&self) { panic!(); } } impl Copy for U {} // OK impl Copy for W {} //~ ERROR the trait `Copy` may not be implemented for this type diff --git a/src/test/compile-fail/union/union-derive-clone.rs b/src/test/compile-fail/union/union-derive-clone.rs new file mode 100644 index 000000000000..6e226d7d79f9 --- /dev/null +++ b/src/test/compile-fail/union/union-derive-clone.rs @@ -0,0 +1,41 @@ +// 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. + +#![feature(untagged_unions)] + +#[derive(Clone)] //~ ERROR the trait bound `U1: std::marker::Copy` is not satisfied +union U1 { + a: u8, +} + +#[derive(Clone)] +union U2 { + a: u8, // OK +} + +impl Copy for U2 {} + +#[derive(Clone, Copy)] +union U3 { + a: u8, // OK +} + +#[derive(Clone, Copy)] +union U4 { + a: T, // OK +} + +#[derive(Clone)] +struct CloneNoCopy; + +fn main() { + let u = U4 { a: CloneNoCopy }; + let w = u.clone(); //~ ERROR no method named `clone` found for type `U4` +} diff --git a/src/test/compile-fail/union/union-derive.rs b/src/test/compile-fail/union/union-derive.rs index 0f78e96f640c..01ce9696284d 100644 --- a/src/test/compile-fail/union/union-derive.rs +++ b/src/test/compile-fail/union/union-derive.rs @@ -13,7 +13,6 @@ #![feature(untagged_unions)] #[derive( - Clone, //~ ERROR this trait cannot be derived for unions PartialEq, //~ ERROR this trait cannot be derived for unions Eq, //~ ERROR this trait cannot be derived for unions PartialOrd, //~ ERROR this trait cannot be derived for unions diff --git a/src/test/run-pass/union/union-c-interop.rs b/src/test/run-pass/union/union-c-interop.rs index a9f97620ebd4..bea4d5f923e2 100644 --- a/src/test/run-pass/union/union-c-interop.rs +++ b/src/test/run-pass/union/union-c-interop.rs @@ -10,14 +10,14 @@ #![feature(untagged_unions)] -#[derive(Copy)] +#[derive(Clone, Copy)] #[repr(C)] struct LARGE_INTEGER_U { LowPart: u32, HighPart: u32, } -#[derive(Copy)] +#[derive(Clone, Copy)] #[repr(C)] union LARGE_INTEGER { __unnamed__: LARGE_INTEGER_U, @@ -25,9 +25,6 @@ union LARGE_INTEGER { QuadPart: u64, } -impl Clone for LARGE_INTEGER_U { fn clone(&self) -> Self { *self } } -impl Clone for LARGE_INTEGER { fn clone(&self) -> Self { *self } } - #[link(name = "rust_test_helpers")] extern "C" { fn increment_all_parts(_: LARGE_INTEGER) -> LARGE_INTEGER; diff --git a/src/test/run-pass/union/union-derive.rs b/src/test/run-pass/union/union-derive.rs index b71c23990a47..8314416e2b10 100644 --- a/src/test/run-pass/union/union-derive.rs +++ b/src/test/run-pass/union/union-derive.rs @@ -14,18 +14,23 @@ #[derive( Copy, + Clone, )] union U { a: u8, b: u16, } -impl Clone for U { - fn clone(&self) -> Self { *self } +#[derive(Clone, Copy)] +union W { + a: T, } fn main() { let u = U { b: 0 }; let u1 = u; let u2 = u.clone(); + + let w = W { a: 0 }; + let w1 = w.clone(); } From 63fecad2e7c1f58e962a100d4159ddd47ebc627f Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 9 Sep 2016 20:39:49 -0700 Subject: [PATCH 283/443] Inherit overflow checks for sum and product --- src/libcore/iter/iterator.rs | 6 ++-- src/libcore/iter/traits.rs | 19 ++++------ src/test/run-pass/iter-sum-overflow-debug.rs | 35 +++++++++++++++++++ src/test/run-pass/iter-sum-overflow-ndebug.rs | 23 ++++++++++++ 4 files changed, 69 insertions(+), 14 deletions(-) create mode 100644 src/test/run-pass/iter-sum-overflow-debug.rs create mode 100644 src/test/run-pass/iter-sum-overflow-ndebug.rs diff --git a/src/libcore/iter/iterator.rs b/src/libcore/iter/iterator.rs index 6b616f801815..0e74bbe9c260 100644 --- a/src/libcore/iter/iterator.rs +++ b/src/libcore/iter/iterator.rs @@ -1867,7 +1867,8 @@ pub trait Iterator { /// # Panics /// /// When calling `sum` and a primitive integer type is being returned, this - /// method will panic if the computation overflows. + /// method will panic if the computation overflows and debug assertions are + /// enabled. /// /// # Examples /// @@ -1894,7 +1895,8 @@ pub trait Iterator { /// # Panics /// /// When calling `product` and a primitive integer type is being returned, - /// this method will panic if the computation overflows. + /// method will panic if the computation overflows and debug assertions are + /// enabled. /// /// # Examples /// diff --git a/src/libcore/iter/traits.rs b/src/libcore/iter/traits.rs index 59e23c4d9605..563fb213d376 100644 --- a/src/libcore/iter/traits.rs +++ b/src/libcore/iter/traits.rs @@ -7,6 +7,7 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. +use ops::{Mul, Add}; /// Conversion from an `Iterator`. /// @@ -581,41 +582,35 @@ pub trait Product: Sized { fn product>(iter: I) -> Self; } +// NB: explicitly use Add and Mul here to inherit overflow checks macro_rules! integer_sum_product { ($($a:ident)*) => ($( #[stable(feature = "iter_arith_traits", since = "1.12.0")] impl Sum for $a { + #[rustc_inherit_overflow_checks] fn sum>(iter: I) -> $a { - iter.fold(0, |a, b| { - a.checked_add(b).expect("overflow in sum") - }) + iter.fold(0, Add::add) } } #[stable(feature = "iter_arith_traits", since = "1.12.0")] impl Product for $a { fn product>(iter: I) -> $a { - iter.fold(1, |a, b| { - a.checked_mul(b).expect("overflow in product") - }) + iter.fold(1, Mul::mul) } } #[stable(feature = "iter_arith_traits", since = "1.12.0")] impl<'a> Sum<&'a $a> for $a { fn sum>(iter: I) -> $a { - iter.fold(0, |a, b| { - a.checked_add(*b).expect("overflow in sum") - }) + iter.cloned().fold(0, Add::add) } } #[stable(feature = "iter_arith_traits", since = "1.12.0")] impl<'a> Product<&'a $a> for $a { fn product>(iter: I) -> $a { - iter.fold(1, |a, b| { - a.checked_mul(*b).expect("overflow in product") - }) + iter.cloned().fold(1, Mul::mul) } } )*) diff --git a/src/test/run-pass/iter-sum-overflow-debug.rs b/src/test/run-pass/iter-sum-overflow-debug.rs new file mode 100644 index 000000000000..6c07afb37b8a --- /dev/null +++ b/src/test/run-pass/iter-sum-overflow-debug.rs @@ -0,0 +1,35 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -C debug_assertions=yes + +use std::panic; + +fn main() { + let r = panic::catch_unwind(|| { + [1, i32::max_value()].iter().sum::(); + }); + assert!(r.is_err()); + + let r = panic::catch_unwind(|| { + [2, i32::max_value()].iter().product::(); + }); + assert!(r.is_err()); + + let r = panic::catch_unwind(|| { + [1, i32::max_value()].iter().cloned().sum::(); + }); + assert!(r.is_err()); + + let r = panic::catch_unwind(|| { + [2, i32::max_value()].iter().cloned().product::(); + }); + assert!(r.is_err()); +} diff --git a/src/test/run-pass/iter-sum-overflow-ndebug.rs b/src/test/run-pass/iter-sum-overflow-ndebug.rs new file mode 100644 index 000000000000..65ac1ef29ed6 --- /dev/null +++ b/src/test/run-pass/iter-sum-overflow-ndebug.rs @@ -0,0 +1,23 @@ +// 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. + +// compile-flags: -C debug_assertions=no + +fn main() { + assert_eq!([1i32, i32::max_value()].iter().sum::(), + 1i32.wrapping_add(i32::max_value())); + assert_eq!([2i32, i32::max_value()].iter().product::(), + 2i32.wrapping_mul(i32::max_value())); + + assert_eq!([1i32, i32::max_value()].iter().cloned().sum::(), + 1i32.wrapping_add(i32::max_value())); + assert_eq!([2i32, i32::max_value()].iter().cloned().product::(), + 2i32.wrapping_mul(i32::max_value())); +} From 72e103fe90f678f6c6028f17cdd9a5b825a8c5f9 Mon Sep 17 00:00:00 2001 From: Keegan McAllister Date: Thu, 8 Sep 2016 20:04:05 -0700 Subject: [PATCH 284/443] Tweak std::mem docs Fixes #29362. --- src/libcore/intrinsics.rs | 47 +++--- src/libcore/mem.rs | 294 ++++++++++++++++++++++++++------------ 2 files changed, 231 insertions(+), 110 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 8271b85b01a3..06b506ab014b 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -262,22 +262,25 @@ extern "rust-intrinsic" { /// Moves a value out of scope without running drop glue. pub fn forget(_: T) -> (); - /// Reinterprets the bits of a value of one type as another type; both types - /// must have the same size. Neither the original, nor the result, may be an - /// [invalid value] (../../nomicon/meet-safe-and-unsafe.html). + /// Reinterprets the bits of a value of one type as another type. + /// + /// Both types must have the same size. Neither the original, nor the result, + /// may be an [invalid value](../../nomicon/meet-safe-and-unsafe.html). /// /// `transmute` is semantically equivalent to a bitwise move of one type - /// into another. It copies the bits from the destination type into the - /// source type, then forgets the original. It's equivalent to C's `memcpy` - /// under the hood, just like `transmute_copy`. + /// into another. It copies the bits from the source value into the + /// destination value, then forgets the original. It's equivalent to C's + /// `memcpy` under the hood, just like `transmute_copy`. /// - /// `transmute` is incredibly unsafe. There are a vast number of ways to - /// cause undefined behavior with this function. `transmute` should be + /// `transmute` is **incredibly** unsafe. There are a vast number of ways to + /// cause [undefined behavior][ub] with this function. `transmute` should be /// the absolute last resort. /// /// The [nomicon](../../nomicon/transmutes.html) has additional /// documentation. /// + /// [ub]: ../../reference.html#behavior-considered-undefined + /// /// # Examples /// /// There are a few things that `transmute` is really useful for. @@ -292,7 +295,8 @@ extern "rust-intrinsic" { /// assert_eq!(bitpattern, 0x3F800000); /// ``` /// - /// Turning a pointer into a function pointer: + /// Turning a pointer into a function pointer. This is *not* portable to + /// machines where function pointers and data pointers have different sizes. /// /// ``` /// fn foo() -> i32 { @@ -305,8 +309,8 @@ extern "rust-intrinsic" { /// assert_eq!(function(), 0); /// ``` /// - /// Extending a lifetime, or shortening an invariant lifetime; this is - /// advanced, very unsafe rust: + /// Extending a lifetime, or shortening an invariant lifetime. This is + /// advanced, very unsafe Rust! /// /// ``` /// struct R<'a>(&'a i32); @@ -322,11 +326,9 @@ extern "rust-intrinsic" { /// /// # Alternatives /// - /// However, many uses of `transmute` can be achieved through other means. - /// `transmute` can transform any type into any other, with just the caveat - /// that they're the same size, and often interesting results occur. Below - /// are common applications of `transmute` which can be replaced with safe - /// applications of `as`: + /// Don't despair: many uses of `transmute` can be achieved through other means. + /// Below are common applications of `transmute` which can be replaced with safer + /// constructs. /// /// Turning a pointer into a `usize`: /// @@ -335,6 +337,7 @@ extern "rust-intrinsic" { /// let ptr_num_transmute = unsafe { /// std::mem::transmute::<&i32, usize>(ptr) /// }; + /// /// // Use an `as` cast instead /// let ptr_num_cast = ptr as *const i32 as usize; /// ``` @@ -346,6 +349,7 @@ extern "rust-intrinsic" { /// let ref_transmuted = unsafe { /// std::mem::transmute::<*mut i32, &mut i32>(ptr) /// }; + /// /// // Use a reborrow instead /// let ref_casted = unsafe { &mut *ptr }; /// ``` @@ -357,6 +361,7 @@ extern "rust-intrinsic" { /// let val_transmuted = unsafe { /// std::mem::transmute::<&mut i32, &mut u32>(ptr) /// }; + /// /// // Now, put together `as` and reborrowing - note the chaining of `as` /// // `as` is not transitive /// let val_casts = unsafe { &mut *(ptr as *mut i32 as *mut u32) }; @@ -368,9 +373,11 @@ extern "rust-intrinsic" { /// // this is not a good way to do this. /// let slice = unsafe { std::mem::transmute::<&str, &[u8]>("Rust") }; /// assert_eq!(slice, &[82, 117, 115, 116]); + /// /// // You could use `str::as_bytes` /// let slice = "Rust".as_bytes(); /// assert_eq!(slice, &[82, 117, 115, 116]); + /// /// // Or, just use a byte string, if you have control over the string /// // literal /// assert_eq!(b"Rust", &[82, 117, 115, 116]); @@ -381,18 +388,21 @@ extern "rust-intrinsic" { /// ``` /// let store = [0, 1, 2, 3]; /// let mut v_orig = store.iter().collect::>(); + /// /// // Using transmute: this is Undefined Behavior, and a bad idea. /// // However, it is no-copy. /// let v_transmuted = unsafe { /// std::mem::transmute::, Vec>>( /// v_orig.clone()) /// }; + /// /// // This is the suggested, safe way. - /// // It does copy the entire Vector, though, into a new array. + /// // It does copy the entire vector, though, into a new array. /// let v_collected = v_orig.clone() /// .into_iter() /// .map(|r| Some(r)) /// .collect::>>(); + /// /// // The no-copy, unsafe way, still using transmute, but not UB. /// // This is equivalent to the original, but safer, and reuses the /// // same Vec internals. Therefore the new inner type must have the @@ -412,6 +422,7 @@ extern "rust-intrinsic" { /// /// ``` /// use std::{slice, mem}; + /// /// // There are multiple ways to do this; and there are multiple problems /// // with the following, transmute, way. /// fn split_at_mut_transmute(slice: &mut [T], mid: usize) @@ -426,6 +437,7 @@ extern "rust-intrinsic" { /// (&mut slice[0..mid], &mut slice2[mid..len]) /// } /// } + /// /// // This gets rid of the typesafety problems; `&mut *` will *only* give /// // you an `&mut T` from an `&mut T` or `*mut T`. /// fn split_at_mut_casts(slice: &mut [T], mid: usize) @@ -439,6 +451,7 @@ extern "rust-intrinsic" { /// (&mut slice[0..mid], &mut slice2[mid..len]) /// } /// } + /// /// // This is how the standard library does it. This is the best method, if /// // you need to do something like this /// fn split_at_stdlib(slice: &mut [T], mid: usize) diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index 9c61f76ac889..d3b8a60b7977 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -21,54 +21,39 @@ use ptr; #[stable(feature = "rust1", since = "1.0.0")] pub use intrinsics::transmute; -/// Leaks a value into the void, consuming ownership and never running its -/// destructor. +/// Leaks a value: takes ownership and "forgets" about the value **without running +/// its destructor**. /// -/// This function will take ownership of its argument, but is distinct from the -/// `mem::drop` function in that it **does not run the destructor**, leaking the -/// value and any resources that it owns. +/// Any resources the value manages, such as heap memory or a file handle, will linger +/// forever in an unreachable state. /// -/// There's only a few reasons to use this function. They mainly come -/// up in unsafe code or FFI code. -/// -/// * You have an uninitialized value, perhaps for performance reasons, and -/// need to prevent the destructor from running on it. -/// * You have two copies of a value (like when writing something like -/// [`mem::swap`][swap]), but need the destructor to only run once to -/// prevent a double `free`. -/// * Transferring resources across [FFI][ffi] boundaries. -/// -/// [swap]: fn.swap.html -/// [ffi]: ../../book/ffi.html +/// If you want to dispose of a value properly, running its destructor, see +/// [`mem::drop`][drop]. /// /// # Safety /// -/// This function is not marked as `unsafe` as Rust does not guarantee that the -/// `Drop` implementation for a value will always run. Note, however, that -/// leaking resources such as memory or I/O objects is likely not desired, so -/// this function is only recommended for specialized use cases. +/// `forget` is not marked as `unsafe`, because Rust's safety guarantees +/// do not include a guarantee that destructors will always run. For example, +/// a program can create a reference cycle using [`Rc`][rc], or call +/// [`process:exit`][exit] to exit without running destructors. Thus, allowing +/// `mem::forget` from safe code does not fundamentally change Rust's safety +/// guarantees. /// -/// The safety of this function implies that when writing `unsafe` code -/// yourself care must be taken when leveraging a destructor that is required to -/// run to preserve memory safety. There are known situations where the -/// destructor may not run (such as if ownership of the object with the -/// destructor is returned) which must be taken into account. +/// That said, leaking resources such as memory or I/O objects is usually undesirable, +/// so `forget` is only recommended for specialized use cases like those shown below. /// -/// # Other forms of Leakage +/// Because forgetting a value is allowed, any `unsafe` code you write must +/// allow for this possibility. You cannot return a value and expect that the +/// caller will necessarily run the value's destructor. /// -/// It's important to point out that this function is not the only method by -/// which a value can be leaked in safe Rust code. Other known sources of -/// leakage are: +/// [rc]: ../../std/rc/struct.Rc.html +/// [exit]: ../../std/process/fn.exit.html /// -/// * `Rc` and `Arc` cycles -/// * `mpsc::{Sender, Receiver}` cycles (they use `Arc` internally) -/// * Panicking destructors are likely to leak local resources -/// -/// # Example +/// # Examples /// /// Leak some heap memory by never deallocating it: /// -/// ```rust +/// ``` /// use std::mem; /// /// let heap_memory = Box::new(3); @@ -77,7 +62,7 @@ pub use intrinsics::transmute; /// /// Leak an I/O object, never closing the file: /// -/// ```rust,no_run +/// ```no_run /// use std::mem; /// use std::fs::File; /// @@ -85,9 +70,43 @@ pub use intrinsics::transmute; /// mem::forget(file); /// ``` /// -/// The `mem::swap` function uses `mem::forget` to good effect: +/// The practical use cases for `forget` are rather specialized and mainly come +/// up in unsafe or FFI code. /// -/// ```rust +/// ## Use case 1 +/// +/// You have created an uninitialized value using [`mem::uninitialized`][uninit]. +/// You must either initialize or `forget` it on every computation path before +/// Rust drops it automatically, like at the end of a scope or after a panic. +/// Running the destructor on an uninitialized value would be [undefined behavior][ub]. +/// +/// ``` +/// use std::mem; +/// use std::ptr; +/// +/// # let some_condition = false; +/// unsafe { +/// let mut uninit_vec: Vec = mem::uninitialized(); +/// +/// if some_condition { +/// // Initialize the variable. +/// ptr::write(&mut uninit_vec, Vec::new()); +/// } else { +/// // Forget the uninitialized value so its destructor doesn't run. +/// mem::forget(uninit_vec); +/// } +/// } +/// ``` +/// +/// ## Use case 2 +/// +/// You have duplicated the bytes making up a value, without doing a proper +/// [`Clone`][clone]. You need the value's destructor to run only once, +/// because a double `free` is undefined behavior. +/// +/// An example is the definition of [`mem::swap`][swap] in this module: +/// +/// ``` /// use std::mem; /// use std::ptr; /// @@ -109,6 +128,41 @@ pub use intrinsics::transmute; /// } /// } /// ``` +/// +/// ## Use case 3 +/// +/// You are transferring ownership across a [FFI] boundary to code written in +/// another language. You need to `forget` the value on the Rust side because Rust +/// code is no longer responsible for it. +/// +/// ```no_run +/// use std::mem; +/// +/// extern "C" { +/// fn my_c_function(x: *const u32); +/// } +/// +/// let x: Box = Box::new(3); +/// +/// // Transfer ownership into C code. +/// unsafe { +/// my_c_function(&*x); +/// } +/// mem::forget(x); +/// ``` +/// +/// In this case, C code must call back into Rust to free the object. Calling C's `free` +/// function on a [`Box`][box] is *not* safe! Also, `Box` provides an [`into_raw`][into_raw] +/// method which is the preferred way to do this in practice. +/// +/// [drop]: fn.drop.html +/// [uninit]: fn.uninitialized.html +/// [clone]: ../clone/trait.Clone.html +/// [swap]: fn.swap.html +/// [FFI]: ../../book/ffi.html +/// [box]: ../../std/boxed/struct.Box.html +/// [into_raw]: ../../std/boxed/struct.Box.html#method.into_raw +/// [ub]: ../../reference.html#behavior-considered-undefined #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn forget(t: T) { @@ -133,7 +187,14 @@ pub fn size_of() -> usize { unsafe { intrinsics::size_of::() } } -/// Returns the size of the given value in bytes. +/// Returns the size of the pointed-to value in bytes. +/// +/// This is usually the same as `size_of::()`. However, when `T` *has* no +/// statically known size, e.g. a slice [`[T]`][slice] or a [trait object], +/// then `size_of_val` can be used to get the dynamically-known size. +/// +/// [slice]: ../../std/primitive.slice.html +/// [trait object]: ../../book/trait-objects.html /// /// # Examples /// @@ -141,6 +202,10 @@ pub fn size_of() -> usize { /// use std::mem; /// /// assert_eq!(4, mem::size_of_val(&5i32)); +/// +/// let x: [u8; 13] = [0; 13]; +/// let y: &[u8] = &x; +/// assert_eq!(13, mem::size_of_val(y)); /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] @@ -148,10 +213,14 @@ pub fn size_of_val(val: &T) -> usize { unsafe { intrinsics::size_of_val(val) } } -/// Returns the ABI-required minimum alignment of a type +/// Returns the [ABI]-required minimum alignment of a type. +/// +/// Every valid address of a value of the type `T` must be a multiple of this number. /// /// This is the alignment used for struct fields. It may be smaller than the preferred alignment. /// +/// [ABI]: https://en.wikipedia.org/wiki/Application_binary_interface +/// /// # Examples /// /// ``` @@ -167,7 +236,11 @@ pub fn min_align_of() -> usize { unsafe { intrinsics::min_align_of::() } } -/// Returns the ABI-required minimum alignment of the type of the value that `val` points to +/// Returns the [ABI]-required minimum alignment of the type of the value that `val` points to. +/// +/// Every valid address of a value of the type `T` must be a multiple of this number. +/// +/// [ABI]: https://en.wikipedia.org/wiki/Application_binary_interface /// /// # Examples /// @@ -184,10 +257,14 @@ pub fn min_align_of_val(val: &T) -> usize { unsafe { intrinsics::min_align_of_val(val) } } -/// Returns the alignment in memory for a type. +/// Returns the [ABI]-required minimum alignment of a type. +/// +/// Every valid address of a value of the type `T` must be a multiple of this number. /// /// This is the alignment used for struct fields. It may be smaller than the preferred alignment. /// +/// [ABI]: https://en.wikipedia.org/wiki/Application_binary_interface +/// /// # Examples /// /// ``` @@ -201,7 +278,11 @@ pub fn align_of() -> usize { unsafe { intrinsics::min_align_of::() } } -/// Returns the ABI-required minimum alignment of the type of the value that `val` points to +/// Returns the [ABI]-required minimum alignment of the type of the value that `val` points to. +/// +/// Every valid address of a value of the type `T` must be a multiple of this number. +/// +/// [ABI]: https://en.wikipedia.org/wiki/Application_binary_interface /// /// # Examples /// @@ -216,16 +297,23 @@ pub fn align_of_val(val: &T) -> usize { unsafe { intrinsics::min_align_of_val(val) } } -/// Creates a value initialized to zero. +/// Creates a value whose bytes are all zero. /// -/// This function is similar to allocating space for a local variable and zeroing it out (an unsafe -/// operation). +/// This has the same effect as allocating space with +/// [`mem::uninitialized`][uninit] and then zeroing it out. It is useful for +/// [FFI] sometimes, but should generally be avoided. /// -/// Care must be taken when using this function, if the type `T` has a destructor and the value -/// falls out of scope (due to unwinding or returning) before being initialized, then the -/// destructor will run on zeroed data, likely leading to crashes. +/// There is no guarantee that an all-zero byte-pattern represents a valid value of +/// some type `T`. If `T` has a destructor and the value is destroyed (due to +/// a panic or the end of a scope) before being initialized, then the destructor +/// will run on zeroed data, likely leading to [undefined behavior][ub]. /// -/// This is useful for FFI functions sometimes, but should generally be avoided. +/// See also the documentation for [`mem::uninitialized`][uninit], which has +/// many of the same caveats. +/// +/// [uninit]: fn.uninitialized.html +/// [FFI]: ../../book/ffi.html +/// [ub]: ../../reference.html#behavior-considered-undefined /// /// # Examples /// @@ -233,6 +321,7 @@ pub fn align_of_val(val: &T) -> usize { /// use std::mem; /// /// let x: i32 = unsafe { mem::zeroed() }; +/// assert_eq!(0, x); /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] @@ -241,32 +330,38 @@ pub unsafe fn zeroed() -> T { } /// Bypasses Rust's normal memory-initialization checks by pretending to -/// produce a value of type T, while doing nothing at all. +/// produce a value of type `T`, while doing nothing at all. /// /// **This is incredibly dangerous, and should not be done lightly. Deeply /// consider initializing your memory with a default value instead.** /// -/// This is useful for FFI functions and initializing arrays sometimes, +/// This is useful for [FFI] functions and initializing arrays sometimes, /// but should generally be avoided. /// -/// # Undefined Behavior +/// [FFI]: ../../book/ffi.html /// -/// It is Undefined Behavior to read uninitialized memory. Even just an +/// # Undefined behavior +/// +/// It is [undefined behavior][ub] to read uninitialized memory, even just an /// uninitialized boolean. For instance, if you branch on the value of such -/// a boolean your program may take one, both, or neither of the branches. +/// a boolean, your program may take one, both, or neither of the branches. /// -/// Note that this often also includes *writing* to the uninitialized value. -/// Rust believes the value is initialized, and will therefore try to Drop -/// the uninitialized value and its fields if you try to overwrite the memory -/// in a normal manner. The only way to safely initialize an arbitrary -/// uninitialized value is with one of the `ptr` functions: `write`, `copy`, or -/// `copy_nonoverlapping`. This isn't necessary if `T` is a primitive -/// or otherwise only contains types that don't implement Drop. +/// Writing to the uninitialized value is similarly dangerous. Rust believes the +/// value is initialized, and will therefore try to [`Drop`][drop] the uninitialized +/// value and its fields if you try to overwrite it in a normal manner. The only way +/// to safely initialize an uninitialized value is with [`ptr::write`][write], +/// [`ptr::copy`][copy], or [`ptr::copy_nonoverlapping`][copy_no]. /// -/// If this value *does* need some kind of Drop, it must be initialized before +/// If the value does implement `Drop`, it must be initialized before /// it goes out of scope (and therefore would be dropped). Note that this /// includes a `panic` occurring and unwinding the stack suddenly. /// +/// [ub]: ../../reference.html#behavior-considered-undefined +/// [write]: ../ptr/fn.write.html +/// [copy]: ../intrinsics/fn.copy.html +/// [copy_no]: ../intrinsics/fn.copy_nonoverlapping.html +/// [drop]: ../ops/trait.Drop.html +/// /// # Examples /// /// Here's how to safely initialize an array of `Vec`s. @@ -309,8 +404,8 @@ pub unsafe fn zeroed() -> T { /// println!("{:?}", &data[0]); /// ``` /// -/// This example emphasizes exactly how delicate and dangerous doing this is. -/// Note that the `vec!` macro *does* let you initialize every element with a +/// This example emphasizes exactly how delicate and dangerous using `mem::uninitialized` +/// can be. Note that the `vec!` macro *does* let you initialize every element with a /// value that is only `Clone`, so the following is semantically equivalent and /// vastly less dangerous, as long as you can live with an extra heap /// allocation: @@ -325,21 +420,20 @@ pub unsafe fn uninitialized() -> T { intrinsics::uninit() } -/// Swap the values at two mutable locations of the same type, without deinitializing or copying -/// either one. +/// Swaps the values at two mutable locations, without deinitializing either one. /// /// # Examples /// /// ``` /// use std::mem; /// -/// let x = &mut 5; -/// let y = &mut 42; +/// let mut x = 5; +/// let mut y = 42; /// -/// mem::swap(x, y); +/// mem::swap(&mut x, &mut y); /// -/// assert_eq!(42, *x); -/// assert_eq!(5, *y); +/// assert_eq!(42, x); +/// assert_eq!(5, y); /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] @@ -361,10 +455,7 @@ pub fn swap(x: &mut T, y: &mut T) { } /// Replaces the value at a mutable location with a new one, returning the old value, without -/// deinitializing or copying either one. -/// -/// This is primarily used for transferring and swapping ownership of a value in a mutable -/// location. +/// deinitializing either one. /// /// # Examples /// @@ -373,15 +464,17 @@ pub fn swap(x: &mut T, y: &mut T) { /// ``` /// use std::mem; /// -/// let mut v: Vec = Vec::new(); +/// let mut v: Vec = vec![1, 2]; /// -/// mem::replace(&mut v, Vec::new()); +/// let old_v = mem::replace(&mut v, vec![3, 4, 5]); +/// assert_eq!(2, old_v.len()); +/// assert_eq!(3, v.len()); /// ``` /// -/// This function allows consumption of one field of a struct by replacing it with another value. -/// The normal approach doesn't always work: +/// `replace` allows consumption of a struct field by replacing it with another value. +/// Without `replace` you can run into issues like these: /// -/// ```rust,ignore +/// ```ignore /// struct Buffer { buf: Vec } /// /// impl Buffer { @@ -401,6 +494,7 @@ pub fn swap(x: &mut T, y: &mut T) { /// ``` /// # #![allow(dead_code)] /// use std::mem; +/// /// # struct Buffer { buf: Vec } /// impl Buffer { /// fn get_and_reset(&mut self) -> Vec { @@ -417,14 +511,25 @@ pub fn replace(dest: &mut T, mut src: T) -> T { /// Disposes of a value. /// -/// While this does call the argument's implementation of `Drop`, it will not -/// release any borrows, as borrows are based on lexical scope. +/// While this does call the argument's implementation of [`Drop`][drop], +/// it will not release any borrows, as borrows are based on lexical scope. /// /// This effectively does nothing for /// [types which implement `Copy`](../../book/ownership.html#copy-types), /// e.g. integers. Such values are copied and _then_ moved into the function, /// so the value persists after this function call. /// +/// This function is not magic; it is literally defined as +/// +/// ``` +/// pub fn drop(_x: T) { } +/// ``` +/// +/// Because `_x` is moved into the function, it is automatically dropped before +/// the function returns. +/// +/// [drop]: ../ops/trait.Drop.html +/// /// # Examples /// /// Basic usage: @@ -461,8 +566,8 @@ pub fn replace(dest: &mut T, mut src: T) -> T { /// v.push(4); // no problems /// ``` /// -/// Since `RefCell` enforces the borrow rules at runtime, `drop()` can -/// seemingly release a borrow of one: +/// Since `RefCell` enforces the borrow rules at runtime, `drop` can +/// release a `RefCell` borrow: /// /// ``` /// use std::cell::RefCell; @@ -478,7 +583,7 @@ pub fn replace(dest: &mut T, mut src: T) -> T { /// println!("{}", *borrow); /// ``` /// -/// Integers and other types implementing `Copy` are unaffected by `drop()` +/// Integers and other types implementing `Copy` are unaffected by `drop`. /// /// ``` /// #[derive(Copy, Clone)] @@ -496,19 +601,22 @@ pub fn replace(dest: &mut T, mut src: T) -> T { #[stable(feature = "rust1", since = "1.0.0")] pub fn drop(_x: T) { } -/// Interprets `src` as `&U`, and then reads `src` without moving the contained -/// value. +/// Interprets `src` as having type `&U`, and then reads `src` without moving +/// the contained value. /// /// This function will unsafely assume the pointer `src` is valid for -/// `sizeof(U)` bytes by transmuting `&T` to `&U` and then reading the `&U`. It -/// will also unsafely create a copy of the contained value instead of moving -/// out of `src`. +/// [`size_of::()`][size_of] bytes by transmuting `&T` to `&U` and then reading +/// the `&U`. It will also unsafely create a copy of the contained value instead of +/// moving out of `src`. /// /// It is not a compile-time error if `T` and `U` have different sizes, but it /// is highly encouraged to only invoke this function where `T` and `U` have the -/// same size. This function triggers undefined behavior if `U` is larger than +/// same size. This function triggers [undefined behavior][ub] if `U` is larger than /// `T`. /// +/// [ub]: ../../reference.html#behavior-considered-undefined +/// [size_of]: fn.size_of.html +/// /// # Examples /// /// ``` From 62cb7510ac6285c93ec691198a92f910582d31a2 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 26 Aug 2016 19:23:42 +0300 Subject: [PATCH 285/443] Improve `Eq` deriving --- src/libcore/cmp.rs | 13 ++++- src/libsyntax/ext/build.rs | 18 ++++++ src/libsyntax_ext/deriving/clone.rs | 15 +---- src/libsyntax_ext/deriving/cmp/eq.rs | 55 ++++++++++++------- .../compile-fail/union/union-derive-eq.rs | 30 ++++++++++ src/test/compile-fail/union/union-derive.rs | 1 - src/test/run-pass/union/union-derive.rs | 13 ++++- 7 files changed, 109 insertions(+), 36 deletions(-) create mode 100644 src/test/compile-fail/union/union-derive-eq.rs diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index 670978a2d49a..f990a27e52b3 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -129,7 +129,7 @@ pub trait PartialEq { /// This trait can be used with `#[derive]`. When `derive`d, because `Eq` has /// no extra methods, it is only informing the compiler that this is an /// equivalence relation rather than a partial equivalence relation. Note that -/// the `derive` strategy requires all fields are `PartialEq`, which isn't +/// the `derive` strategy requires all fields are `Eq`, which isn't /// always desired. /// /// ## How can I implement `Eq`? @@ -165,6 +165,17 @@ pub trait Eq: PartialEq { fn assert_receiver_is_total_eq(&self) {} } +// FIXME: this struct is used solely by #[derive] to +// assert that every component of a type implements Eq. +// +// This struct should never appear in user code. +#[doc(hidden)] +#[allow(missing_debug_implementations)] +#[unstable(feature = "derive_eq", + reason = "deriving hack, should not be public", + issue = "0")] +pub struct AssertParamIsEq { _field: ::marker::PhantomData } + /// An `Ordering` is the result of a comparison between two values. /// /// # Examples diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 3dcdbc890962..b81d95a6998c 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -97,6 +97,7 @@ pub trait AstBuilder { typ: P, ex: P) -> P; + fn stmt_let_type_only(&self, span: Span, ty: P) -> ast::Stmt; fn stmt_item(&self, sp: Span, item: P) -> ast::Stmt; // blocks @@ -577,6 +578,23 @@ impl<'a> AstBuilder for ExtCtxt<'a> { }) } + // Generate `let _: Type;`, usually used for type assertions. + fn stmt_let_type_only(&self, span: Span, ty: P) -> ast::Stmt { + let local = P(ast::Local { + pat: self.pat_wild(span), + ty: Some(ty), + init: None, + id: ast::DUMMY_NODE_ID, + span: span, + attrs: ast::ThinVec::new(), + }); + ast::Stmt { + id: ast::DUMMY_NODE_ID, + node: ast::StmtKind::Local(local), + span: span, + } + } + fn stmt_item(&self, sp: Span, item: P) -> ast::Stmt { ast::Stmt { id: ast::DUMMY_NODE_ID, diff --git a/src/libsyntax_ext/deriving/clone.rs b/src/libsyntax_ext/deriving/clone.rs index aa7c2c301dd7..d7bc2a6faeeb 100644 --- a/src/libsyntax_ext/deriving/clone.rs +++ b/src/libsyntax_ext/deriving/clone.rs @@ -115,20 +115,7 @@ fn cs_clone_shallow(name: &str, let assert_path = cx.path_all(span, true, cx.std_path(&["clone", helper_name]), vec![], vec![ty], vec![]); - let local = P(ast::Local { - pat: cx.pat_wild(span), - ty: Some(cx.ty_path(assert_path)), - init: None, - id: ast::DUMMY_NODE_ID, - span: span, - attrs: ast::ThinVec::new(), - }); - let stmt = ast::Stmt { - id: ast::DUMMY_NODE_ID, - node: ast::StmtKind::Local(local), - span: span, - }; - stmts.push(stmt); + stmts.push(cx.stmt_let_type_only(span, cx.ty_path(assert_path))); } fn process_variant(cx: &mut ExtCtxt, stmts: &mut Vec, variant: &VariantData) { for field in variant.fields() { diff --git a/src/libsyntax_ext/deriving/cmp/eq.rs b/src/libsyntax_ext/deriving/cmp/eq.rs index 425a47a991bc..fa0fb2492c55 100644 --- a/src/libsyntax_ext/deriving/cmp/eq.rs +++ b/src/libsyntax_ext/deriving/cmp/eq.rs @@ -11,7 +11,7 @@ use deriving::generic::*; use deriving::generic::ty::*; -use syntax::ast::{Expr, MetaItem}; +use syntax::ast::{self, Expr, MetaItem}; use syntax::ext::base::{Annotatable, ExtCtxt}; use syntax::ext::build::AstBuilder; use syntax::parse::token::InternedString; @@ -23,22 +23,6 @@ pub fn expand_deriving_eq(cx: &mut ExtCtxt, mitem: &MetaItem, item: &Annotatable, push: &mut FnMut(Annotatable)) { - fn cs_total_eq_assert(cx: &mut ExtCtxt, span: Span, substr: &Substructure) -> P { - cs_same_method(|cx, span, exprs| { - // create `a.(); b.(); c.(); ...` - // (where method is `assert_receiver_is_total_eq`) - let stmts = exprs.into_iter().map(|e| cx.stmt_expr(e)).collect(); - let block = cx.block(span, stmts); - cx.expr_block(block) - }, - Box::new(|cx, sp, _, _| { - cx.span_bug(sp, "non matching enums in derive(Eq)?") - }), - cx, - span, - substr) - } - let inline = cx.meta_word(span, InternedString::new("inline")); let hidden = cx.meta_list_item_word(span, InternedString::new("hidden")); let doc = cx.meta_list(span, InternedString::new("doc"), vec![hidden]); @@ -50,7 +34,7 @@ pub fn expand_deriving_eq(cx: &mut ExtCtxt, additional_bounds: Vec::new(), generics: LifetimeBounds::empty(), is_unsafe: false, - supports_unions: false, + supports_unions: true, methods: vec![MethodDef { name: "assert_receiver_is_total_eq", generics: LifetimeBounds::empty(), @@ -66,5 +50,38 @@ pub fn expand_deriving_eq(cx: &mut ExtCtxt, }], associated_types: Vec::new(), }; - trait_def.expand(cx, mitem, item, push) + trait_def.expand_ext(cx, mitem, item, push, true) +} + +fn cs_total_eq_assert(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) -> P { + fn assert_ty_bounds(cx: &mut ExtCtxt, stmts: &mut Vec, + ty: P, span: Span, helper_name: &str) { + // Generate statement `let _: helper_name;`, + // set the expn ID so we can use the unstable struct. + let span = super::allow_unstable(cx, span, "derive(Eq)"); + let assert_path = cx.path_all(span, true, + cx.std_path(&["cmp", helper_name]), + vec![], vec![ty], vec![]); + stmts.push(cx.stmt_let_type_only(span, cx.ty_path(assert_path))); + } + fn process_variant(cx: &mut ExtCtxt, stmts: &mut Vec, variant: &ast::VariantData) { + for field in variant.fields() { + // let _: AssertParamIsEq; + assert_ty_bounds(cx, stmts, field.ty.clone(), field.span, "AssertParamIsEq"); + } + } + + let mut stmts = Vec::new(); + match *substr.fields { + StaticStruct(vdata, ..) => { + process_variant(cx, &mut stmts, vdata); + } + StaticEnum(enum_def, ..) => { + for variant in &enum_def.variants { + process_variant(cx, &mut stmts, &variant.node.data); + } + } + _ => cx.span_bug(trait_span, "unexpected substructure in `derive(Eq)`") + } + cx.expr_block(cx.block(trait_span, stmts)) } diff --git a/src/test/compile-fail/union/union-derive-eq.rs b/src/test/compile-fail/union/union-derive-eq.rs new file mode 100644 index 000000000000..9dfec288c157 --- /dev/null +++ b/src/test/compile-fail/union/union-derive-eq.rs @@ -0,0 +1,30 @@ +// 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. + +#![feature(untagged_unions)] + +#[derive(Eq)] // OK +union U1 { + a: u8, +} + +impl PartialEq for U1 { fn eq(&self, rhs: &Self) -> bool { true } } + +#[derive(PartialEq)] +struct PartialEqNotEq; + +#[derive(Eq)] +union U2 { + a: PartialEqNotEq, //~ ERROR the trait bound `PartialEqNotEq: std::cmp::Eq` is not satisfied +} + +impl PartialEq for U2 { fn eq(&self, rhs: &Self) -> bool { true } } + +fn main() {} diff --git a/src/test/compile-fail/union/union-derive.rs b/src/test/compile-fail/union/union-derive.rs index 01ce9696284d..26dbdfd0b411 100644 --- a/src/test/compile-fail/union/union-derive.rs +++ b/src/test/compile-fail/union/union-derive.rs @@ -14,7 +14,6 @@ #[derive( PartialEq, //~ ERROR this trait cannot be derived for unions - Eq, //~ ERROR this trait cannot be derived for unions PartialOrd, //~ ERROR this trait cannot be derived for unions Ord, //~ ERROR this trait cannot be derived for unions Hash, //~ ERROR this trait cannot be derived for unions diff --git a/src/test/run-pass/union/union-derive.rs b/src/test/run-pass/union/union-derive.rs index 8314416e2b10..8ff6f17394f9 100644 --- a/src/test/run-pass/union/union-derive.rs +++ b/src/test/run-pass/union/union-derive.rs @@ -15,22 +15,33 @@ #[derive( Copy, Clone, + Eq, )] union U { a: u8, b: u16, } -#[derive(Clone, Copy)] +impl PartialEq for U { fn eq(&self, rhs: &Self) -> bool { true } } + +#[derive( + Clone, + Copy, + Eq +)] union W { a: T, } +impl PartialEq for W { fn eq(&self, rhs: &Self) -> bool { true } } + fn main() { let u = U { b: 0 }; let u1 = u; let u2 = u.clone(); + assert!(u1 == u2); let w = W { a: 0 }; let w1 = w.clone(); + assert!(w == w1); } From f647db4c8a8e6e49aac60e973044b6556af5a3ad Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Sat, 10 Sep 2016 13:22:19 -0700 Subject: [PATCH 286/443] Update E0297 to new error format --- src/librustc_const_eval/check_match.rs | 7 +++++-- src/test/compile-fail/E0297.rs | 4 +++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs index da4445ef6894..a1e7d0a1e34d 100644 --- a/src/librustc_const_eval/check_match.rs +++ b/src/librustc_const_eval/check_match.rs @@ -410,10 +410,13 @@ fn check_exhaustive<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>, }, _ => bug!(), }; - span_err!(cx.tcx.sess, sp, E0297, + let pattern_string = pat_to_string(witness); + struct_span_err!(cx.tcx.sess, sp, E0297, "refutable pattern in `for` loop binding: \ `{}` not covered", - pat_to_string(witness)); + pattern_string) + .span_label(sp, &format!("pattern `{}` not covered", pattern_string)) + .emit(); }, _ => { let pattern_strings: Vec<_> = witnesses.iter().map(|w| { diff --git a/src/test/compile-fail/E0297.rs b/src/test/compile-fail/E0297.rs index 43166c1a9e83..32c129b22a16 100644 --- a/src/test/compile-fail/E0297.rs +++ b/src/test/compile-fail/E0297.rs @@ -11,5 +11,7 @@ fn main() { let xs : Vec> = vec!(Some(1), None); - for Some(x) in xs {} //~ ERROR E0297 + for Some(x) in xs {} + //~^ ERROR E0297 + //~| NOTE pattern `None` not covered } From 3d289278ee123a67827c2b8bbff053d904d7373a Mon Sep 17 00:00:00 2001 From: ggomez Date: Fri, 9 Sep 2016 16:07:31 +0200 Subject: [PATCH 287/443] Improve Clone doc --- src/libcore/clone.rs | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/src/libcore/clone.rs b/src/libcore/clone.rs index 748bb62a1f3e..69355c6c6cc0 100644 --- a/src/libcore/clone.rs +++ b/src/libcore/clone.rs @@ -14,10 +14,14 @@ //! assign them or pass them as arguments, the receiver will get a copy, //! leaving the original value in place. These types do not require //! allocation to copy and do not have finalizers (i.e. they do not -//! contain owned boxes or implement `Drop`), so the compiler considers +//! contain owned boxes or implement [`Drop`]), so the compiler considers //! them cheap and safe to copy. For other types copies must be made -//! explicitly, by convention implementing the `Clone` trait and calling -//! the `clone` method. +//! explicitly, by convention implementing the [`Clone`] trait and calling +//! the [`clone`][clone] method. +//! +//! [`Clone`]: trait.Clone.html +//! [clone]: trait.Clone.html#tymethod.clone +//! [`Drop`]: ../../std/ops/trait.Drop.html //! //! Basic usage example: //! @@ -46,22 +50,22 @@ /// A common trait for the ability to explicitly duplicate an object. /// -/// Differs from `Copy` in that `Copy` is implicit and extremely inexpensive, while +/// Differs from [`Copy`] in that [`Copy`] is implicit and extremely inexpensive, while /// `Clone` is always explicit and may or may not be expensive. In order to enforce -/// these characteristics, Rust does not allow you to reimplement `Copy`, but you +/// these characteristics, Rust does not allow you to reimplement [`Copy`], but you /// may reimplement `Clone` and run arbitrary code. /// -/// Since `Clone` is more general than `Copy`, you can automatically make anything -/// `Copy` be `Clone` as well. +/// Since `Clone` is more general than [`Copy`], you can automatically make anything +/// [`Copy`] be `Clone` as well. /// /// ## Derivable /// /// This trait can be used with `#[derive]` if all fields are `Clone`. The `derive`d -/// implementation of `clone()` calls `clone()` on each field. +/// implementation of [`clone()`] calls [`clone()`] on each field. /// /// ## How can I implement `Clone`? /// -/// Types that are `Copy` should have a trivial implementation of `Clone`. More formally: +/// Types that are [`Copy`] should have a trivial implementation of `Clone`. More formally: /// if `T: Copy`, `x: T`, and `y: &T`, then `let x = y.clone();` is equivalent to `let x = *y;`. /// Manual implementations should be careful to uphold this invariant; however, unsafe code /// must not rely on it to ensure memory safety. @@ -70,6 +74,9 @@ /// library only implements `Clone` up until arrays of size 32. In this case, the implementation of /// `Clone` cannot be `derive`d, but can be implemented as: /// +/// [`Copy`]: ../../std/marker/trait.Copy.html +/// [`clone()`]: trait.Clone.html#tymethod.clone +/// /// ``` /// #[derive(Copy)] /// struct Stats { From 48dc0ba307abe4e0abdc16db7ebc5915bf813f01 Mon Sep 17 00:00:00 2001 From: ggomez Date: Fri, 9 Sep 2016 16:07:44 +0200 Subject: [PATCH 288/443] Improve Copy trait doc --- src/libcore/marker.rs | 51 +++++++++++++++++++++++++++++-------------- 1 file changed, 35 insertions(+), 16 deletions(-) diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index 0a46813df7eb..c22c9f0d1c71 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -126,7 +126,7 @@ pub trait Unsize { /// } /// ``` /// -/// The `PointList` `struct` cannot implement `Copy`, because `Vec` is not `Copy`. If we +/// The `PointList` `struct` cannot implement `Copy`, because [`Vec`] is not `Copy`. If we /// attempt to derive a `Copy` implementation, we'll get an error: /// /// ```text @@ -136,10 +136,10 @@ pub trait Unsize { /// ## When can my type _not_ be `Copy`? /// /// Some types can't be copied safely. For example, copying `&mut T` would create an aliased -/// mutable reference, and copying `String` would result in two attempts to free the same buffer. +/// mutable reference, and copying [`String`] would result in two attempts to free the same buffer. /// -/// Generalizing the latter case, any type implementing `Drop` can't be `Copy`, because it's -/// managing some resource besides its own `size_of::()` bytes. +/// Generalizing the latter case, any type implementing [`Drop`] can't be `Copy`, because it's +/// managing some resource besides its own [`size_of::()`] bytes. /// /// ## What if I derive `Copy` on a type that can't? /// @@ -156,8 +156,7 @@ pub trait Unsize { /// /// ## Derivable /// -/// This trait can be used with `#[derive]` if all of its components implement `Copy` and the type -/// implements `Clone`. The implementation will copy the bytes of each field using `memcpy`. +/// This trait can be used with `#[derive]` if all of its components implement `Copy` and the type. /// /// ## How can I implement `Copy`? /// @@ -178,6 +177,11 @@ pub trait Unsize { /// /// There is a small difference between the two: the `derive` strategy will also place a `Copy` /// bound on type parameters, which isn't always desired. +/// +/// [`Vec`]: ../../std/vec/struct.Vec.html +/// [`String`]: ../../std/string/struct.String.html +/// [`Drop`]: ../../std/ops/trait.Drop.html +/// [`size_of::()`]: ../../std/mem/fn.size_of.html #[stable(feature = "rust1", since = "1.0.0")] #[lang = "copy"] pub trait Copy : Clone { @@ -190,11 +194,11 @@ pub trait Copy : Clone { /// thread-safe. In other words, there is no possibility of data races /// when passing `&T` references between threads. /// -/// As one would expect, primitive types like `u8` and `f64` are all +/// As one would expect, primitive types like [`u8`] and [`f64`] are all /// `Sync`, and so are simple aggregate types containing them (like /// tuples, structs and enums). More instances of basic `Sync` types /// include "immutable" types like `&T` and those with simple -/// inherited mutability, such as `Box`, `Vec` and most other +/// inherited mutability, such as [`Box`], [`Vec`] and most other /// collection types. (Generic parameters need to be `Sync` for their /// container to be `Sync`.) /// @@ -206,27 +210,42 @@ pub trait Copy : Clone { /// race. /// /// Types that are not `Sync` are those that have "interior -/// mutability" in a non-thread-safe way, such as `Cell` and `RefCell` -/// in `std::cell`. These types allow for mutation of their contents +/// mutability" in a non-thread-safe way, such as [`Cell`] and [`RefCell`] +/// in [`std::cell`]. These types allow for mutation of their contents /// even when in an immutable, aliasable slot, e.g. the contents of -/// `&Cell` can be `.set`, and do not ensure data races are +/// [`&Cell`][`Cell`] can be [`.set`], and do not ensure data races are /// impossible, hence they cannot be `Sync`. A higher level example /// of a non-`Sync` type is the reference counted pointer -/// `std::rc::Rc`, because any reference `&Rc` can clone a new +/// [`std::rc::Rc`][`Rc`], because any reference [`&Rc`][`Rc`] can clone a new /// reference, which modifies the reference counts in a non-atomic /// way. /// /// For cases when one does need thread-safe interior mutability, -/// types like the atomics in `std::sync` and `Mutex` & `RWLock` in -/// the `sync` crate do ensure that any mutation cannot cause data +/// types like the atomics in [`std::sync`][`sync`] and [`Mutex`] / [`RwLock`] in +/// the [`sync`] crate do ensure that any mutation cannot cause data /// races. Hence these types are `Sync`. /// -/// Any types with interior mutability must also use the `std::cell::UnsafeCell` +/// Any types with interior mutability must also use the [`std::cell::UnsafeCell`] /// wrapper around the value(s) which can be mutated when behind a `&` /// reference; not doing this is undefined behavior (for example, -/// `transmute`-ing from `&T` to `&mut T` is invalid). +/// [`transmute`]-ing from `&T` to `&mut T` is invalid). /// /// This trait is automatically derived when the compiler determines it's appropriate. +/// +/// [`u8`]: ../../std/primitive.u8.html +/// [`f64`]: ../../std/primitive.f64.html +/// [`Vec`]: ../../std/vec/struct.Vec.html +/// [`Box`]: ../../std/boxed/struct.Box.html +/// [`Cell`]: ../../std/cell/struct.Cell.html +/// [`RefCell`]: ../../std/cell/struct.RefCell.html +/// [`std::cell`]: ../../std/cell/index.html +/// [`.set`]: ../../std/cell/struct.Cell.html#method.set +/// [`Rc`]: ../../std/rc/struct.Rc.html +/// [`sync`]: ../../std/sync/index.html +/// [`Mutex`]: ../../std/sync/struct.Mutex.html +/// [`RwLock`]: ../../std/sync/struct.RwLock.html +/// [`std::cell::UnsafeCell`]: ../../std/cell/struct.UnsafeCell.html +/// [`transmute`]: ../../std/mem/fn.transmute.html #[stable(feature = "rust1", since = "1.0.0")] #[lang = "sync"] #[rustc_on_unimplemented = "`{Self}` cannot be shared between threads safely"] From 57a603795160250de09dd4e3634c099a2d76fb58 Mon Sep 17 00:00:00 2001 From: ggomez Date: Fri, 9 Sep 2016 16:07:56 +0200 Subject: [PATCH 289/443] Improve Option doc --- src/libcore/option.rs | 78 +++++++++++++++++++++++++++---------------- 1 file changed, 50 insertions(+), 28 deletions(-) diff --git a/src/libcore/option.rs b/src/libcore/option.rs index cf52849e0197..dacb396ee402 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -10,9 +10,9 @@ //! Optional values. //! -//! Type `Option` represents an optional value: every `Option` -//! is either `Some` and contains a value, or `None`, and -//! does not. `Option` types are very common in Rust code, as +//! Type [`Option`] represents an optional value: every [`Option`] +//! is either [`Some`] and contains a value, or [`None`], and +//! does not. [`Option`] types are very common in Rust code, as //! they have a number of uses: //! //! * Initial values @@ -26,8 +26,8 @@ //! * Nullable pointers //! * Swapping things out of difficult situations //! -//! Options are commonly paired with pattern matching to query the presence -//! of a value and take action, always accounting for the `None` case. +//! [`Option`]s are commonly paired with pattern matching to query the presence +//! of a value and take action, always accounting for the [`None`] case. //! //! ``` //! fn divide(numerator: f64, denominator: f64) -> Option { @@ -57,13 +57,13 @@ //! //! Rust's pointer types must always point to a valid location; there are //! no "null" pointers. Instead, Rust has *optional* pointers, like -//! the optional owned box, `Option>`. +//! the optional owned box, [`Option`]`<`[`Box`]`>`. //! -//! The following example uses `Option` to create an optional box of -//! `i32`. Notice that in order to use the inner `i32` value first the +//! The following example uses [`Option`] to create an optional box of +//! [`i32`]. Notice that in order to use the inner [`i32`] value first the //! `check_optional` function needs to use pattern matching to -//! determine whether the box has a value (i.e. it is `Some(...)`) or -//! not (`None`). +//! determine whether the box has a value (i.e. it is [`Some(...)`][`Some`]) or +//! not ([`None`]). //! //! ``` //! let optional: Option> = None; @@ -80,14 +80,14 @@ //! } //! ``` //! -//! This usage of `Option` to create safe nullable pointers is so +//! This usage of [`Option`] to create safe nullable pointers is so //! common that Rust does special optimizations to make the -//! representation of `Option>` a single pointer. Optional pointers +//! representation of [`Option`]`<`[`Box`]`>` a single pointer. Optional pointers //! in Rust are stored as efficiently as any other pointer type. //! //! # Examples //! -//! Basic pattern matching on `Option`: +//! Basic pattern matching on [`Option`]: //! //! ``` //! let msg = Some("howdy"); @@ -101,7 +101,7 @@ //! let unwrapped_msg = msg.unwrap_or("default message"); //! ``` //! -//! Initialize a result to `None` before a loop: +//! Initialize a result to [`None`] before a loop: //! //! ``` //! enum Kingdom { Plant(u32, &'static str), Animal(u32, &'static str) } @@ -136,6 +136,12 @@ //! None => println!("there are no animals :("), //! } //! ``` +//! +//! [`Option`]: enum.Option.html +//! [`Some`]: enum.Option.html#variant.Some +//! [`None`]: enum.Option.html#variant.None +//! [`Box`]: ../../std/boxed/struct.Box.html +//! [`i32`]: ../../std/primitive.i32.html #![stable(feature = "rust1", since = "1.0.0")] @@ -156,7 +162,7 @@ pub enum Option { None, /// Some value `T` #[stable(feature = "rust1", since = "1.0.0")] - Some(#[stable(feature = "rust1", since = "1.0.0")] T) + Some(#[stable(feature = "rust1", since = "1.0.0")] T), } ///////////////////////////////////////////////////////////////////////////// @@ -168,7 +174,7 @@ impl Option { // Querying the contained values ///////////////////////////////////////////////////////////////////////// - /// Returns `true` if the option is a `Some` value + /// Returns `true` if the option is a `Some` value. /// /// # Examples /// @@ -188,7 +194,7 @@ impl Option { } } - /// Returns `true` if the option is a `None` value + /// Returns `true` if the option is a `None` value. /// /// # Examples /// @@ -209,15 +215,17 @@ impl Option { // Adapter for working with references ///////////////////////////////////////////////////////////////////////// - /// Converts from `Option` to `Option<&T>` + /// Converts from `Option` to `Option<&T>`. /// /// # Examples /// /// Convert an `Option` into an `Option`, preserving the original. - /// The `map` method takes the `self` argument by value, consuming the original, + /// The [`map`] method takes the `self` argument by value, consuming the original, /// so this technique uses `as_ref` to first take an `Option` to a reference /// to the value inside the original. /// + /// [`map`]: enum.Option.html#method.map + /// /// ``` /// let num_as_str: Option = Some("10".to_string()); /// // First, cast `Option` to `Option<&String>` with `as_ref`, @@ -234,7 +242,7 @@ impl Option { } } - /// Converts from `Option` to `Option<&mut T>` + /// Converts from `Option` to `Option<&mut T>`. /// /// # Examples /// @@ -357,7 +365,7 @@ impl Option { // Transforming contained values ///////////////////////////////////////////////////////////////////////// - /// Maps an `Option` to `Option` by applying a function to a contained value + /// Maps an `Option` to `Option` by applying a function to a contained value. /// /// # Examples /// @@ -423,8 +431,12 @@ impl Option { } } - /// Transforms the `Option` into a `Result`, mapping `Some(v)` to - /// `Ok(v)` and `None` to `Err(err)`. + /// Transforms the `Option` into a [`Result`], mapping `Some(v)` to + /// [`Ok(v)`] and `None` to [`Err(err)`][Err]. + /// + /// [`Result`]: ../../std/result/enum.Result.html + /// [`Ok(v)`]: ../../std/result/enum.Result.html#variant.Ok + /// [Err]: ../../std/result/enum.Result.html#variant.Err /// /// # Examples /// @@ -444,8 +456,12 @@ impl Option { } } - /// Transforms the `Option` into a `Result`, mapping `Some(v)` to - /// `Ok(v)` and `None` to `Err(err())`. + /// Transforms the `Option` into a [`Result`], mapping `Some(v)` to + /// [`Ok(v)`] and `None` to [`Err(err())`][Err]. + /// + /// [`Result`]: ../../std/result/enum.Result.html + /// [`Ok(v)`]: ../../std/result/enum.Result.html#variant.Ok + /// [Err]: ../../std/result/enum.Result.html#variant.Err /// /// # Examples /// @@ -789,7 +805,9 @@ impl DoubleEndedIterator for Item { impl ExactSizeIterator for Item {} impl FusedIterator for Item {} -/// An iterator over a reference of the contained item in an Option. +/// An iterator over a reference of the contained item in an [`Option`]. +/// +/// [`Option`]: enum.Option.html #[stable(feature = "rust1", since = "1.0.0")] #[derive(Debug)] pub struct Iter<'a, A: 'a> { inner: Item<&'a A> } @@ -823,7 +841,9 @@ impl<'a, A> Clone for Iter<'a, A> { } } -/// An iterator over a mutable reference of the contained item in an Option. +/// An iterator over a mutable reference of the contained item in an [`Option`]. +/// +/// [`Option`]: enum.Option.html #[stable(feature = "rust1", since = "1.0.0")] #[derive(Debug)] pub struct IterMut<'a, A: 'a> { inner: Item<&'a mut A> } @@ -850,7 +870,9 @@ impl<'a, A> ExactSizeIterator for IterMut<'a, A> {} #[unstable(feature = "fused", issue = "35602")] impl<'a, A> FusedIterator for IterMut<'a, A> {} -/// An iterator over the item contained inside an Option. +/// An iterator over the item contained inside an [`Option`]. +/// +/// [`Option`]: enum.Option.html #[derive(Clone, Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub struct IntoIter { inner: Item } From e3153cfd8896d97be89e3b1b26e44a3ebf8a6374 Mon Sep 17 00:00:00 2001 From: ggomez Date: Fri, 9 Sep 2016 16:08:04 +0200 Subject: [PATCH 290/443] Improve Result doc --- src/libcore/result.rs | 95 +++++++++++++++++++++++++++---------------- 1 file changed, 59 insertions(+), 36 deletions(-) diff --git a/src/libcore/result.rs b/src/libcore/result.rs index 94b6d5fa0031..96845259299b 100644 --- a/src/libcore/result.rs +++ b/src/libcore/result.rs @@ -10,9 +10,9 @@ //! Error handling with the `Result` type. //! -//! `Result` is the type used for returning and propagating -//! errors. It is an enum with the variants, `Ok(T)`, representing -//! success and containing a value, and `Err(E)`, representing error +//! [`Result`][`Result`] is the type used for returning and propagating +//! errors. It is an enum with the variants, [`Ok(T)`], representing +//! success and containing a value, and [`Err(E)`], representing error //! and containing an error value. //! //! ``` @@ -23,11 +23,11 @@ //! } //! ``` //! -//! Functions return `Result` whenever errors are expected and -//! recoverable. In the `std` crate `Result` is most prominently used +//! Functions return [`Result`] whenever errors are expected and +//! recoverable. In the `std` crate, [`Result`] is most prominently used //! for [I/O](../../std/io/index.html). //! -//! A simple function returning `Result` might be +//! A simple function returning [`Result`] might be //! defined and used like so: //! //! ``` @@ -50,8 +50,8 @@ //! } //! ``` //! -//! Pattern matching on `Result`s is clear and straightforward for -//! simple cases, but `Result` comes with some convenience methods +//! Pattern matching on [`Result`]s is clear and straightforward for +//! simple cases, but [`Result`] comes with some convenience methods //! that make working with it more succinct. //! //! ``` @@ -80,14 +80,14 @@ //! //! A common problem with using return values to indicate errors is //! that it is easy to ignore the return value, thus failing to handle -//! the error. Result is annotated with the #[must_use] attribute, +//! the error. [`Result`] is annotated with the `#[must_use]` attribute, //! which will cause the compiler to issue a warning when a Result -//! value is ignored. This makes `Result` especially useful with +//! value is ignored. This makes [`Result`] especially useful with //! functions that may encounter errors but don't otherwise return a //! useful value. //! -//! Consider the `write_all` method defined for I/O types -//! by the [`Write`](../../std/io/trait.Write.html) trait: +//! Consider the [`write_all`] method defined for I/O types +//! by the [`Write`] trait: //! //! ``` //! use std::io; @@ -97,8 +97,8 @@ //! } //! ``` //! -//! *Note: The actual definition of `Write` uses `io::Result`, which -//! is just a synonym for `Result`.* +//! *Note: The actual definition of [`Write`] uses [`io::Result`], which +//! is just a synonym for [`Result`]``.* //! //! This method doesn't produce a value, but the write may //! fail. It's crucial to handle the error case, and *not* write @@ -119,7 +119,7 @@ //! warning (by default, controlled by the `unused_must_use` lint). //! //! You might instead, if you don't want to handle the error, simply -//! assert success with `expect`. This will panic if the +//! assert success with [`expect`]. This will panic if the //! write fails, providing a marginally useful message indicating why: //! //! ```{.no_run} @@ -139,7 +139,7 @@ //! assert!(file.write_all(b"important message").is_ok()); //! ``` //! -//! Or propagate the error up the call stack with `try!`: +//! Or propagate the error up the call stack with [`try!`]: //! //! ``` //! # use std::fs::File; @@ -156,7 +156,7 @@ //! # The `try!` macro //! //! When writing code that calls many functions that return the -//! `Result` type, the error handling can be tedious. The `try!` +//! [`Result`] type, the error handling can be tedious. The [`try!`] //! macro hides some of the boilerplate of propagating errors up the //! call stack. //! @@ -219,9 +219,9 @@ //! //! *It's much nicer!* //! -//! Wrapping an expression in `try!` will result in the unwrapped -//! success (`Ok`) value, unless the result is `Err`, in which case -//! `Err` is returned early from the enclosing function. Its simple definition +//! Wrapping an expression in [`try!`] will result in the unwrapped +//! success ([`Ok`]) value, unless the result is [`Err`], in which case +//! [`Err`] is returned early from the enclosing function. Its simple definition //! makes it clear: //! //! ``` @@ -230,9 +230,21 @@ //! } //! ``` //! -//! `try!` is imported by the prelude and is available everywhere, but it can only -//! be used in functions that return `Result` because of the early return of -//! `Err` that it provides. +//! [`try!`] is imported by the prelude and is available everywhere, but it can only +//! be used in functions that return [`Result`] because of the early return of +//! [`Err`] that it provides. +//! +//! [`expect`]: enum.Result.html#method.expect +//! [`Write`]: ../../std/io/trait.Write.html +//! [`write_all`]: ../../std/io/trait.Write.html#method.write_all +//! [`io::Result`]: ../../std/io/type.Result.html +//! [`try!`]: ../../std/macro.try.html +//! [`Result`]: enum.Result.html +//! [`Ok(T)`]: enum.Result.html#variant.Ok +//! [`Err(E)`]: enum.Result.html#variant.Err +//! [`io::Error`]: ../../std/io/struct.Error.html +//! [`Ok`]: enum.Result.html#variant.Ok +//! [`Err`]: enum.Result.html#variant.Err #![stable(feature = "rust1", since = "1.0.0")] @@ -264,7 +276,7 @@ impl Result { // Querying the contained values ///////////////////////////////////////////////////////////////////////// - /// Returns true if the result is `Ok` + /// Returns true if the result is `Ok`. /// /// # Examples /// @@ -286,7 +298,7 @@ impl Result { } } - /// Returns true if the result is `Err` + /// Returns true if the result is `Err`. /// /// # Examples /// @@ -309,11 +321,13 @@ impl Result { // Adapter for each variant ///////////////////////////////////////////////////////////////////////// - /// Converts from `Result` to `Option` + /// Converts from `Result` to [`Option`]. /// - /// Converts `self` into an `Option`, consuming `self`, + /// Converts `self` into an [`Option`], consuming `self`, /// and discarding the error, if any. /// + /// [`Option`]: ../../std/option/enum.Option.html + /// /// # Examples /// /// Basic usage: @@ -334,11 +348,13 @@ impl Result { } } - /// Converts from `Result` to `Option` + /// Converts from `Result` to [`Option`]. /// - /// Converts `self` into an `Option`, consuming `self`, + /// Converts `self` into an [`Option`], consuming `self`, /// and discarding the success value, if any. /// + /// [`Option`]: ../../std/option/enum.Option.html + /// /// # Examples /// /// Basic usage: @@ -363,7 +379,7 @@ impl Result { // Adapter for working with references ///////////////////////////////////////////////////////////////////////// - /// Converts from `Result` to `Result<&T, &E>` + /// Converts from `Result` to `Result<&T, &E>`. /// /// Produces a new `Result`, containing a reference /// into the original, leaving the original in place. @@ -388,7 +404,7 @@ impl Result { } } - /// Converts from `Result` to `Result<&mut T, &mut E>` + /// Converts from `Result` to `Result<&mut T, &mut E>`. /// /// # Examples /// @@ -563,7 +579,7 @@ impl Result { /// Calls `op` if the result is `Ok`, otherwise returns the `Err` value of `self`. /// - /// This function can be used for control flow based on result values. + /// This function can be used for control flow based on `Result` values. /// /// # Examples /// @@ -646,7 +662,7 @@ impl Result { } /// Unwraps a result, yielding the content of an `Ok`. - /// Else it returns `optb`. + /// Else, it returns `optb`. /// /// # Examples /// @@ -837,7 +853,10 @@ impl<'a, T, E> IntoIterator for &'a mut Result { // The Result Iterators ///////////////////////////////////////////////////////////////////////////// -/// An iterator over a reference to the `Ok` variant of a `Result`. +/// An iterator over a reference to the [`Ok`] variant of a [`Result`]. +/// +/// [`Ok`]: enum.Result.html#variant.Ok +/// [`Result`]: enum.Result.html #[derive(Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub struct Iter<'a, T: 'a> { inner: Option<&'a T> } @@ -872,7 +891,10 @@ impl<'a, T> Clone for Iter<'a, T> { fn clone(&self) -> Iter<'a, T> { Iter { inner: self.inner } } } -/// An iterator over a mutable reference to the `Ok` variant of a `Result`. +/// An iterator over a mutable reference to the [`Ok`] variant of a [`Result`]. +/// +/// [`Ok`]: enum.Result.html#variant.Ok +/// [`Result`]: enum.Result.html #[derive(Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub struct IterMut<'a, T: 'a> { inner: Option<&'a mut T> } @@ -902,10 +924,11 @@ impl<'a, T> ExactSizeIterator for IterMut<'a, T> {} #[unstable(feature = "fused", issue = "35602")] impl<'a, T> FusedIterator for IterMut<'a, T> {} -/// An iterator over the value in a `Ok` variant of a `Result`. This struct is +/// An iterator over the value in a [`Ok`] variant of a [`Result`]. This struct is /// created by the [`into_iter`] method on [`Result`][`Result`] (provided by /// the [`IntoIterator`] trait). /// +/// [`Ok`]: enum.Result.html#variant.Ok /// [`Result`]: enum.Result.html /// [`into_iter`]: ../iter/trait.IntoIterator.html#tymethod.into_iter /// [`IntoIterator`]: ../iter/trait.IntoIterator.html From 49e77dbf25ed6526fb5d37c32e55797fb04522f0 Mon Sep 17 00:00:00 2001 From: athulappadan Date: Sun, 11 Sep 2016 17:00:09 +0530 Subject: [PATCH 291/443] Documentation of what does for each type --- src/liballoc/arc.rs | 2 ++ src/liballoc/boxed.rs | 1 + src/liballoc/rc.rs | 1 + src/libcollections/binary_heap.rs | 1 + src/libcollections/borrow.rs | 1 + src/libcollections/btree/map.rs | 1 + src/libcollections/btree/set.rs | 1 + src/libcollections/linked_list.rs | 1 + src/libcollections/string.rs | 1 + src/libcollections/vec.rs | 1 + src/libcollections/vec_deque.rs | 1 + src/libcore/cell.rs | 3 +++ src/libcore/hash/sip.rs | 1 + src/libcore/option.rs | 1 + src/libcore/slice.rs | 2 ++ src/libcore/str/mod.rs | 1 + src/libcore/sync/atomic.rs | 2 ++ src/libcoretest/hash/mod.rs | 2 ++ src/librand/reseeding.rs | 2 ++ src/librustc/session/config.rs | 1 + src/librustc/ty/layout.rs | 1 + src/librustc_data_structures/fnv.rs | 1 + src/librustc_resolve/resolve_imports.rs | 1 + src/libstd/collections/hash/map.rs | 2 ++ src/libstd/collections/hash/set.rs | 1 + src/libstd/ffi/c_str.rs | 1 + src/libstd/ffi/os_str.rs | 2 ++ src/libstd/sync/condvar.rs | 1 + src/libstd/sync/mutex.rs | 1 + src/libstd/sync/rwlock.rs | 1 + src/libsyntax/ast.rs | 1 + src/libsyntax/ptr.rs | 1 + 32 files changed, 41 insertions(+) diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index b54b71cabd1e..a2923091fb55 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -718,6 +718,7 @@ impl Clone for Weak { #[stable(feature = "downgraded_weak", since = "1.10.0")] impl Default for Weak { + /// Creates a new `Weak`. fn default() -> Weak { Weak::new() } @@ -923,6 +924,7 @@ impl fmt::Pointer for Arc { #[stable(feature = "rust1", since = "1.0.0")] impl Default for Arc { + /// Creates a new `Arc`, with the `Default` value for T. fn default() -> Arc { Arc::new(Default::default()) } diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 70c429cc3600..bc9b6e805efc 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -290,6 +290,7 @@ impl Box { #[stable(feature = "rust1", since = "1.0.0")] impl Default for Box { + /// Creates a `Box`, with the `Default` value for T. fn default() -> Box { box Default::default() } diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index c24c7ca47ad0..dadddbc2cb3e 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -870,6 +870,7 @@ impl fmt::Debug for Weak { #[stable(feature = "downgraded_weak", since = "1.10.0")] impl Default for Weak { + /// Creates a new `Weak`. fn default() -> Weak { Weak::new() } diff --git a/src/libcollections/binary_heap.rs b/src/libcollections/binary_heap.rs index 0b923468c741..1fe921543bd4 100644 --- a/src/libcollections/binary_heap.rs +++ b/src/libcollections/binary_heap.rs @@ -263,6 +263,7 @@ impl Clone for BinaryHeap { #[stable(feature = "rust1", since = "1.0.0")] impl Default for BinaryHeap { + /// Creates an empty `BinaryHeap`. #[inline] fn default() -> BinaryHeap { BinaryHeap::new() diff --git a/src/libcollections/borrow.rs b/src/libcollections/borrow.rs index 3ad1d0829858..ef136f3356aa 100644 --- a/src/libcollections/borrow.rs +++ b/src/libcollections/borrow.rs @@ -249,6 +249,7 @@ impl<'a, B: ?Sized> Default for Cow<'a, B> where B: ToOwned, ::Owned: Default { + /// Creates a `Cow<'a, B>` pointer. fn default() -> Cow<'a, B> { Owned(::Owned::default()) } diff --git a/src/libcollections/btree/map.rs b/src/libcollections/btree/map.rs index 624083a8eaf3..36cb5a1fd9f6 100644 --- a/src/libcollections/btree/map.rs +++ b/src/libcollections/btree/map.rs @@ -1667,6 +1667,7 @@ impl Hash for BTreeMap { } impl Default for BTreeMap { + /// Creates an empty `BTreeMap`. fn default() -> BTreeMap { BTreeMap::new() } diff --git a/src/libcollections/btree/set.rs b/src/libcollections/btree/set.rs index 5d7b00f57c83..24da81c3e937 100644 --- a/src/libcollections/btree/set.rs +++ b/src/libcollections/btree/set.rs @@ -674,6 +674,7 @@ impl<'a, T: 'a + Ord + Copy> Extend<&'a T> for BTreeSet { #[stable(feature = "rust1", since = "1.0.0")] impl Default for BTreeSet { + /// Creates a new `BTreeSet`. fn default() -> BTreeSet { BTreeSet::new() } diff --git a/src/libcollections/linked_list.rs b/src/libcollections/linked_list.rs index 769c5162a456..690c4f4af358 100644 --- a/src/libcollections/linked_list.rs +++ b/src/libcollections/linked_list.rs @@ -164,6 +164,7 @@ impl LinkedList { #[stable(feature = "rust1", since = "1.0.0")] impl Default for LinkedList { + /// Creates an empty `LinkedList`. #[inline] fn default() -> Self { Self::new() diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index 3a304c629293..773e94f1b414 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -1567,6 +1567,7 @@ impl_eq! { Cow<'a, str>, String } #[stable(feature = "rust1", since = "1.0.0")] impl Default for String { + /// Creates an empty `String`. #[inline] fn default() -> String { String::new() diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index 876314613f52..cb1d0de6e5eb 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -1610,6 +1610,7 @@ impl Drop for Vec { #[stable(feature = "rust1", since = "1.0.0")] impl Default for Vec { + /// Creates an empty `Vec`. fn default() -> Vec { Vec::new() } diff --git a/src/libcollections/vec_deque.rs b/src/libcollections/vec_deque.rs index 96624f121b2a..efee4914a112 100644 --- a/src/libcollections/vec_deque.rs +++ b/src/libcollections/vec_deque.rs @@ -84,6 +84,7 @@ impl Drop for VecDeque { #[stable(feature = "rust1", since = "1.0.0")] impl Default for VecDeque { + /// Creates a `VecDeque` with a constant initial capacity. #[inline] fn default() -> VecDeque { VecDeque::new() diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index f0710a1d9357..51221f1b9b9e 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -317,6 +317,7 @@ impl Clone for Cell { #[stable(feature = "rust1", since = "1.0.0")] impl Default for Cell { + /// Creates a `Cell`, with the `Default` value for T. #[inline] fn default() -> Cell { Cell::new(Default::default()) @@ -758,6 +759,7 @@ impl Clone for RefCell { #[stable(feature = "rust1", since = "1.0.0")] impl Default for RefCell { + /// Creates a `RefCell`, with the `Default` value for T. #[inline] fn default() -> RefCell { RefCell::new(Default::default()) @@ -1139,6 +1141,7 @@ impl UnsafeCell { #[stable(feature = "unsafe_cell_default", since = "1.9.0")] impl Default for UnsafeCell { + /// Creates an `UnsafeCell`, with the `Default` value for T. fn default() -> UnsafeCell { UnsafeCell::new(Default::default()) } diff --git a/src/libcore/hash/sip.rs b/src/libcore/hash/sip.rs index bd6cae92b050..dc53683d6337 100644 --- a/src/libcore/hash/sip.rs +++ b/src/libcore/hash/sip.rs @@ -333,6 +333,7 @@ impl Clone for Hasher { } impl Default for Hasher { + /// Creates a `Hasher` with the two initial keys set to 0. #[inline] fn default() -> Hasher { Hasher::new_with_keys(0, 0) diff --git a/src/libcore/option.rs b/src/libcore/option.rs index cf52849e0197..4c449c6562e2 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -698,6 +698,7 @@ fn expect_failed(msg: &str) -> ! { #[stable(feature = "rust1", since = "1.0.0")] impl Default for Option { + /// Creates an instance of None. #[inline] fn default() -> Option { None } } diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs index b22bdb43414f..53d2b3ded673 100644 --- a/src/libcore/slice.rs +++ b/src/libcore/slice.rs @@ -755,11 +755,13 @@ impl ops::IndexMut> for [T] { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> Default for &'a [T] { + /// Creates an empty Slice. fn default() -> &'a [T] { &[] } } #[stable(feature = "mut_slice_default", since = "1.5.0")] impl<'a, T> Default for &'a mut [T] { + /// Creates a mutable empty Slice. fn default() -> &'a mut [T] { &mut [] } } diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 18e43c02c648..1f1ae6f12ab4 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -1987,5 +1987,6 @@ impl AsRef<[u8]> for str { #[stable(feature = "rust1", since = "1.0.0")] impl<'a> Default for &'a str { + /// Creates an empty str fn default() -> &'a str { "" } } diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs index 75ddd2021a8f..a5efda702dfa 100644 --- a/src/libcore/sync/atomic.rs +++ b/src/libcore/sync/atomic.rs @@ -95,6 +95,7 @@ pub struct AtomicBool { #[cfg(target_has_atomic = "8")] #[stable(feature = "rust1", since = "1.0.0")] impl Default for AtomicBool { + /// Creates an `AtomicBool` initialised as false. fn default() -> Self { Self::new(false) } @@ -117,6 +118,7 @@ pub struct AtomicPtr { #[cfg(target_has_atomic = "ptr")] #[stable(feature = "rust1", since = "1.0.0")] impl Default for AtomicPtr { + /// Creates an `AtomicPtr` with an initial mutable null pointer. fn default() -> AtomicPtr { AtomicPtr::new(::ptr::null_mut()) } diff --git a/src/libcoretest/hash/mod.rs b/src/libcoretest/hash/mod.rs index 4ea42644ecdf..dec8b57518f2 100644 --- a/src/libcoretest/hash/mod.rs +++ b/src/libcoretest/hash/mod.rs @@ -18,6 +18,7 @@ struct MyHasher { } impl Default for MyHasher { + /// Constructs a `MyHasher` with initial value zero. fn default() -> MyHasher { MyHasher { hash: 0 } } @@ -90,6 +91,7 @@ impl Hasher for CustomHasher { } impl Default for CustomHasher { + /// Constructs a `CustomHasher` with initial value zero. fn default() -> CustomHasher { CustomHasher { output: 0 } } diff --git a/src/librand/reseeding.rs b/src/librand/reseeding.rs index c7d560eb1f8e..48395c12fafe 100644 --- a/src/librand/reseeding.rs +++ b/src/librand/reseeding.rs @@ -113,6 +113,7 @@ impl Reseeder for ReseedWithDefault { } #[stable(feature = "rust1", since = "1.0.0")] impl Default for ReseedWithDefault { + /// Creates an instance of `ReseedWithDefault`. fn default() -> ReseedWithDefault { ReseedWithDefault } @@ -137,6 +138,7 @@ mod tests { } } impl Default for Counter { + /// Constructs a `Counter` with initial value zero. fn default() -> Counter { Counter { i: 0 } } diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 2009e18f6ee2..5708f961adad 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -84,6 +84,7 @@ pub enum ErrorOutputType { } impl Default for ErrorOutputType { + /// Creates an `HumanReadble`, initialised with `ColorConfig` enum type `Auto`. fn default() -> ErrorOutputType { ErrorOutputType::HumanReadable(ColorConfig::Auto) } diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index e3f3da916a0a..6fec698cfac9 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -45,6 +45,7 @@ pub struct TargetDataLayout { } impl Default for TargetDataLayout { + /// Creates an instance of `TargetDataLayout`. fn default() -> TargetDataLayout { TargetDataLayout { endian: Endian::Big, diff --git a/src/librustc_data_structures/fnv.rs b/src/librustc_data_structures/fnv.rs index 47f623266f3b..ae90c2fac832 100644 --- a/src/librustc_data_structures/fnv.rs +++ b/src/librustc_data_structures/fnv.rs @@ -35,6 +35,7 @@ pub fn FnvHashSet() -> FnvHashSet { pub struct FnvHasher(u64); impl Default for FnvHasher { + /// Creates a `FnvHasher`, with a 64-bit hex initial value. #[inline] fn default() -> FnvHasher { FnvHasher(0xcbf29ce484222325) diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 74f88433b358..29add1f9b9d4 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -109,6 +109,7 @@ enum SingleImports<'a> { } impl<'a> Default for SingleImports<'a> { + /// Creates a `SingleImports<'a>` of None type. fn default() -> Self { SingleImports::None } diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 4eb2c8f06441..48c54c16ed85 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -1218,6 +1218,7 @@ impl Default for HashMap where K: Eq + Hash, S: BuildHasher + Default, { + /// Creates a `HashMap`, with initial `Default` hasher. fn default() -> HashMap { HashMap::with_hasher(Default::default()) } @@ -2026,6 +2027,7 @@ impl Hasher for DefaultHasher { #[stable(feature = "rust1", since = "1.0.0")] impl Default for RandomState { + /// Constructs a new `RandomState`. #[inline] fn default() -> RandomState { RandomState::new() diff --git a/src/libstd/collections/hash/set.rs b/src/libstd/collections/hash/set.rs index ca5137e95736..b5652bcabf16 100644 --- a/src/libstd/collections/hash/set.rs +++ b/src/libstd/collections/hash/set.rs @@ -665,6 +665,7 @@ impl Default for HashSet where T: Eq + Hash, S: BuildHasher + Default, { + /// Creates a `HashSet` with initial `Default` hasher. fn default() -> HashSet { HashSet::with_hasher(Default::default()) } diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs index 38222c014f61..044112ea1365 100644 --- a/src/libstd/ffi/c_str.rs +++ b/src/libstd/ffi/c_str.rs @@ -339,6 +339,7 @@ impl<'a> Default for &'a CStr { #[stable(feature = "cstr_default", since = "1.10.0")] impl Default for CString { + /// Creates a new `CString`, by calling the `Default` of `CStr`, and then owns it. fn default() -> CString { let a: &CStr = Default::default(); a.to_owned() diff --git a/src/libstd/ffi/os_str.rs b/src/libstd/ffi/os_str.rs index 36cf4ef758d8..d93d3c736226 100644 --- a/src/libstd/ffi/os_str.rs +++ b/src/libstd/ffi/os_str.rs @@ -170,6 +170,7 @@ impl ops::Deref for OsString { #[stable(feature = "osstring_default", since = "1.9.0")] impl Default for OsString { + /// Constructs an empty `OsString`. #[inline] fn default() -> OsString { OsString::new() @@ -342,6 +343,7 @@ impl OsStr { #[stable(feature = "osstring_default", since = "1.9.0")] impl<'a> Default for &'a OsStr { + /// Creates an empty `OsStr`. #[inline] fn default() -> &'a OsStr { OsStr::new("") diff --git a/src/libstd/sync/condvar.rs b/src/libstd/sync/condvar.rs index 4c946e613ea9..3db8b05b954c 100644 --- a/src/libstd/sync/condvar.rs +++ b/src/libstd/sync/condvar.rs @@ -241,6 +241,7 @@ impl Condvar { #[stable(feature = "condvar_default", since = "1.9.0")] impl Default for Condvar { + /// Creates a `Condvar` which is ready to be waited on and notified. fn default() -> Condvar { Condvar::new() } diff --git a/src/libstd/sync/mutex.rs b/src/libstd/sync/mutex.rs index c8ae88c23310..098a3e44258c 100644 --- a/src/libstd/sync/mutex.rs +++ b/src/libstd/sync/mutex.rs @@ -287,6 +287,7 @@ impl Drop for Mutex { #[stable(feature = "mutex_default", since = "1.9.0")] impl Default for Mutex { + /// Creates a `Mutex`, with the `Default` value for T. fn default() -> Mutex { Mutex::new(Default::default()) } diff --git a/src/libstd/sync/rwlock.rs b/src/libstd/sync/rwlock.rs index 4801bcffd081..7f053c6704b5 100644 --- a/src/libstd/sync/rwlock.rs +++ b/src/libstd/sync/rwlock.rs @@ -311,6 +311,7 @@ impl fmt::Debug for RwLock { #[stable(feature = "rw_lock_default", since = "1.9.0")] impl Default for RwLock { + /// Creates a new `RwLock`, with the `Default` value for T. fn default() -> RwLock { RwLock::new(Default::default()) } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 105f911dd575..40c8ba93bd5d 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -362,6 +362,7 @@ impl Generics { } impl Default for Generics { + /// Creates an instance of `Generics`. fn default() -> Generics { Generics { lifetimes: Vec::new(), diff --git a/src/libsyntax/ptr.rs b/src/libsyntax/ptr.rs index c3f8a977a659..a65c54ac1e26 100644 --- a/src/libsyntax/ptr.rs +++ b/src/libsyntax/ptr.rs @@ -154,6 +154,7 @@ impl P<[T]> { } impl Default for P<[T]> { + /// Creates a new `P`, with the `Default` value for T. fn default() -> P<[T]> { P::new() } From c8b656bea5e90f1e174bee7e65cbd362914264b3 Mon Sep 17 00:00:00 2001 From: Richard Janis Goldschmidt Date: Sun, 11 Sep 2016 16:48:04 +0200 Subject: [PATCH 292/443] Remove unnecessary `cmp::min` from BufWriter::write The first branch of the if statement already checks if `buf.len() >= self.buf.capacity()`, which makes the `cmp::min(buf.len(), self.buf.capacity())` redundant: the result will always be `buf.len()`. Therefore, we can pass the `buf` slice directly into `Write::write`. --- src/libstd/io/buffered.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs index a26a932ad2de..dbb45d54f38d 100644 --- a/src/libstd/io/buffered.rs +++ b/src/libstd/io/buffered.rs @@ -468,8 +468,7 @@ impl Write for BufWriter { self.panicked = false; r } else { - let amt = cmp::min(buf.len(), self.buf.capacity()); - Write::write(&mut self.buf, &buf[..amt]) + Write::write(&mut self.buf, buf) } } fn flush(&mut self) -> io::Result<()> { From 41881e85bd832127f2a6eee5821eaae353dea281 Mon Sep 17 00:00:00 2001 From: athulappadan Date: Sun, 11 Sep 2016 22:58:01 +0530 Subject: [PATCH 293/443] Documentation for default types modified --- src/liballoc/arc.rs | 2 +- src/libcollections/borrow.rs | 2 +- src/libcollections/btree/set.rs | 2 +- src/libcollections/vec_deque.rs | 2 +- src/libcore/option.rs | 2 +- src/libcore/slice.rs | 4 ++-- src/libcore/sync/atomic.rs | 2 +- src/libcoretest/hash/mod.rs | 2 -- src/librustc/session/config.rs | 1 - src/libstd/collections/hash/map.rs | 2 +- src/libstd/collections/hash/set.rs | 2 +- src/libstd/ffi/c_str.rs | 2 +- src/libsyntax/ptr.rs | 2 +- 13 files changed, 12 insertions(+), 15 deletions(-) diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index a2923091fb55..3d579641b965 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -718,7 +718,7 @@ impl Clone for Weak { #[stable(feature = "downgraded_weak", since = "1.10.0")] impl Default for Weak { - /// Creates a new `Weak`. + /// Constructs a new `Weak` without an accompanying instance of T. fn default() -> Weak { Weak::new() } diff --git a/src/libcollections/borrow.rs b/src/libcollections/borrow.rs index ef136f3356aa..700f88dc0f26 100644 --- a/src/libcollections/borrow.rs +++ b/src/libcollections/borrow.rs @@ -249,7 +249,7 @@ impl<'a, B: ?Sized> Default for Cow<'a, B> where B: ToOwned, ::Owned: Default { - /// Creates a `Cow<'a, B>` pointer. + /// Creates an owned Cow<'a, B> with the default value for the contained owned value. fn default() -> Cow<'a, B> { Owned(::Owned::default()) } diff --git a/src/libcollections/btree/set.rs b/src/libcollections/btree/set.rs index 24da81c3e937..49da3aa480c3 100644 --- a/src/libcollections/btree/set.rs +++ b/src/libcollections/btree/set.rs @@ -674,7 +674,7 @@ impl<'a, T: 'a + Ord + Copy> Extend<&'a T> for BTreeSet { #[stable(feature = "rust1", since = "1.0.0")] impl Default for BTreeSet { - /// Creates a new `BTreeSet`. + /// Makes a empty `BTreeSet` with a reasonable choice of B. fn default() -> BTreeSet { BTreeSet::new() } diff --git a/src/libcollections/vec_deque.rs b/src/libcollections/vec_deque.rs index efee4914a112..2e561dabb479 100644 --- a/src/libcollections/vec_deque.rs +++ b/src/libcollections/vec_deque.rs @@ -84,7 +84,7 @@ impl Drop for VecDeque { #[stable(feature = "rust1", since = "1.0.0")] impl Default for VecDeque { - /// Creates a `VecDeque` with a constant initial capacity. + /// Creates an empty `VecDeque`. #[inline] fn default() -> VecDeque { VecDeque::new() diff --git a/src/libcore/option.rs b/src/libcore/option.rs index 4c449c6562e2..7733b90ec01a 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -698,7 +698,7 @@ fn expect_failed(msg: &str) -> ! { #[stable(feature = "rust1", since = "1.0.0")] impl Default for Option { - /// Creates an instance of None. + /// Returns None. #[inline] fn default() -> Option { None } } diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs index 53d2b3ded673..7b147faccd20 100644 --- a/src/libcore/slice.rs +++ b/src/libcore/slice.rs @@ -755,13 +755,13 @@ impl ops::IndexMut> for [T] { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> Default for &'a [T] { - /// Creates an empty Slice. + /// Creates an empty slice. fn default() -> &'a [T] { &[] } } #[stable(feature = "mut_slice_default", since = "1.5.0")] impl<'a, T> Default for &'a mut [T] { - /// Creates a mutable empty Slice. + /// Creates a mutable empty slice. fn default() -> &'a mut [T] { &mut [] } } diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs index a5efda702dfa..f5f37be52de6 100644 --- a/src/libcore/sync/atomic.rs +++ b/src/libcore/sync/atomic.rs @@ -118,7 +118,7 @@ pub struct AtomicPtr { #[cfg(target_has_atomic = "ptr")] #[stable(feature = "rust1", since = "1.0.0")] impl Default for AtomicPtr { - /// Creates an `AtomicPtr` with an initial mutable null pointer. + /// Creates a null `AtomicPtr`. fn default() -> AtomicPtr { AtomicPtr::new(::ptr::null_mut()) } diff --git a/src/libcoretest/hash/mod.rs b/src/libcoretest/hash/mod.rs index dec8b57518f2..4ea42644ecdf 100644 --- a/src/libcoretest/hash/mod.rs +++ b/src/libcoretest/hash/mod.rs @@ -18,7 +18,6 @@ struct MyHasher { } impl Default for MyHasher { - /// Constructs a `MyHasher` with initial value zero. fn default() -> MyHasher { MyHasher { hash: 0 } } @@ -91,7 +90,6 @@ impl Hasher for CustomHasher { } impl Default for CustomHasher { - /// Constructs a `CustomHasher` with initial value zero. fn default() -> CustomHasher { CustomHasher { output: 0 } } diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 5708f961adad..2009e18f6ee2 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -84,7 +84,6 @@ pub enum ErrorOutputType { } impl Default for ErrorOutputType { - /// Creates an `HumanReadble`, initialised with `ColorConfig` enum type `Auto`. fn default() -> ErrorOutputType { ErrorOutputType::HumanReadable(ColorConfig::Auto) } diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 48c54c16ed85..eb1653f18cba 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -1218,7 +1218,7 @@ impl Default for HashMap where K: Eq + Hash, S: BuildHasher + Default, { - /// Creates a `HashMap`, with initial `Default` hasher. + /// Creates an empty `HashMap`, with the `Default` value for the hasher. fn default() -> HashMap { HashMap::with_hasher(Default::default()) } diff --git a/src/libstd/collections/hash/set.rs b/src/libstd/collections/hash/set.rs index b5652bcabf16..ff56747fee6a 100644 --- a/src/libstd/collections/hash/set.rs +++ b/src/libstd/collections/hash/set.rs @@ -665,7 +665,7 @@ impl Default for HashSet where T: Eq + Hash, S: BuildHasher + Default, { - /// Creates a `HashSet` with initial `Default` hasher. + /// Creates an empty `HashSet` with the `Default` value for the hasher. fn default() -> HashSet { HashSet::with_hasher(Default::default()) } diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs index 044112ea1365..0f7dc3889f0b 100644 --- a/src/libstd/ffi/c_str.rs +++ b/src/libstd/ffi/c_str.rs @@ -339,7 +339,7 @@ impl<'a> Default for &'a CStr { #[stable(feature = "cstr_default", since = "1.10.0")] impl Default for CString { - /// Creates a new `CString`, by calling the `Default` of `CStr`, and then owns it. + /// Creates an empty `CString`. fn default() -> CString { let a: &CStr = Default::default(); a.to_owned() diff --git a/src/libsyntax/ptr.rs b/src/libsyntax/ptr.rs index a65c54ac1e26..587501589314 100644 --- a/src/libsyntax/ptr.rs +++ b/src/libsyntax/ptr.rs @@ -154,7 +154,7 @@ impl P<[T]> { } impl Default for P<[T]> { - /// Creates a new `P`, with the `Default` value for T. + /// Creates an empty `P<[T]>`. fn default() -> P<[T]> { P::new() } From 54c680cdb136bb991bdf60c31edcb1304da9005e Mon Sep 17 00:00:00 2001 From: Keegan McAllister Date: Sat, 10 Sep 2016 10:47:05 -0700 Subject: [PATCH 294/443] Tweak array docs Fixes #29331. --- src/libstd/primitive_docs.rs | 84 +++++++++++++++++++++++++++--------- 1 file changed, 64 insertions(+), 20 deletions(-) diff --git a/src/libstd/primitive_docs.rs b/src/libstd/primitive_docs.rs index 2b92da6c684a..fdc84467015f 100644 --- a/src/libstd/primitive_docs.rs +++ b/src/libstd/primitive_docs.rs @@ -249,37 +249,58 @@ mod prim_pointer { } #[doc(primitive = "array")] // /// A fixed-size array, denoted `[T; N]`, for the element type, `T`, and the -/// non-negative compile time constant size, `N`. +/// non-negative compile-time constant size, `N`. /// -/// Arrays values are created either with an explicit expression that lists -/// each element: `[x, y, z]` or a repeat expression: `[x; N]`. The repeat -/// expression requires that the element type is `Copy`. +/// There are two syntactic forms for creating an array: /// -/// The type `[T; N]` is `Copy` if `T: Copy`. +/// * A list with each element, i.e. `[x, y, z]`. +/// * A repeat expression `[x; N]`, which produces an array with `N` copies of `x`. +/// The type of `x` must be [`Copy`][copy]. /// /// Arrays of sizes from 0 to 32 (inclusive) implement the following traits if /// the element type allows it: /// -/// - `Clone` (only if `T: Copy`) -/// - `Debug` -/// - `IntoIterator` (implemented for `&[T; N]` and `&mut [T; N]`) -/// - `PartialEq`, `PartialOrd`, `Ord`, `Eq` -/// - `Hash` -/// - `AsRef`, `AsMut` -/// - `Borrow`, `BorrowMut` -/// - `Default` +/// - [`Clone`][clone] (only if `T: Copy`) +/// - [`Debug`][debug] +/// - [`IntoIterator`][intoiterator] (implemented for `&[T; N]` and `&mut [T; N]`) +/// - [`PartialEq`][partialeq], [`PartialOrd`][partialord], [`Eq`][eq], [`Ord`][ord] +/// - [`Hash`][hash] +/// - [`AsRef`][asref], [`AsMut`][asmut] +/// - [`Borrow`][borrow], [`BorrowMut`][borrowmut] +/// - [`Default`][default] /// -/// This limitation to `N in 0..33` exists because Rust does not yet support -/// generics over the size of an array type. `[Foo; 3]` and `[Bar; 3]` are -/// instances of same generic type `[T; 3]`, but `[Foo; 3]` and `[Foo; 5]` are +/// This limitation on the size `N` exists because Rust does not yet support +/// code that is generic over the size of an array type. `[Foo; 3]` and `[Bar; 3]` +/// are instances of same generic type `[T; 3]`, but `[Foo; 3]` and `[Foo; 5]` are /// entirely different types. As a stopgap, trait implementations are -/// statically generated for `N in 0..33`. +/// statically generated up to size 32. /// -/// Arrays coerce to [slices (`[T]`)][slice], so their methods can be called on -/// arrays. Slices are dynamic and do not coerce to arrays; consequently more -/// methods are defined on `slice` where they support both types. +/// Arrays of *any* size are [`Copy`][copy] if the element type is `Copy`. This +/// works because the `Copy` trait is specially known to the compiler. +/// +/// Arrays coerce to [slices (`[T]`)][slice], so a slice method may be called on +/// an array. Indeed, this provides most of the API for working with arrays. +/// Slices have a dynamic size and do not coerce to arrays. +/// +/// There is no way to move elements out of an array. See [`mem::replace`][replace] +/// for an alternative. /// /// [slice]: primitive.slice.html +/// [copy]: marker/trait.Copy.html +/// [clone]: clone/trait.Clone.html +/// [debug]: fmt/trait.Debug.html +/// [intoiterator]: iter/trait.IntoIterator.html +/// [partialeq]: cmp/trait.PartialEq.html +/// [partialord]: cmp/trait.PartialOrd.html +/// [eq]: cmp/trait.Eq.html +/// [ord]: cmp/trait.Ord.html +/// [hash]: hash/trait.Hash.html +/// [asref]: convert/trait.AsRef.html +/// [asmut]: convert/trait.AsMut.html +/// [borrow]: borrow/trait.Borrow.html +/// [borrowmut]: borrow/trait.BorrowMut.html +/// [default]: default/trait.Default.html +/// [replace]: mem/fn.replace.html /// /// # Examples /// @@ -295,7 +316,30 @@ mod prim_pointer { } /// for x in &array { /// print!("{} ", x); /// } +/// ``` /// +/// An array itself is not iterable: +/// +/// ```ignore +/// let array: [i32; 3] = [0; 3]; +/// +/// for x in array { } +/// // error: the trait bound `[i32; 3]: std::iter::Iterator` is not satisfied +/// ``` +/// +/// The solution is to coerce the array to a slice by calling a slice method: +/// +/// ``` +/// # let array: [i32; 3] = [0; 3]; +/// for x in array.iter() { } +/// ``` +/// +/// If the array has 32 or fewer elements (see above), you can also use the +/// array reference's `IntoIterator` implementation: +/// +/// ``` +/// # let array: [i32; 3] = [0; 3]; +/// for x in &array { } /// ``` /// mod prim_array { } From 6b99e011626a6f73747307907cdadbc8ab9ebffd Mon Sep 17 00:00:00 2001 From: Scott Olson Date: Sun, 11 Sep 2016 16:45:49 -0600 Subject: [PATCH 295/443] Delete stray ` character in error message. --- src/librustc_lint/types.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index a6049acdb10d..e8d9e90456ef 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -569,7 +569,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { ty::TyTuple(_) => { FfiUnsafe("found Rust tuple type in foreign module; \ - consider using a struct instead`") + consider using a struct instead") } ty::TyRawPtr(ref m) | ty::TyRef(_, ref m) => { From f1bd90778997865480fa666fbf2eef1b164a0f72 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Mon, 12 Sep 2016 01:53:43 +0300 Subject: [PATCH 296/443] use `adt::trans_const` when translating constant closures and tuples Fixes #36401 --- src/librustc_trans/mir/constant.rs | 86 ++++++++++++++++++++---------- src/test/run-pass/issue-36401.rs | 25 +++++++++ 2 files changed, 83 insertions(+), 28 deletions(-) create mode 100644 src/test/run-pass/issue-36401.rs diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index 15dc7bb4421c..e9f324c0b08f 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -38,6 +38,7 @@ use value::Value; use syntax::ast; use syntax_pos::{Span, DUMMY_SP}; +use std::fmt; use std::ptr; use super::operand::{OperandRef, OperandValue}; @@ -149,6 +150,12 @@ impl<'tcx> Const<'tcx> { } } +impl<'tcx> fmt::Debug for Const<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Const({:?}: {:?})", Value(self.llval), self.ty) + } +} + #[derive(Copy, Clone)] enum Base { /// A constant value without an unique address. @@ -472,7 +479,8 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { fn const_operand(&self, operand: &mir::Operand<'tcx>, span: Span) -> Result, ConstEvalErr> { - match *operand { + debug!("const_operand({:?} @ {:?})", operand, span); + let result = match *operand { mir::Operand::Consume(ref lvalue) => { Ok(self.const_lvalue(lvalue, span)?.to_const(span)) } @@ -501,13 +509,33 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { } } } - } + }; + debug!("const_operand({:?} @ {:?}) = {:?}", operand, span, + result.as_ref().ok()); + result + } + + fn const_array(&self, array_ty: Ty<'tcx>, fields: &[ValueRef]) + -> Const<'tcx> + { + let elem_ty = array_ty.builtin_index().unwrap_or_else(|| { + bug!("bad array type {:?}", array_ty) + }); + let llunitty = type_of::type_of(self.ccx, elem_ty); + // If the array contains enums, an LLVM array won't work. + let val = if fields.iter().all(|&f| val_ty(f) == llunitty) { + C_array(llunitty, fields) + } else { + C_struct(self.ccx, fields, false) + }; + Const::new(val, array_ty) } fn const_rvalue(&self, rvalue: &mir::Rvalue<'tcx>, dest_ty: Ty<'tcx>, span: Span) -> Result, ConstEvalErr> { let tcx = self.ccx.tcx(); + debug!("const_rvalue({:?}: {:?} @ {:?})", rvalue, dest_ty, span); let val = match *rvalue { mir::Rvalue::Use(ref operand) => self.const_operand(operand, span)?, @@ -515,15 +543,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { let elem = self.const_operand(elem, span)?; let size = count.value.as_u64(tcx.sess.target.uint_type); let fields = vec![elem.llval; size as usize]; - - let llunitty = type_of::type_of(self.ccx, elem.ty); - // If the array contains enums, an LLVM array won't work. - let val = if val_ty(elem.llval) == llunitty { - C_array(llunitty, &fields) - } else { - C_struct(self.ccx, &fields, false) - }; - Const::new(val, dest_ty) + self.const_array(dest_ty, &fields) } mir::Rvalue::Aggregate(ref kind, ref operands) => { @@ -547,22 +567,26 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { self.monomorphize(&substs)); } - let val = if let mir::AggregateKind::Adt(adt_def, index, _, _) = *kind { - let repr = adt::represent_type(self.ccx, dest_ty); - let disr = Disr::from(adt_def.variants[index].disr_val); - adt::trans_const(self.ccx, &repr, disr, &fields) - } else if let ty::TyArray(elem_ty, _) = dest_ty.sty { - let llunitty = type_of::type_of(self.ccx, elem_ty); - // If the array contains enums, an LLVM array won't work. - if fields.iter().all(|&f| val_ty(f) == llunitty) { - C_array(llunitty, &fields) - } else { - C_struct(self.ccx, &fields, false) + match *kind { + mir::AggregateKind::Vec => { + self.const_array(dest_ty, &fields) } - } else { - C_struct(self.ccx, &fields, false) - }; - Const::new(val, dest_ty) + mir::AggregateKind::Adt(..) | + mir::AggregateKind::Closure(..) | + mir::AggregateKind::Tuple => { + let disr = match *kind { + mir::AggregateKind::Adt(adt_def, index, _, _) => { + Disr::from(adt_def.variants[index].disr_val) + } + _ => Disr(0) + }; + let repr = adt::represent_type(self.ccx, dest_ty); + Const::new( + adt::trans_const(self.ccx, &repr, disr, &fields), + dest_ty + ) + } + } } mir::Rvalue::Cast(ref kind, ref source, cast_ty) => { @@ -786,6 +810,8 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { _ => span_bug!(span, "{:?} in constant", rvalue) }; + debug!("const_rvalue({:?}: {:?} @ {:?}) = {:?}", rvalue, dest_ty, span, val); + Ok(val) } @@ -935,6 +961,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { constant: &mir::Constant<'tcx>) -> Const<'tcx> { + debug!("trans_constant({:?})", constant); let ty = bcx.monomorphize(&constant.ty); let result = match constant.literal.clone() { mir::Literal::Item { def_id, substs } => { @@ -959,11 +986,14 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { } }; - result.unwrap_or_else(|_| { + let result = result.unwrap_or_else(|_| { // We've errored, so we don't have to produce working code. let llty = type_of::type_of(bcx.ccx(), ty); Const::new(C_undef(llty), ty) - }) + }); + + debug!("trans_constant({:?}) = {:?}", constant, result); + result } } diff --git a/src/test/run-pass/issue-36401.rs b/src/test/run-pass/issue-36401.rs new file mode 100644 index 000000000000..7b08eba9e498 --- /dev/null +++ b/src/test/run-pass/issue-36401.rs @@ -0,0 +1,25 @@ +// 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. + +#[derive(Debug)] +pub enum Event { + Key(u8), + Resize, + Unknown(u16), +} + +static XTERM_SINGLE_BYTES : [(u8, Event); 1] = [(1, Event::Resize)]; + +fn main() { + match XTERM_SINGLE_BYTES[0] { + (1, Event::Resize) => {}, + ref bad => panic!("unexpected {:?}", bad) + } +} From f1c6cad96398d558e6ecca9cc144a1b96da9e4c5 Mon Sep 17 00:00:00 2001 From: Ahmed Charles Date: Sat, 27 Aug 2016 01:42:56 -0700 Subject: [PATCH 297/443] Use question_mark feature in linkchecker. --- src/tools/linkchecker/main.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/tools/linkchecker/main.rs b/src/tools/linkchecker/main.rs index 27adabbc72e5..3e2bc9032a1c 100644 --- a/src/tools/linkchecker/main.rs +++ b/src/tools/linkchecker/main.rs @@ -24,6 +24,8 @@ //! A few whitelisted exceptions are allowed as there's known bugs in rustdoc, //! but this should catch the majority of "broken link" cases. +#![feature(question_mark)] + extern crate url; use std::env; @@ -243,15 +245,14 @@ fn load_file(cache: &mut Cache, None } Entry::Vacant(entry) => { - let mut fp = try!(File::open(file.clone()).map_err(|err| { + let mut fp = File::open(file.clone()).map_err(|err| { if let FromRedirect(true) = redirect { LoadError::BrokenRedirect(file.clone(), err) } else { LoadError::IOError(err) } - })); - try!(fp.read_to_string(&mut contents) - .map_err(|err| LoadError::IOError(err))); + })?; + fp.read_to_string(&mut contents).map_err(|err| LoadError::IOError(err))?; let maybe = maybe_redirect(&contents); if maybe.is_some() { From f0a414e74e4bd4d70fcf93198791432705df9b92 Mon Sep 17 00:00:00 2001 From: Ahmed Charles Date: Sat, 27 Aug 2016 01:47:03 -0700 Subject: [PATCH 298/443] Use question_mark feature in compiletest. --- src/tools/compiletest/src/runtest.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 228d6ada01dc..bfb85dd479d5 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -2113,23 +2113,23 @@ actual:\n\ } fn aggressive_rm_rf(&self, path: &Path) -> io::Result<()> { - for e in try!(path.read_dir()) { - let entry = try!(e); + for e in path.read_dir()? { + let entry = e?; let path = entry.path(); - if try!(entry.file_type()).is_dir() { - try!(self.aggressive_rm_rf(&path)); + if entry.file_type()?.is_dir() { + self.aggressive_rm_rf(&path)?; } else { // Remove readonly files as well on windows (by default we can't) - try!(fs::remove_file(&path).or_else(|e| { + fs::remove_file(&path).or_else(|e| { if cfg!(windows) && e.kind() == io::ErrorKind::PermissionDenied { - let mut meta = try!(entry.metadata()).permissions(); + let mut meta = entry.metadata()?.permissions(); meta.set_readonly(false); - try!(fs::set_permissions(&path, meta)); + fs::set_permissions(&path, meta)?; fs::remove_file(&path) } else { Err(e) } - })) + })?; } } fs::remove_dir(path) From 6d88ab57b3e308456c79694e281dbd4f08603f13 Mon Sep 17 00:00:00 2001 From: Ahmed Charles Date: Sat, 27 Aug 2016 02:10:09 -0700 Subject: [PATCH 299/443] Fix typo in bootstrap/lib.rs. --- src/bootstrap/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 94c14f7ea254..a1424bf3aaa4 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -46,7 +46,7 @@ use util::{exe, mtime, libdir, add_lib_path}; /// * The error itself /// /// This is currently used judiciously throughout the build system rather than -/// using a `Result` with `try!`, but this may change on day... +/// using a `Result` with `try!`, but this may change one day... macro_rules! t { ($e:expr) => (match $e { Ok(e) => e, From bfd123d1e9fce7b0cfb4462966b09a76e65b00d6 Mon Sep 17 00:00:00 2001 From: Ahmed Charles Date: Sat, 27 Aug 2016 02:12:25 -0700 Subject: [PATCH 300/443] Use question_mark feature in libcore. --- src/libcore/num/bignum.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcore/num/bignum.rs b/src/libcore/num/bignum.rs index bc503ba3e46a..1ca550c67463 100644 --- a/src/libcore/num/bignum.rs +++ b/src/libcore/num/bignum.rs @@ -474,9 +474,9 @@ macro_rules! define_bignum { let sz = if self.size < 1 {1} else {self.size}; let digitlen = mem::size_of::<$ty>() * 2; - try!(write!(f, "{:#x}", self.base[sz-1])); + write!(f, "{:#x}", self.base[sz-1])?; for &v in self.base[..sz-1].iter().rev() { - try!(write!(f, "_{:01$x}", v, digitlen)); + write!(f, "_{:01$x}", v, digitlen)?; } ::result::Result::Ok(()) } From 8391760bd846740ea13f9c415a00af10a0b735d1 Mon Sep 17 00:00:00 2001 From: Ahmed Charles Date: Sat, 27 Aug 2016 02:21:36 -0700 Subject: [PATCH 301/443] Use question_mark feature in librustc_errors. --- src/librustc_errors/emitter.rs | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index dcdbe2a85259..1bdc9ef30881 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -882,45 +882,45 @@ impl Destination { match style { Style::FileNameStyle | Style::LineAndColumn => {} Style::LineNumber => { - try!(self.start_attr(term::Attr::Bold)); + self.start_attr(term::Attr::Bold)?; if cfg!(windows) { - try!(self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_CYAN))); + self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_CYAN))?; } else { - try!(self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_BLUE))); + self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_BLUE))?; } } Style::ErrorCode => { - try!(self.start_attr(term::Attr::Bold)); - try!(self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_MAGENTA))); + self.start_attr(term::Attr::Bold)?; + self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_MAGENTA))?; } Style::Quotation => {} Style::OldSchoolNote => { - try!(self.start_attr(term::Attr::Bold)); - try!(self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_GREEN))); + self.start_attr(term::Attr::Bold)?; + self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_GREEN))?; } Style::OldSchoolNoteText | Style::HeaderMsg => { - try!(self.start_attr(term::Attr::Bold)); + self.start_attr(term::Attr::Bold)?; if cfg!(windows) { - try!(self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_WHITE))); + self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_WHITE))?; } } Style::UnderlinePrimary | Style::LabelPrimary => { - try!(self.start_attr(term::Attr::Bold)); - try!(self.start_attr(term::Attr::ForegroundColor(lvl.color()))); + self.start_attr(term::Attr::Bold)?; + self.start_attr(term::Attr::ForegroundColor(lvl.color()))?; } Style::UnderlineSecondary | Style::LabelSecondary => { - try!(self.start_attr(term::Attr::Bold)); + self.start_attr(term::Attr::Bold)?; if cfg!(windows) { - try!(self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_CYAN))); + self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_CYAN))?; } else { - try!(self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_BLUE))); + self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_BLUE))?; } } Style::NoStyle => {} Style::Level(l) => { - try!(self.start_attr(term::Attr::Bold)); - try!(self.start_attr(term::Attr::ForegroundColor(l.color()))); + self.start_attr(term::Attr::Bold)?; + self.start_attr(term::Attr::ForegroundColor(l.color()))?; } } Ok(()) @@ -960,4 +960,4 @@ impl Write for Destination { Raw(ref mut w) => w.flush(), } } -} \ No newline at end of file +} From 8a9e52a8e734972b9b16cbfc3902743eb432cfbc Mon Sep 17 00:00:00 2001 From: Ahmed Charles Date: Sat, 27 Aug 2016 02:31:17 -0700 Subject: [PATCH 302/443] Use question_mark feature in librustc_incremental. --- src/librustc_incremental/persist/hash.rs | 4 ++-- src/librustc_incremental/persist/load.rs | 8 ++++---- src/librustc_incremental/persist/save.rs | 10 +++++----- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/librustc_incremental/persist/hash.rs b/src/librustc_incremental/persist/hash.rs index 95bee669d325..bafaafd4afa0 100644 --- a/src/librustc_incremental/persist/hash.rs +++ b/src/librustc_incremental/persist/hash.rs @@ -194,7 +194,7 @@ impl<'a, 'tcx> HashContext<'a, 'tcx> { // Load up the hashes for the def-ids from this crate. let mut decoder = Decoder::new(data, 0); - let svh_in_hashes_file = try!(Svh::decode(&mut decoder)); + let svh_in_hashes_file = Svh::decode(&mut decoder)?; if svh_in_hashes_file != expected_svh { // We should not be able to get here. If we do, then @@ -202,7 +202,7 @@ impl<'a, 'tcx> HashContext<'a, 'tcx> { bug!("mismatch between SVH in crate and SVH in incr. comp. hashes") } - let serialized_hashes = try!(SerializedMetadataHashes::decode(&mut decoder)); + let serialized_hashes = SerializedMetadataHashes::decode(&mut decoder)?; for serialized_hash in serialized_hashes.hashes { // the hashes are stored with just a def-index, which is // always relative to the old crate; convert that to use diff --git a/src/librustc_incremental/persist/load.rs b/src/librustc_incremental/persist/load.rs index 48f95430f26b..6e6464e49683 100644 --- a/src/librustc_incremental/persist/load.rs +++ b/src/librustc_incremental/persist/load.rs @@ -125,11 +125,11 @@ pub fn decode_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, { // Decode the list of work_products let mut work_product_decoder = Decoder::new(work_products_data, 0); - let work_products = try!(>::decode(&mut work_product_decoder)); + let work_products = >::decode(&mut work_product_decoder)?; // Deserialize the directory and dep-graph. let mut dep_graph_decoder = Decoder::new(dep_graph_data, 0); - let prev_commandline_args_hash = try!(u64::decode(&mut dep_graph_decoder)); + let prev_commandline_args_hash = u64::decode(&mut dep_graph_decoder)?; if prev_commandline_args_hash != tcx.sess.opts.dep_tracking_hash() { // We can't reuse the cache, purge it. @@ -142,8 +142,8 @@ pub fn decode_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, return Ok(()); } - let directory = try!(DefIdDirectory::decode(&mut dep_graph_decoder)); - let serialized_dep_graph = try!(SerializedDepGraph::decode(&mut dep_graph_decoder)); + let directory = DefIdDirectory::decode(&mut dep_graph_decoder)?; + let serialized_dep_graph = SerializedDepGraph::decode(&mut dep_graph_decoder)?; // Retrace the paths in the directory to find their current location (if any). let retraced = directory.retrace(tcx); diff --git a/src/librustc_incremental/persist/save.rs b/src/librustc_incremental/persist/save.rs index d31252be5e85..41212d8e138d 100644 --- a/src/librustc_incremental/persist/save.rs +++ b/src/librustc_incremental/persist/save.rs @@ -110,7 +110,7 @@ pub fn encode_dep_graph(preds: &Predecessors, -> io::Result<()> { // First encode the commandline arguments hash let tcx = builder.tcx(); - try!(tcx.sess.opts.dep_tracking_hash().encode(encoder)); + tcx.sess.opts.dep_tracking_hash().encode(encoder)?; // Create a flat list of (Input, WorkProduct) edges for // serialization. @@ -149,8 +149,8 @@ pub fn encode_dep_graph(preds: &Predecessors, debug!("graph = {:#?}", graph); // Encode the directory and then the graph data. - try!(builder.directory().encode(encoder)); - try!(graph.encode(encoder)); + builder.directory().encode(encoder)?; + graph.encode(encoder)?; Ok(()) } @@ -222,8 +222,8 @@ pub fn encode_metadata_hashes(tcx: TyCtxt, } // Encode everything. - try!(svh.encode(encoder)); - try!(serialized_hashes.encode(encoder)); + svh.encode(encoder)?; + serialized_hashes.encode(encoder)?; Ok(()) } From e10e0bcf2d4e8a5c98c4cfb577f161187b74bfcc Mon Sep 17 00:00:00 2001 From: Ahmed Charles Date: Sat, 27 Aug 2016 02:32:28 -0700 Subject: [PATCH 303/443] Use question_mark feature in librustc_mir. --- src/librustc_mir/pretty.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/librustc_mir/pretty.rs b/src/librustc_mir/pretty.rs index d46a7b2bb950..01e2c6308ba0 100644 --- a/src/librustc_mir/pretty.rs +++ b/src/librustc_mir/pretty.rs @@ -77,12 +77,12 @@ pub fn dump_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, node_id, promotion_id, pass_name, disambiguator); file_path.push(&file_name); let _ = fs::File::create(&file_path).and_then(|mut file| { - try!(writeln!(file, "// MIR for `{}`", node_path)); - try!(writeln!(file, "// node_id = {}", node_id)); - try!(writeln!(file, "// pass_name = {}", pass_name)); - try!(writeln!(file, "// disambiguator = {}", disambiguator)); - try!(writeln!(file, "")); - try!(write_mir_fn(tcx, src, mir, &mut file, auxiliary)); + writeln!(file, "// MIR for `{}`", node_path)?; + writeln!(file, "// node_id = {}", node_id)?; + writeln!(file, "// pass_name = {}", pass_name)?; + writeln!(file, "// disambiguator = {}", disambiguator)?; + writeln!(file, "")?; + write_mir_fn(tcx, src, mir, &mut file, auxiliary)?; Ok(()) }); } From 14d3937e659b383a32ec9c90e5805386150c0054 Mon Sep 17 00:00:00 2001 From: Ahmed Charles Date: Sat, 27 Aug 2016 06:50:17 -0700 Subject: [PATCH 304/443] Use question_mark feature in librustc. --- src/librustc/hir/print.rs | 4 ++-- src/librustc/infer/higher_ranked/mod.rs | 2 +- src/librustc/util/fs.rs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index f236bd4884d5..eebc8fa9e5d5 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -1756,9 +1756,9 @@ impl<'a> State<'a> { self.commasep(Inconsistent, &elts[ddpos..], |s, p| s.print_pat(&p))?; } } else { - try!(self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(&p))); + self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(&p))?; } - try!(self.pclose()); + self.pclose()?; } PatKind::Path(None, ref path) => { self.print_path(path, true, 0)?; diff --git a/src/librustc/infer/higher_ranked/mod.rs b/src/librustc/infer/higher_ranked/mod.rs index 322752ccea3e..7c02de05d26d 100644 --- a/src/librustc/infer/higher_ranked/mod.rs +++ b/src/librustc/infer/higher_ranked/mod.rs @@ -130,7 +130,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { debug!("higher_ranked_match: skol_map={:?}", skol_map); // Equate types now that bound regions have been replaced. - try!(self.equate(a_is_expected).relate(&a_match, &b_match)); + self.equate(a_is_expected).relate(&a_match, &b_match)?; // Map each skolemized region to a vector of other regions that it // must be equated with. (Note that this vector may include other diff --git a/src/librustc/util/fs.rs b/src/librustc/util/fs.rs index d7800ccaa5dd..c290d8f893e9 100644 --- a/src/librustc/util/fs.rs +++ b/src/librustc/util/fs.rs @@ -68,7 +68,7 @@ pub fn link_or_copy, Q: AsRef>(p: P, q: Q) -> io::Result
  • Date: Sat, 27 Aug 2016 07:16:17 -0700 Subject: [PATCH 305/443] Use question_mark feature in libserialize. --- src/libserialize/json.rs | 11 +++++------ src/libserialize/serialize.rs | 8 ++++---- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/libserialize/json.rs b/src/libserialize/json.rs index 0782601e1796..6ccc0be41bc0 100644 --- a/src/libserialize/json.rs +++ b/src/libserialize/json.rs @@ -475,15 +475,14 @@ impl<'a> Encoder<'a> { } macro_rules! emit_enquoted_if_mapkey { - ($enc:ident,$e:expr) => { + ($enc:ident,$e:expr) => ({ if $enc.is_emitting_map_key { - try!(write!($enc.writer, "\"{}\"", $e)); - Ok(()) + write!($enc.writer, "\"{}\"", $e)?; } else { - try!(write!($enc.writer, "{}", $e)); - Ok(()) + write!($enc.writer, "{}", $e)?; } - } + Ok(()) + }) } impl<'a> ::Encoder for Encoder<'a> { diff --git a/src/libserialize/serialize.rs b/src/libserialize/serialize.rs index b75ec5dad8dd..8e271597dfcb 100644 --- a/src/libserialize/serialize.rs +++ b/src/libserialize/serialize.rs @@ -511,10 +511,10 @@ macro_rules! tuple { let len: usize = count_idents!($($name,)*); d.read_tuple(len, |d| { let mut i = 0; - let ret = ($(try!(d.read_tuple_arg({ i+=1; i-1 }, - |d| -> Result<$name,D::Error> { + let ret = ($(d.read_tuple_arg({ i+=1; i-1 }, + |d| -> Result<$name,D::Error> { Decodable::decode(d) - })),)*); + })?,)*); Ok(ret) }) } @@ -527,7 +527,7 @@ macro_rules! tuple { $(let $name = $name; n += 1;)* s.emit_tuple(n, |s| { let mut i = 0; - $(try!(s.emit_tuple_arg({ i+=1; i-1 }, |s| $name.encode(s)));)* + $(s.emit_tuple_arg({ i+=1; i-1 }, |s| $name.encode(s))?;)* Ok(()) }) } From 637f1492e7beb768c039b962fb04b6855d6e9461 Mon Sep 17 00:00:00 2001 From: Ahmed Charles Date: Sat, 27 Aug 2016 07:33:36 -0700 Subject: [PATCH 306/443] Use question_mark feature in libstd. --- src/libstd/sync/mpsc/oneshot.rs | 2 +- src/libstd/sync/mpsc/stream.rs | 3 +-- src/libstd/sys/common/backtrace.rs | 4 ++-- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/libstd/sync/mpsc/oneshot.rs b/src/libstd/sync/mpsc/oneshot.rs index 7a35ea6bbaaa..7389280b853d 100644 --- a/src/libstd/sync/mpsc/oneshot.rs +++ b/src/libstd/sync/mpsc/oneshot.rs @@ -150,7 +150,7 @@ impl Packet { let timed_out = !wait_token.wait_max_until(deadline); // Try to reset the state if timed_out { - try!(self.abort_selection().map_err(Upgraded)); + self.abort_selection().map_err(Upgraded)?; } } else { wait_token.wait(); diff --git a/src/libstd/sync/mpsc/stream.rs b/src/libstd/sync/mpsc/stream.rs index aa1254c8641f..61c8316467d9 100644 --- a/src/libstd/sync/mpsc/stream.rs +++ b/src/libstd/sync/mpsc/stream.rs @@ -187,8 +187,7 @@ impl Packet { if let Some(deadline) = deadline { let timed_out = !wait_token.wait_max_until(deadline); if timed_out { - try!(self.abort_selection(/* was_upgrade = */ false) - .map_err(Upgraded)); + self.abort_selection(/* was_upgrade = */ false).map_err(Upgraded)?; } } else { wait_token.wait(); diff --git a/src/libstd/sys/common/backtrace.rs b/src/libstd/sys/common/backtrace.rs index a509b80eaca9..a8540fed9286 100644 --- a/src/libstd/sys/common/backtrace.rs +++ b/src/libstd/sys/common/backtrace.rs @@ -153,11 +153,11 @@ pub fn demangle(writer: &mut Write, s: &str) -> io::Result<()> { macro_rules! demangle { ($($pat:expr => $demangled:expr),*) => ({ $(if rest.starts_with($pat) { - try!(writer.write_all($demangled)); + writer.write_all($demangled)?; rest = &rest[$pat.len()..]; } else)* { - try!(writer.write_all(rest.as_bytes())); + writer.write_all(rest.as_bytes())?; break; } From 0dbf77e722e6f30568664808808716d8d3650dc5 Mon Sep 17 00:00:00 2001 From: Ahmed Charles Date: Sat, 27 Aug 2016 07:48:39 -0700 Subject: [PATCH 307/443] Use question_mark feature in librustc_back. --- src/librustc_back/target/aarch64_apple_ios.rs | 2 +- src/librustc_back/target/apple_ios_base.rs | 4 ++-- src/librustc_back/target/armv7_apple_ios.rs | 2 +- src/librustc_back/target/armv7s_apple_ios.rs | 2 +- src/librustc_back/target/i386_apple_ios.rs | 2 +- src/librustc_back/target/i586_pc_windows_msvc.rs | 2 +- .../target/i586_unknown_linux_gnu.rs | 2 +- src/librustc_back/target/mod.rs | 16 ++++++++-------- src/librustc_back/target/x86_64_apple_ios.rs | 2 +- 9 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/librustc_back/target/aarch64_apple_ios.rs b/src/librustc_back/target/aarch64_apple_ios.rs index 6530ccb0630d..660ed0ac7b84 100644 --- a/src/librustc_back/target/aarch64_apple_ios.rs +++ b/src/librustc_back/target/aarch64_apple_ios.rs @@ -12,7 +12,7 @@ use target::{Target, TargetOptions, TargetResult}; use super::apple_ios_base::{opts, Arch}; pub fn target() -> TargetResult { - let base = try!(opts(Arch::Arm64)); + let base = opts(Arch::Arm64)?; Ok(Target { llvm_target: "arm64-apple-ios".to_string(), target_endian: "little".to_string(), diff --git a/src/librustc_back/target/apple_ios_base.rs b/src/librustc_back/target/apple_ios_base.rs index 8bd9feabdbeb..17492b8bdcb6 100644 --- a/src/librustc_back/target/apple_ios_base.rs +++ b/src/librustc_back/target/apple_ios_base.rs @@ -68,7 +68,7 @@ fn build_pre_link_args(arch: Arch) -> Result, String> { let arch_name = arch.to_string(); - let sdk_root = try!(get_sdk_root(sdk_name)); + let sdk_root = get_sdk_root(sdk_name)?; Ok(vec!["-arch".to_string(), arch_name.to_string(), "-Wl,-syslibroot".to_string(), sdk_root]) @@ -85,7 +85,7 @@ fn target_cpu(arch: Arch) -> String { } pub fn opts(arch: Arch) -> Result { - let pre_link_args = try!(build_pre_link_args(arch)); + let pre_link_args = build_pre_link_args(arch)?; Ok(TargetOptions { cpu: target_cpu(arch), dynamic_linking: false, diff --git a/src/librustc_back/target/armv7_apple_ios.rs b/src/librustc_back/target/armv7_apple_ios.rs index a806204d0a6b..71533a09b167 100644 --- a/src/librustc_back/target/armv7_apple_ios.rs +++ b/src/librustc_back/target/armv7_apple_ios.rs @@ -12,7 +12,7 @@ use target::{Target, TargetOptions, TargetResult}; use super::apple_ios_base::{opts, Arch}; pub fn target() -> TargetResult { - let base = try!(opts(Arch::Armv7)); + let base = opts(Arch::Armv7)?; Ok(Target { llvm_target: "armv7-apple-ios".to_string(), target_endian: "little".to_string(), diff --git a/src/librustc_back/target/armv7s_apple_ios.rs b/src/librustc_back/target/armv7s_apple_ios.rs index aaa3570fa62e..f24b9969910e 100644 --- a/src/librustc_back/target/armv7s_apple_ios.rs +++ b/src/librustc_back/target/armv7s_apple_ios.rs @@ -12,7 +12,7 @@ use target::{Target, TargetOptions, TargetResult}; use super::apple_ios_base::{opts, Arch}; pub fn target() -> TargetResult { - let base = try!(opts(Arch::Armv7s)); + let base = opts(Arch::Armv7s)?; Ok(Target { llvm_target: "armv7s-apple-ios".to_string(), target_endian: "little".to_string(), diff --git a/src/librustc_back/target/i386_apple_ios.rs b/src/librustc_back/target/i386_apple_ios.rs index f391d4118ea7..94146fe9d988 100644 --- a/src/librustc_back/target/i386_apple_ios.rs +++ b/src/librustc_back/target/i386_apple_ios.rs @@ -12,7 +12,7 @@ use target::{Target, TargetOptions, TargetResult}; use super::apple_ios_base::{opts, Arch}; pub fn target() -> TargetResult { - let base = try!(opts(Arch::I386)); + let base = opts(Arch::I386)?; Ok(Target { llvm_target: "i386-apple-ios".to_string(), target_endian: "little".to_string(), diff --git a/src/librustc_back/target/i586_pc_windows_msvc.rs b/src/librustc_back/target/i586_pc_windows_msvc.rs index 445ee6c41228..9b88cde59893 100644 --- a/src/librustc_back/target/i586_pc_windows_msvc.rs +++ b/src/librustc_back/target/i586_pc_windows_msvc.rs @@ -11,7 +11,7 @@ use target::TargetResult; pub fn target() -> TargetResult { - let mut base = try!(super::i686_pc_windows_msvc::target()); + let mut base = super::i686_pc_windows_msvc::target()?; base.options.cpu = "pentium".to_string(); base.llvm_target = "i586-pc-windows-msvc".to_string(); Ok(base) diff --git a/src/librustc_back/target/i586_unknown_linux_gnu.rs b/src/librustc_back/target/i586_unknown_linux_gnu.rs index 1ca8606149bf..40fb4a67acdf 100644 --- a/src/librustc_back/target/i586_unknown_linux_gnu.rs +++ b/src/librustc_back/target/i586_unknown_linux_gnu.rs @@ -11,7 +11,7 @@ use target::TargetResult; pub fn target() -> TargetResult { - let mut base = try!(super::i686_unknown_linux_gnu::target()); + let mut base = super::i686_unknown_linux_gnu::target()?; base.options.cpu = "pentium".to_string(); base.llvm_target = "i586-unknown-linux-gnu".to_string(); Ok(base) diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs index d48370b23b69..e9fce9cee00d 100644 --- a/src/librustc_back/target/mod.rs +++ b/src/librustc_back/target/mod.rs @@ -77,12 +77,12 @@ macro_rules! supported_targets { match target { $( $triple => { - let mut t = try!($module::target()); + let mut t = $module::target()?; t.options.is_builtin = true; // round-trip through the JSON parser to ensure at // run-time that the parser works correctly - t = try!(Target::from_json(t.to_json())); + t = Target::from_json(t.to_json())?; debug!("Got builtin target: {:?}", t); Ok(t) }, @@ -442,12 +442,12 @@ impl Target { }; let mut base = Target { - llvm_target: try!(get_req_field("llvm-target")), - target_endian: try!(get_req_field("target-endian")), - target_pointer_width: try!(get_req_field("target-pointer-width")), - data_layout: try!(get_req_field("data-layout")), - arch: try!(get_req_field("arch")), - target_os: try!(get_req_field("os")), + llvm_target: get_req_field("llvm-target")?, + target_endian: get_req_field("target-endian")?, + target_pointer_width: get_req_field("target-pointer-width")?, + data_layout: get_req_field("data-layout")?, + arch: get_req_field("arch")?, + target_os: get_req_field("os")?, target_env: get_opt_field("env", ""), target_vendor: get_opt_field("vendor", "unknown"), options: Default::default(), diff --git a/src/librustc_back/target/x86_64_apple_ios.rs b/src/librustc_back/target/x86_64_apple_ios.rs index 4afc9bcb946c..3b8b636b6dc6 100644 --- a/src/librustc_back/target/x86_64_apple_ios.rs +++ b/src/librustc_back/target/x86_64_apple_ios.rs @@ -12,7 +12,7 @@ use target::{Target, TargetOptions, TargetResult}; use super::apple_ios_base::{opts, Arch}; pub fn target() -> TargetResult { - let base = try!(opts(Arch::X86_64)); + let base = opts(Arch::X86_64)?; Ok(Target { llvm_target: "x86_64-apple-ios".to_string(), target_endian: "little".to_string(), From 509aa235ba4a2d453cf545f2553b8173dcd5f25b Mon Sep 17 00:00:00 2001 From: Ahmed Charles Date: Sat, 27 Aug 2016 07:51:55 -0700 Subject: [PATCH 308/443] Use question_mark feature in librustc_const_eval. --- src/librustc_const_eval/eval.rs | 41 +++++++++++++++------------------ 1 file changed, 19 insertions(+), 22 deletions(-) diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index 4f4c16d3f6a6..4ced9d87f0a5 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -278,9 +278,9 @@ pub fn const_expr_to_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } let pat = match expr.node { hir::ExprTup(ref exprs) => - PatKind::Tuple(try!(exprs.iter() - .map(|expr| const_expr_to_pat(tcx, &expr, pat_id, span)) - .collect()), None), + PatKind::Tuple(exprs.iter() + .map(|expr| const_expr_to_pat(tcx, &expr, pat_id, span)) + .collect::>()?, None), hir::ExprCall(ref callee, ref args) => { let def = tcx.expect_def(callee.id); @@ -297,34 +297,31 @@ pub fn const_expr_to_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, })), _ => bug!() }; - let pats = try!(args.iter() - .map(|expr| const_expr_to_pat(tcx, &**expr, - pat_id, span)) - .collect()); + let pats = args.iter() + .map(|expr| const_expr_to_pat(tcx, &**expr, pat_id, span)) + .collect::>()?; PatKind::TupleStruct(path, pats, None) } hir::ExprStruct(ref path, ref fields, None) => { let field_pats = - try!(fields.iter() - .map(|field| Ok(codemap::Spanned { - span: syntax_pos::DUMMY_SP, - node: hir::FieldPat { - name: field.name.node, - pat: try!(const_expr_to_pat(tcx, &field.expr, - pat_id, span)), - is_shorthand: false, - }, - })) - .collect()); + fields.iter() + .map(|field| Ok(codemap::Spanned { + span: syntax_pos::DUMMY_SP, + node: hir::FieldPat { + name: field.name.node, + pat: const_expr_to_pat(tcx, &field.expr, pat_id, span)?, + is_shorthand: false, + }, + })) + .collect::>()?; PatKind::Struct(path.clone(), field_pats, false) } hir::ExprVec(ref exprs) => { - let pats = try!(exprs.iter() - .map(|expr| const_expr_to_pat(tcx, &expr, - pat_id, span)) - .collect()); + let pats = exprs.iter() + .map(|expr| const_expr_to_pat(tcx, &expr, pat_id, span)) + .collect::>()?; PatKind::Vec(pats, None, hir::HirVec::new()) } From 694d601dbc2df575c32a490a529656a864dc0a2e Mon Sep 17 00:00:00 2001 From: Ahmed Charles Date: Sat, 27 Aug 2016 07:53:05 -0700 Subject: [PATCH 309/443] Use question_mark feature in librustc_metadata. --- src/librustc_metadata/loader.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc_metadata/loader.rs b/src/librustc_metadata/loader.rs index 44d7861066da..a4f8ee477990 100644 --- a/src/librustc_metadata/loader.rs +++ b/src/librustc_metadata/loader.rs @@ -809,7 +809,7 @@ fn get_metadata_section_imp(target: &Target, flavor: CrateFlavor, filename: &Pat None => Err(format!("failed to read rlib metadata: '{}'", filename.display())), Some(blob) => { - try!(verify_decompressed_encoding_version(&blob, filename)); + verify_decompressed_encoding_version(&blob, filename)?; Ok(blob) } }; @@ -858,7 +858,7 @@ fn get_metadata_section_imp(target: &Target, flavor: CrateFlavor, filename: &Pat match flate::inflate_bytes(bytes) { Ok(inflated) => { let blob = MetadataVec(inflated); - try!(verify_decompressed_encoding_version(&blob, filename)); + verify_decompressed_encoding_version(&blob, filename)?; return Ok(blob); } Err(_) => {} From 5b59c141438f10f7351992f1ff38c20e63a9a441 Mon Sep 17 00:00:00 2001 From: dangcheng Date: Mon, 12 Sep 2016 12:02:35 +0800 Subject: [PATCH 310/443] change error message --- src/doc/book/traits.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/book/traits.md b/src/doc/book/traits.md index 605dc2a152df..d07fb6b7c45b 100644 --- a/src/doc/book/traits.md +++ b/src/doc/book/traits.md @@ -275,7 +275,7 @@ won’t have its methods: [write]: ../std/io/trait.Write.html ```rust,ignore -let mut f = std::fs::File::create("foo.txt").expect("Couldn’t open foo.txt"); +let mut f = std::fs::File::create("foo.txt").expect("Couldn’t create foo.txt"); let buf = b"whatever"; // byte string literal. buf: &[u8; 8] let result = f.write(buf); # result.unwrap(); // ignore the error @@ -294,7 +294,7 @@ We need to `use` the `Write` trait first: ```rust,ignore use std::io::Write; -let mut f = std::fs::File::create("foo.txt").expect("Couldn’t open foo.txt"); +let mut f = std::fs::File::create("foo.txt").expect("Couldn’t create foo.txt"); let buf = b"whatever"; let result = f.write(buf); # result.unwrap(); // ignore the error From 4c274b6aea00c2327211e8295f4d97ee6e624a2b Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 12 Sep 2016 13:03:21 +1000 Subject: [PATCH 311/443] Avoid an unnecessary intermediate value in char_lit(). This makes the function more concise and easier to understand. --- src/libsyntax/parse/mod.rs | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index af95e44a567b..31fa2cda5db5 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -287,26 +287,21 @@ pub fn char_lit(lit: &str) -> (char, isize) { use std::char; let mut chars = lit.chars(); - let c = match (chars.next(), chars.next()) { + match (chars.next(), chars.next()) { (Some(c), None) if c != '\\' => return (c, 1), (Some('\\'), Some(c)) => match c { - '"' => Some('"'), - 'n' => Some('\n'), - 'r' => Some('\r'), - 't' => Some('\t'), - '\\' => Some('\\'), - '\'' => Some('\''), - '0' => Some('\0'), - _ => { None } + '"' => return ('"', 2), + 'n' => return ('\n', 2), + 'r' => return ('\r', 2), + 't' => return ('\t', 2), + '\\' => return ('\\', 2), + '\'' => return ('\'', 2), + '0' => return ('\0', 2), + _ => {} }, _ => panic!("lexer accepted invalid char escape `{}`", lit) }; - match c { - Some(x) => return (x, 2), - None => { } - } - let msg = format!("lexer should have rejected a bad character escape {}", lit); let msg2 = &msg[..]; From 826f673664023e79e86409296d3d67527c9b0a5a Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 12 Sep 2016 14:31:51 +1000 Subject: [PATCH 312/443] Lazily construct panic messages in char_lit(). This reduces the time taken to run `rustc -Zparse-only rustc-benchmarks/issue-32278-big-array-of-strings` from 0.18s to 0.15s on my machine, and reduces the number of instructions (as measured by Cachegrind) from 1.34B to 1.01B. With the change applied, the time to fully compile that benchmark is 1.96s, so this is a 1.5% improvement. --- src/libsyntax/parse/mod.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 31fa2cda5db5..a1eceb6921c6 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -302,9 +302,6 @@ pub fn char_lit(lit: &str) -> (char, isize) { _ => panic!("lexer accepted invalid char escape `{}`", lit) }; - let msg = format!("lexer should have rejected a bad character escape {}", lit); - let msg2 = &msg[..]; - fn esc(len: usize, lit: &str) -> Option<(char, isize)> { u32::from_str_radix(&lit[2..len], 16).ok() .and_then(char::from_u32) @@ -313,7 +310,10 @@ pub fn char_lit(lit: &str) -> (char, isize) { let unicode_escape = || -> Option<(char, isize)> { if lit.as_bytes()[2] == b'{' { - let idx = lit.find('}').expect(msg2); + let idx = lit.find('}').unwrap_or_else(|| { + panic!("lexer should have rejected a bad character escape {}", lit) + }); + let subslice = &lit[3..idx]; u32::from_str_radix(subslice, 16).ok() .and_then(char::from_u32) @@ -329,7 +329,9 @@ pub fn char_lit(lit: &str) -> (char, isize) { 'u' => unicode_escape(), 'U' => esc(10, lit), _ => None, - }.expect(msg2); + }.unwrap_or_else(|| { + panic!("lexer should have rejected a bad character escape {}", lit) + }) } /// Parse a string representing a string literal into its final form. Does From 9ca578687b88d2c7817d5709b2700fb6777348f2 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 12 Sep 2016 17:43:44 -0400 Subject: [PATCH 313/443] check stack discipline of tasks --- src/librustc/dep_graph/shadow.rs | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/src/librustc/dep_graph/shadow.rs b/src/librustc/dep_graph/shadow.rs index f9f75d006775..72a321425ef0 100644 --- a/src/librustc/dep_graph/shadow.rs +++ b/src/librustc/dep_graph/shadow.rs @@ -17,8 +17,10 @@ //! runtime impact. Therefore, it is largely compiled out if //! debug-assertions are not enabled. //! -//! The basic sanity check, always enabled, is that there is always a -//! task (or ignore) on the stack when you do read/write. +//! The basic sanity check, enabled if you have debug assertions +//! enabled, is that there is always a task (or ignore) on the stack +//! when you do read/write, and that the tasks are pushed/popped +//! according to a proper stack discipline. //! //! Optionally, if you specify RUST_FORBID_DEP_GRAPH_EDGE, you can //! specify an edge filter to be applied to each edge as it is @@ -81,13 +83,23 @@ impl ShadowGraph { DepMessage::Write(ref n) => self.check_edge(top(&stack), Some(Some(n))), DepMessage::PushTask(ref n) => stack.push(Some(n.clone())), DepMessage::PushIgnore => stack.push(None), - DepMessage::PopTask(_) | + DepMessage::PopTask(ref n) => { + match stack.pop() { + Some(Some(m)) => { + if *n != m { + bug!("stack mismatch: found {:?} expected {:?}", m, n) + } + } + Some(None) => bug!("stack mismatch: found Ignore expected {:?}", n), + None => bug!("stack mismatch: found empty stack, expected {:?}", n), + } + } DepMessage::PopIgnore => { - // we could easily check that the stack is - // well-formed here, but since we use closures and - // RAII accessors, this bug basically never - // happens, so it seems not worth the overhead - stack.pop(); + match stack.pop() { + Some(Some(m)) => bug!("stack mismatch: found {:?} expected ignore", m), + Some(None) => (), + None => bug!("stack mismatch: found empty stack, expected ignore"), + } } DepMessage::Query => (), } From 7bd25a304851afdf0ba1897a950220ed3ad0a215 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Mon, 12 Sep 2016 15:55:02 -0700 Subject: [PATCH 314/443] Remove stray attribute --- src/libcore/iter/traits.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libcore/iter/traits.rs b/src/libcore/iter/traits.rs index 563fb213d376..b55d6f96af9b 100644 --- a/src/libcore/iter/traits.rs +++ b/src/libcore/iter/traits.rs @@ -587,7 +587,6 @@ macro_rules! integer_sum_product { ($($a:ident)*) => ($( #[stable(feature = "iter_arith_traits", since = "1.12.0")] impl Sum for $a { - #[rustc_inherit_overflow_checks] fn sum>(iter: I) -> $a { iter.fold(0, Add::add) } From be2fa70c1604f4383463fa4e64cd9f4567ff47e8 Mon Sep 17 00:00:00 2001 From: knight42 Date: Thu, 8 Sep 2016 18:54:45 +0800 Subject: [PATCH 315/443] Implement std::str::replacen --- src/libcollections/str.rs | 43 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index 999c84ba7053..6a6b450e5186 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -1594,6 +1594,49 @@ impl str { result } + /// Replaces first N matches of a pattern with another string. + /// + /// `replacen` creates a new [`String`], and copies the data from this string slice into it. + /// While doing so, it attempts to find matches of a pattern. If it finds any, it + /// replaces them with the replacement string slice at most `N` times. + /// + /// [`String`]: string/struct.String.html + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # #![feature(str_replacen)] + /// let s = "foo foo 123 foo"; + /// assert_eq!("new new 123 foo", s.replacen("foo", "new", 2)); + /// assert_eq!("faa fao 123 foo", s.replacen('o', "a", 3)); + /// assert_eq!("foo foo new23 foo", s.replacen(char::is_numeric, "new", 1)); + /// ``` + /// + /// When the pattern doesn't match: + /// + /// ``` + /// # #![feature(str_replacen)] + /// let s = "this is old"; + /// assert_eq!(s, s.replacen("cookie monster", "little lamb", 10)); + /// ``` + #[unstable(feature = "str_replacen", + issue = "36436", + reason = "only need to replace first N matches")] + pub fn replacen<'a, P: Pattern<'a>>(&'a self, pat: P, to: &str, count: usize) -> String { + // Hope to reduce the times of re-allocation + let mut result = String::with_capacity(32); + let mut last_end = 0; + for (start, part) in self.match_indices(pat).take(count) { + result.push_str(unsafe { self.slice_unchecked(last_end, start) }); + result.push_str(to); + last_end = start + part.len(); + } + result.push_str(unsafe { self.slice_unchecked(last_end, self.len()) }); + result + } + /// Returns the lowercase equivalent of this string slice, as a new [`String`]. /// /// 'Lowercase' is defined according to the terms of the Unicode Derived Core Property From ebda77072a56a43d33d5723196a5ae37544a1ab9 Mon Sep 17 00:00:00 2001 From: knight42 Date: Thu, 8 Sep 2016 18:55:04 +0800 Subject: [PATCH 316/443] Add tests for str::replacen --- src/libcollectionstest/lib.rs | 1 + src/libcollectionstest/str.rs | 14 ++++++++++++++ 2 files changed, 15 insertions(+) diff --git a/src/libcollectionstest/lib.rs b/src/libcollectionstest/lib.rs index 32a07e3e7e62..878581a4f296 100644 --- a/src/libcollectionstest/lib.rs +++ b/src/libcollectionstest/lib.rs @@ -21,6 +21,7 @@ #![feature(rand)] #![feature(step_by)] #![feature(str_escape)] +#![feature(str_replacen)] #![feature(test)] #![feature(unboxed_closures)] #![feature(unicode)] diff --git a/src/libcollectionstest/str.rs b/src/libcollectionstest/str.rs index a61925cd3be5..62e164a569aa 100644 --- a/src/libcollectionstest/str.rs +++ b/src/libcollectionstest/str.rs @@ -218,6 +218,20 @@ fn test_is_empty() { assert!(!"a".is_empty()); } +#[test] +fn test_replacen() { + assert_eq!("".replacen('a', "b", 5), ""); + assert_eq!("acaaa".replacen("a", "b", 3), "bcbba"); + assert_eq!("aaaa".replacen("a", "b", 0), "aaaa"); + + let test = "test"; + assert_eq!(" test test ".replacen(test, "toast", 3), " toast toast "); + assert_eq!(" test test ".replacen(test, "toast", 0), " test test "); + assert_eq!(" test test ".replacen(test, "", 5), " "); + + assert_eq!("qwer123zxc789".replacen(char::is_numeric, "", 3), "qwerzxc789"); +} + #[test] fn test_replace() { let a = "a"; From 0a62676c73ce8050941d571427dfb621b004a3b8 Mon Sep 17 00:00:00 2001 From: Alex Burka Date: Mon, 12 Sep 2016 17:47:59 -0400 Subject: [PATCH 317/443] fix "X is not a member of trait Y" span labels The span labels for associated types and consts were hardcoded to `Foo` rather than substituting the name of the trait. This also normalizes the wording for associated methods', traits', and consts' span labels. Fixes #36428. --- src/librustc_resolve/lib.rs | 6 +++--- src/test/compile-fail/E0407.rs | 2 +- src/test/compile-fail/E0438.rs | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index c5b505fba38e..a11ef6e221dc 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -247,7 +247,7 @@ fn resolve_struct_error<'b, 'a: 'b, 'c>(resolver: &'b Resolver<'a>, "method `{}` is not a member of trait `{}`", method, trait_); - err.span_label(span, &format!("not a member of `{}`", trait_)); + err.span_label(span, &format!("not a member of trait `{}`", trait_)); err } ResolutionError::TypeNotMemberOfTrait(type_, trait_) => { @@ -257,7 +257,7 @@ fn resolve_struct_error<'b, 'a: 'b, 'c>(resolver: &'b Resolver<'a>, "type `{}` is not a member of trait `{}`", type_, trait_); - err.span_label(span, &format!("not a member of trait `Foo`")); + err.span_label(span, &format!("not a member of trait `{}`", trait_)); err } ResolutionError::ConstNotMemberOfTrait(const_, trait_) => { @@ -267,7 +267,7 @@ fn resolve_struct_error<'b, 'a: 'b, 'c>(resolver: &'b Resolver<'a>, "const `{}` is not a member of trait `{}`", const_, trait_); - err.span_label(span, &format!("not a member of trait `Foo`")); + err.span_label(span, &format!("not a member of trait `{}`", trait_)); err } ResolutionError::VariableNotBoundInPattern(variable_name, from, to) => { diff --git a/src/test/compile-fail/E0407.rs b/src/test/compile-fail/E0407.rs index 2a150b745121..c207dbfca556 100644 --- a/src/test/compile-fail/E0407.rs +++ b/src/test/compile-fail/E0407.rs @@ -18,7 +18,7 @@ impl Foo for Bar { fn a() {} fn b() {} //~^ ERROR E0407 - //~| NOTE not a member of `Foo` + //~| NOTE not a member of trait `Foo` } fn main() { diff --git a/src/test/compile-fail/E0438.rs b/src/test/compile-fail/E0438.rs index f549d62aebfe..2e2df4bee5a3 100644 --- a/src/test/compile-fail/E0438.rs +++ b/src/test/compile-fail/E0438.rs @@ -10,11 +10,11 @@ #![feature(associated_consts)] -trait Foo {} +trait Bar {} -impl Foo for i32 { +impl Bar for i32 { const BAR: bool = true; //~ ERROR E0438 - //~| NOTE not a member of trait `Foo` + //~| NOTE not a member of trait `Bar` } fn main () { From 3fd5fdd8d3e64e957a7eafe3d6d0b10ef4170d59 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 24 Jul 2016 21:42:11 -0500 Subject: [PATCH 318/443] crate-ify compiler-rt into compiler-builtins libcompiler-rt.a is dead, long live libcompiler-builtins.rlib This commit moves the logic that used to build libcompiler-rt.a into a compiler-builtins crate on top of the core crate and below the std crate. This new crate still compiles the compiler-rt instrinsics using gcc-rs but produces an .rlib instead of a static library. Also, with this commit rustc no longer passes -lcompiler-rt to the linker. This effectively makes the "no-compiler-rt" field of target specifications a no-op. Users of `no_std` will have to explicitly add the compiler-builtins crate to their crate dependency graph *if* they need the compiler-rt intrinsics. Users of the `std` have to do nothing extra as the std crate depends on compiler-builtins. Finally, this a step towards lazy compilation of std with Cargo as the compiler-rt intrinsics can now be built by Cargo instead of having to be supplied by the user by some other method. closes #34400 --- mk/clean.mk | 1 - mk/crates.mk | 8 +- mk/main.mk | 5 +- mk/platform.mk | 2 - mk/rt.mk | 340 ++++++++------- src/bootstrap/clean.rs | 1 - src/bootstrap/compile.rs | 22 +- src/bootstrap/lib.rs | 11 - src/bootstrap/native.rs | 397 +---------------- src/bootstrap/step.rs | 5 +- src/libcompiler_builtins/Cargo.toml | 15 + src/libcompiler_builtins/build.rs | 402 ++++++++++++++++++ src/libcompiler_builtins/lib.rs | 16 + src/librustc/middle/cstore.rs | 2 + .../target/asmjs_unknown_emscripten.rs | 1 - src/librustc_back/target/le32_unknown_nacl.rs | 1 - src/librustc_back/target/mod.rs | 6 - src/librustc_metadata/csearch.rs | 4 + src/librustc_metadata/cstore.rs | 5 + src/librustc_trans/back/link.rs | 13 +- src/libstd/Cargo.toml | 1 + src/libstd/lib.rs | 3 + src/libsyntax/feature_gate.rs | 10 + src/rustc/std_shim/Cargo.lock | 9 + .../feature-gate-compiler-builtins.rs | 14 + 25 files changed, 693 insertions(+), 601 deletions(-) create mode 100644 src/libcompiler_builtins/Cargo.toml create mode 100644 src/libcompiler_builtins/build.rs create mode 100644 src/libcompiler_builtins/lib.rs create mode 100644 src/test/compile-fail/feature-gate-compiler-builtins.rs diff --git a/mk/clean.mk b/mk/clean.mk index ac34ac506bb1..3574f25d9b74 100644 --- a/mk/clean.mk +++ b/mk/clean.mk @@ -102,7 +102,6 @@ define CLEAN_TARGET_STAGE_N clean$(1)_T_$(2)_H_$(3): \ $$(foreach crate,$$(CRATES),clean$(1)_T_$(2)_H_$(3)-lib-$$(crate)) \ $$(foreach tool,$$(TOOLS) $$(DEBUGGER_BIN_SCRIPTS_ALL),clean$(1)_T_$(2)_H_$(3)-tool-$$(tool)) - $$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/libcompiler-rt.a $(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/librun_pass_stage* # For unix $(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/run_pass_stage* # For windows diff --git a/mk/crates.mk b/mk/crates.mk index 06ad07de136b..d2c79441d866 100644 --- a/mk/crates.mk +++ b/mk/crates.mk @@ -51,7 +51,7 @@ TARGET_CRATES := libc std term \ getopts collections test rand \ - core alloc \ + compiler_builtins core alloc \ rustc_unicode rustc_bitflags \ alloc_system alloc_jemalloc \ panic_abort panic_unwind unwind @@ -65,6 +65,7 @@ HOST_CRATES := syntax syntax_ext proc_macro syntax_pos $(RUSTC_CRATES) rustdoc f TOOLS := compiletest rustdoc rustc rustbook error_index_generator DEPS_core := +DEPS_compiler_builtins := core DEPS_alloc := core libc alloc_system DEPS_alloc_system := core libc DEPS_alloc_jemalloc := core libc native:jemalloc @@ -77,12 +78,14 @@ DEPS_panic_abort := libc alloc DEPS_panic_unwind := libc alloc unwind DEPS_unwind := libc +RUSTFLAGS_compiler_builtins := -lstatic=compiler-rt + # FIXME(stage0): change this to just `RUSTFLAGS_panic_abort := ...` RUSTFLAGS1_panic_abort := -C panic=abort RUSTFLAGS2_panic_abort := -C panic=abort RUSTFLAGS3_panic_abort := -C panic=abort -DEPS_std := core libc rand alloc collections rustc_unicode \ +DEPS_std := core libc rand alloc collections compiler_builtins rustc_unicode \ native:backtrace \ alloc_system panic_abort panic_unwind unwind DEPS_arena := std @@ -153,6 +156,7 @@ TOOL_SOURCE_rustc := $(S)src/driver/driver.rs TOOL_SOURCE_rustbook := $(S)src/tools/rustbook/main.rs TOOL_SOURCE_error_index_generator := $(S)src/tools/error_index_generator/main.rs +ONLY_RLIB_compiler_builtins := 1 ONLY_RLIB_core := 1 ONLY_RLIB_libc := 1 ONLY_RLIB_alloc := 1 diff --git a/mk/main.mk b/mk/main.mk index 6130b5813875..dd0136e13621 100644 --- a/mk/main.mk +++ b/mk/main.mk @@ -455,7 +455,10 @@ endif TSREQ$(1)_T_$(2)_H_$(3) = \ $$(HSREQ$(1)_H_$(3)) \ $$(foreach obj,$$(REQUIRED_OBJECTS_$(2)),\ - $$(TLIB$(1)_T_$(2)_H_$(3))/$$(obj)) + $$(TLIB$(1)_T_$(2)_H_$(3))/$$(obj)) \ + $$(TLIB0_T_$(2)_H_$(3))/libcompiler-rt.a +# ^ This copies `libcompiler-rt.a` to the stage0 sysroot +# ^ TODO(stage0) update this to not copy `libcompiler-rt.a` to stage0 # Prerequisites for a working stageN compiler and libraries, for a specific # target diff --git a/mk/platform.mk b/mk/platform.mk index d601cab7221f..6a7a20cbfdb9 100644 --- a/mk/platform.mk +++ b/mk/platform.mk @@ -102,8 +102,6 @@ include $(wildcard $(CFG_SRC_DIR)mk/cfg/*.mk) define ADD_INSTALLED_OBJECTS INSTALLED_OBJECTS_$(1) += $$(CFG_INSTALLED_OBJECTS_$(1)) REQUIRED_OBJECTS_$(1) += $$(CFG_THIRD_PARTY_OBJECTS_$(1)) - INSTALLED_OBJECTS_$(1) += $$(call CFG_STATIC_LIB_NAME_$(1),compiler-rt) - REQUIRED_OBJECTS_$(1) += $$(call CFG_STATIC_LIB_NAME_$(1),compiler-rt) endef $(foreach target,$(CFG_TARGET), \ diff --git a/mk/rt.mk b/mk/rt.mk index e86aec60893e..bcbed333e0f7 100644 --- a/mk/rt.mk +++ b/mk/rt.mk @@ -37,6 +37,16 @@ ################################################################################ NATIVE_LIBS := hoedown miniz rust_test_helpers +# A macro to add a generic implementation of intrinsics iff a arch optimized implementation is not +# already in the list. +# $(1) is the target +# $(2) is the intrinsic +define ADD_INTRINSIC + ifeq ($$(findstring X,$$(foreach intrinsic,$$(COMPRT_OBJS_$(1)),$$(if $$(findstring $(2),$$(intrinsic)),X,))),) + COMPRT_OBJS_$(1) += $(2) + endif +endef + # $(1) is the target triple define NATIVE_LIBRARIES @@ -230,167 +240,15 @@ COMPRT_NAME_$(1) := $$(call CFG_STATIC_LIB_NAME_$(1),compiler-rt) COMPRT_LIB_$(1) := $$(RT_OUTPUT_DIR_$(1))/$$(COMPRT_NAME_$(1)) COMPRT_BUILD_DIR_$(1) := $$(RT_OUTPUT_DIR_$(1))/compiler-rt -# GENERIC_SOURCES in CMakeLists.txt -COMPRT_OBJS_$(1) := \ - absvdi2.o \ - absvsi2.o \ - adddf3.o \ - addsf3.o \ - addvdi3.o \ - addvsi3.o \ - apple_versioning.o \ - ashldi3.o \ - ashrdi3.o \ - clear_cache.o \ - clzdi2.o \ - clzsi2.o \ - cmpdi2.o \ - comparedf2.o \ - comparesf2.o \ - ctzdi2.o \ - ctzsi2.o \ - divdc3.o \ - divdf3.o \ - divdi3.o \ - divmoddi4.o \ - divmodsi4.o \ - divsc3.o \ - divsf3.o \ - divsi3.o \ - divxc3.o \ - extendsfdf2.o \ - extendhfsf2.o \ - ffsdi2.o \ - fixdfdi.o \ - fixdfsi.o \ - fixsfdi.o \ - fixsfsi.o \ - fixunsdfdi.o \ - fixunsdfsi.o \ - fixunssfdi.o \ - fixunssfsi.o \ - fixunsxfdi.o \ - fixunsxfsi.o \ - fixxfdi.o \ - floatdidf.o \ - floatdisf.o \ - floatdixf.o \ - floatsidf.o \ - floatsisf.o \ - floatundidf.o \ - floatundisf.o \ - floatundixf.o \ - floatunsidf.o \ - floatunsisf.o \ - int_util.o \ - lshrdi3.o \ - moddi3.o \ - modsi3.o \ - muldc3.o \ - muldf3.o \ - muldi3.o \ - mulodi4.o \ - mulosi4.o \ - muloti4.o \ - mulsc3.o \ - mulsf3.o \ - mulvdi3.o \ - mulvsi3.o \ - mulxc3.o \ - negdf2.o \ - negdi2.o \ - negsf2.o \ - negvdi2.o \ - negvsi2.o \ - paritydi2.o \ - paritysi2.o \ - popcountdi2.o \ - popcountsi2.o \ - powidf2.o \ - powisf2.o \ - powixf2.o \ - subdf3.o \ - subsf3.o \ - subvdi3.o \ - subvsi3.o \ - truncdfhf2.o \ - truncdfsf2.o \ - truncsfhf2.o \ - ucmpdi2.o \ - udivdi3.o \ - udivmoddi4.o \ - udivmodsi4.o \ - udivsi3.o \ - umoddi3.o \ - umodsi3.o +# We must avoid compiling both a generic implementation (e.g. `floatdidf.c) and an arch optimized +# implementation (e.g. `x86_64/floatdidf.S) of the same symbol (e.g. `floatdidf) because that causes +# linker errors. To avoid that, we first add all the arch optimized implementations and then add the +# generic implementations if and only if its arch optimized version is not already in the list. This +# last part is handled by the ADD_INTRINSIC macro. -ifeq ($$(findstring ios,$(1)),) -COMPRT_OBJS_$(1) += \ - absvti2.o \ - addtf3.o \ - addvti3.o \ - ashlti3.o \ - ashrti3.o \ - clzti2.o \ - cmpti2.o \ - ctzti2.o \ - divtf3.o \ - divti3.o \ - ffsti2.o \ - fixdfti.o \ - fixsfti.o \ - fixunsdfti.o \ - fixunssfti.o \ - fixunsxfti.o \ - fixxfti.o \ - floattidf.o \ - floattisf.o \ - floattixf.o \ - floatuntidf.o \ - floatuntisf.o \ - floatuntixf.o \ - lshrti3.o \ - modti3.o \ - multf3.o \ - multi3.o \ - mulvti3.o \ - negti2.o \ - negvti2.o \ - parityti2.o \ - popcountti2.o \ - powitf2.o \ - subtf3.o \ - subvti3.o \ - trampoline_setup.o \ - ucmpti2.o \ - udivmodti4.o \ - udivti3.o \ - umodti3.o -endif - -ifeq ($$(findstring apple,$(1)),apple) -COMPRT_OBJS_$(1) += \ - atomic_flag_clear.o \ - atomic_flag_clear_explicit.o \ - atomic_flag_test_and_set.o \ - atomic_flag_test_and_set_explicit.o \ - atomic_signal_fence.o \ - atomic_thread_fence.o -endif - - -ifeq ($$(findstring windows,$(1)),) -COMPRT_OBJS_$(1) += emutls.o -endif +COMPRT_OBJS_$(1) := ifeq ($$(findstring msvc,$(1)),) - -ifeq ($$(findstring freebsd,$(1)),) -COMPRT_OBJS_$(1) += gcc_personality_v0.o -endif - -COMPRT_OBJS_$(1) += emutls.o - ifeq ($$(findstring x86_64,$(1)),x86_64) COMPRT_OBJS_$(1) += \ x86_64/chkstk.o \ @@ -540,9 +398,168 @@ COMPRT_OBJS_$(1) += \ arm/unordsf2vfp.o endif +$(foreach intrinsic,absvdi2.o \ + absvsi2.o \ + adddf3.o \ + addsf3.o \ + addvdi3.o \ + addvsi3.o \ + apple_versioning.o \ + ashldi3.o \ + ashrdi3.o \ + clear_cache.o \ + clzdi2.o \ + clzsi2.o \ + cmpdi2.o \ + comparedf2.o \ + comparesf2.o \ + ctzdi2.o \ + ctzsi2.o \ + divdc3.o \ + divdf3.o \ + divdi3.o \ + divmoddi4.o \ + divmodsi4.o \ + divsc3.o \ + divsf3.o \ + divsi3.o \ + divxc3.o \ + extendsfdf2.o \ + extendhfsf2.o \ + ffsdi2.o \ + fixdfdi.o \ + fixdfsi.o \ + fixsfdi.o \ + fixsfsi.o \ + fixunsdfdi.o \ + fixunsdfsi.o \ + fixunssfdi.o \ + fixunssfsi.o \ + fixunsxfdi.o \ + fixunsxfsi.o \ + fixxfdi.o \ + floatdidf.o \ + floatdisf.o \ + floatdixf.o \ + floatsidf.o \ + floatsisf.o \ + floatundidf.o \ + floatundisf.o \ + floatundixf.o \ + floatunsidf.o \ + floatunsisf.o \ + int_util.o \ + lshrdi3.o \ + moddi3.o \ + modsi3.o \ + muldc3.o \ + muldf3.o \ + muldi3.o \ + mulodi4.o \ + mulosi4.o \ + muloti4.o \ + mulsc3.o \ + mulsf3.o \ + mulvdi3.o \ + mulvsi3.o \ + mulxc3.o \ + negdf2.o \ + negdi2.o \ + negsf2.o \ + negvdi2.o \ + negvsi2.o \ + paritydi2.o \ + paritysi2.o \ + popcountdi2.o \ + popcountsi2.o \ + powidf2.o \ + powisf2.o \ + powixf2.o \ + subdf3.o \ + subsf3.o \ + subvdi3.o \ + subvsi3.o \ + truncdfhf2.o \ + truncdfsf2.o \ + truncsfhf2.o \ + ucmpdi2.o \ + udivdi3.o \ + udivmoddi4.o \ + udivmodsi4.o \ + udivsi3.o \ + umoddi3.o \ + umodsi3.o, + $(call ADD_INTRINSIC,$(1),$(intrinsic))) + +ifeq ($$(findstring ios,$(1)),) +$(foreach intrinsic,absvti2.o \ + addtf3.o \ + addvti3.o \ + ashlti3.o \ + ashrti3.o \ + clzti2.o \ + cmpti2.o \ + ctzti2.o \ + divtf3.o \ + divti3.o \ + ffsti2.o \ + fixdfti.o \ + fixsfti.o \ + fixunsdfti.o \ + fixunssfti.o \ + fixunsxfti.o \ + fixxfti.o \ + floattidf.o \ + floattisf.o \ + floattixf.o \ + floatuntidf.o \ + floatuntisf.o \ + floatuntixf.o \ + lshrti3.o \ + modti3.o \ + multf3.o \ + multi3.o \ + mulvti3.o \ + negti2.o \ + negvti2.o \ + parityti2.o \ + popcountti2.o \ + powitf2.o \ + subtf3.o \ + subvti3.o \ + trampoline_setup.o \ + ucmpti2.o \ + udivmodti4.o \ + udivti3.o \ + umodti3.o, + $(call ADD_INTRINSIC,$(1),$(intrinsic))) +endif + +ifeq ($$(findstring apple,$(1)),apple) +$(foreach intrinsic,atomic_flag_clear.o \ + atomic_flag_clear_explicit.o \ + atomic_flag_test_and_set.o \ + atomic_flag_test_and_set_explicit.o \ + atomic_signal_fence.o \ + atomic_thread_fence.o, + $(call ADD_INTRINSIC,$(1),$(intrinsic))) +endif + +ifeq ($$(findstring windows,$(1)),) +$(call ADD_INTRINSIC,$(1),emutls.o) +endif + +ifeq ($$(findstring msvc,$(1)),) + +ifeq ($$(findstring freebsd,$(1)),) +$(call ADD_INTRINSIC,$(1),gcc_personality_v0.o) +endif + +$(call ADD_INTRINSIC,$(1),emutls.o) +endif + ifeq ($$(findstring aarch64,$(1)),aarch64) -COMPRT_OBJS_$(1) += \ - comparetf2.o \ +$(foreach intrinsic,comparetf2.o \ extenddftf2.o \ extendsftf2.o \ fixtfdi.o \ @@ -557,7 +574,8 @@ COMPRT_OBJS_$(1) += \ floatunsitf.o \ multc3.o \ trunctfdf2.o \ - trunctfsf2.o + trunctfsf2.o, + $(call ADD_INTRINSIC,$(1),$(intrinsic))) endif ifeq ($$(findstring msvc,$(1)),msvc) diff --git a/src/bootstrap/clean.rs b/src/bootstrap/clean.rs index a466e2e6897f..a1e286e162ff 100644 --- a/src/bootstrap/clean.rs +++ b/src/bootstrap/clean.rs @@ -28,7 +28,6 @@ pub fn clean(build: &Build) { let out = build.out.join(host); - rm_rf(build, &out.join("compiler-rt")); rm_rf(build, &out.join("doc")); for stage in 0..4 { diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index e87669ba08ca..60bf52a514c3 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -35,13 +35,23 @@ pub fn std<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) { println!("Building stage{} std artifacts ({} -> {})", compiler.stage, compiler.host, target); - // Move compiler-rt into place as it'll be required by the compiler when - // building the standard library to link the dylib of libstd let libdir = build.sysroot_libdir(compiler, target); let _ = fs::remove_dir_all(&libdir); t!(fs::create_dir_all(&libdir)); - copy(&build.compiler_rt_built.borrow()[target], - &libdir.join(staticlib("compiler-rt", target))); + // FIXME(stage0) remove this `if` after the next snapshot + // The stage0 compiler still passes the `-lcompiler-rt` flag to the linker but now `bootstrap` + // never builds a `libcopmiler-rt.a`! We'll fill the hole by simply copying stage0's + // `libcompiler-rt.a` to where the stage1's one is expected (though we could as well just use + // an empty `.a` archive). Note that the symbols of that stage0 `libcompiler-rt.a` won't make + // it to the final binary because now `libcore.rlib` also contains the symbols that + // `libcompiler-rt.a` provides. Since that rlib appears first in the linker arguments, its + // symbols are used instead of `libcompiler-rt.a`'s. + if compiler.stage == 0 { + let rtlib = &staticlib("compiler-rt", target); + let src = build.rustc.parent().unwrap().parent().unwrap().join("lib").join("rustlib") + .join(target).join("lib").join(rtlib); + copy(&src, &libdir.join(rtlib)); + } // Some platforms have startup objects that may be required to produce the // libstd dynamic library, for example. @@ -83,12 +93,10 @@ pub fn std_link(build: &Build, // If we're linking one compiler host's output into another, then we weren't // called from the `std` method above. In that case we clean out what's - // already there and then also link compiler-rt into place. + // already there. if host != compiler.host { let _ = fs::remove_dir_all(&libdir); t!(fs::create_dir_all(&libdir)); - copy(&build.compiler_rt_built.borrow()[target], - &libdir.join(staticlib("compiler-rt", target))); } add_to_sysroot(&out_dir, &libdir); diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 94c14f7ea254..4beba5c8852b 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -28,7 +28,6 @@ extern crate rustc_serialize; extern crate toml; extern crate regex; -use std::cell::RefCell; use std::collections::HashMap; use std::env; use std::fs::{self, File}; @@ -131,7 +130,6 @@ pub struct Build { // Runtime state filled in later on cc: HashMap)>, cxx: HashMap, - compiler_rt_built: RefCell>, } /// The various "modes" of invoking Cargo. @@ -198,7 +196,6 @@ impl Build { package_vers: String::new(), cc: HashMap::new(), cxx: HashMap::new(), - compiler_rt_built: RefCell::new(HashMap::new()), gdb_version: None, lldb_version: None, lldb_python_dir: None, @@ -252,9 +249,6 @@ impl Build { Llvm { _dummy } => { native::llvm(self, target.target); } - CompilerRt { _dummy } => { - native::compiler_rt(self, target.target); - } TestHelpers { _dummy } => { native::test_helpers(self, target.target); } @@ -839,11 +833,6 @@ impl Build { } } - /// Root output directory for compiler-rt compiled for `target` - fn compiler_rt_out(&self, target: &str) -> PathBuf { - self.out.join(target).join("compiler-rt") - } - /// Root output directory for rust_test_helpers library compiled for /// `target` fn test_helpers_out(&self, target: &str) -> PathBuf { diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index a4518d6ed761..df6408e5fe1c 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -27,7 +27,7 @@ use cmake; use gcc; use Build; -use util::{staticlib, up_to_date}; +use util::up_to_date; /// Compile LLVM for `target`. pub fn llvm(build: &Build, target: &str) { @@ -131,401 +131,6 @@ fn check_llvm_version(build: &Build, llvm_config: &Path) { panic!("\n\nbad LLVM version: {}, need >=3.5\n\n", version) } -/// Compiles the `compiler-rt` library, or at least the builtins part of it. -/// -/// Note that while compiler-rt has a build system associated with it, we -/// specifically don't use it here. The compiler-rt build system, written in -/// CMake, is actually *very* difficult to work with in terms of getting it to -/// compile on all the relevant platforms we want it to compile on. In the end -/// it became so much pain to work with local patches, work around the oddities -/// of the build system, etc, that we're just building everything by hand now. -/// -/// In general compiler-rt is just a bunch of intrinsics that are in practice -/// *very* stable. We just need to make sure that all the relevant functions and -/// such are compiled somewhere and placed in an object file somewhere. -/// Eventually, these should all be written in Rust! -/// -/// So below you'll find a listing of every single file in the compiler-rt repo -/// that we're compiling. We just reach in and compile with the `gcc` crate -/// which should have all the relevant flags and such already configured. -/// -/// The risk here is that if we update compiler-rt we may need to compile some -/// new intrinsics, but to be honest we surely don't use all of the intrinsics -/// listed below today so the likelihood of us actually needing a new intrinsic -/// is quite low. The failure case is also just that someone reports a link -/// error (if any) and then we just add it to the list. Overall, that cost is -/// far far less than working with compiler-rt's build system over time. -pub fn compiler_rt(build: &Build, target: &str) { - let build_dir = build.compiler_rt_out(target); - let output = build_dir.join(staticlib("compiler-rt", target)); - build.compiler_rt_built.borrow_mut().insert(target.to_string(), - output.clone()); - t!(fs::create_dir_all(&build_dir)); - - let mut cfg = gcc::Config::new(); - cfg.cargo_metadata(false) - .out_dir(&build_dir) - .target(target) - .host(&build.config.build) - .opt_level(2) - .debug(false); - - if target.contains("msvc") { - // Don't pull in extra libraries on MSVC - cfg.flag("/Zl"); - - // Emulate C99 and C++11's __func__ for MSVC prior to 2013 CTP - cfg.define("__func__", Some("__FUNCTION__")); - } else { - // Turn off various features of gcc and such, mostly copying - // compiler-rt's build system already - cfg.flag("-fno-builtin"); - cfg.flag("-fvisibility=hidden"); - cfg.flag("-fomit-frame-pointer"); - cfg.flag("-ffreestanding"); - } - - let mut sources = vec![ - "absvdi2.c", - "absvsi2.c", - "adddf3.c", - "addsf3.c", - "addvdi3.c", - "addvsi3.c", - "apple_versioning.c", - "ashldi3.c", - "ashrdi3.c", - "clear_cache.c", - "clzdi2.c", - "clzsi2.c", - "cmpdi2.c", - "comparedf2.c", - "comparesf2.c", - "ctzdi2.c", - "ctzsi2.c", - "divdc3.c", - "divdf3.c", - "divdi3.c", - "divmoddi4.c", - "divmodsi4.c", - "divsc3.c", - "divsf3.c", - "divsi3.c", - "divxc3.c", - "extendsfdf2.c", - "extendhfsf2.c", - "ffsdi2.c", - "fixdfdi.c", - "fixdfsi.c", - "fixsfdi.c", - "fixsfsi.c", - "fixunsdfdi.c", - "fixunsdfsi.c", - "fixunssfdi.c", - "fixunssfsi.c", - "fixunsxfdi.c", - "fixunsxfsi.c", - "fixxfdi.c", - "floatdidf.c", - "floatdisf.c", - "floatdixf.c", - "floatsidf.c", - "floatsisf.c", - "floatundidf.c", - "floatundisf.c", - "floatundixf.c", - "floatunsidf.c", - "floatunsisf.c", - "int_util.c", - "lshrdi3.c", - "moddi3.c", - "modsi3.c", - "muldc3.c", - "muldf3.c", - "muldi3.c", - "mulodi4.c", - "mulosi4.c", - "muloti4.c", - "mulsc3.c", - "mulsf3.c", - "mulvdi3.c", - "mulvsi3.c", - "mulxc3.c", - "negdf2.c", - "negdi2.c", - "negsf2.c", - "negvdi2.c", - "negvsi2.c", - "paritydi2.c", - "paritysi2.c", - "popcountdi2.c", - "popcountsi2.c", - "powidf2.c", - "powisf2.c", - "powixf2.c", - "subdf3.c", - "subsf3.c", - "subvdi3.c", - "subvsi3.c", - "truncdfhf2.c", - "truncdfsf2.c", - "truncsfhf2.c", - "ucmpdi2.c", - "udivdi3.c", - "udivmoddi4.c", - "udivmodsi4.c", - "udivsi3.c", - "umoddi3.c", - "umodsi3.c", - ]; - - if !target.contains("ios") { - sources.extend(vec![ - "absvti2.c", - "addtf3.c", - "addvti3.c", - "ashlti3.c", - "ashrti3.c", - "clzti2.c", - "cmpti2.c", - "ctzti2.c", - "divtf3.c", - "divti3.c", - "ffsti2.c", - "fixdfti.c", - "fixsfti.c", - "fixunsdfti.c", - "fixunssfti.c", - "fixunsxfti.c", - "fixxfti.c", - "floattidf.c", - "floattisf.c", - "floattixf.c", - "floatuntidf.c", - "floatuntisf.c", - "floatuntixf.c", - "lshrti3.c", - "modti3.c", - "multf3.c", - "multi3.c", - "mulvti3.c", - "negti2.c", - "negvti2.c", - "parityti2.c", - "popcountti2.c", - "powitf2.c", - "subtf3.c", - "subvti3.c", - "trampoline_setup.c", - "ucmpti2.c", - "udivmodti4.c", - "udivti3.c", - "umodti3.c", - ]); - } - - if target.contains("apple") { - sources.extend(vec![ - "atomic_flag_clear.c", - "atomic_flag_clear_explicit.c", - "atomic_flag_test_and_set.c", - "atomic_flag_test_and_set_explicit.c", - "atomic_signal_fence.c", - "atomic_thread_fence.c", - ]); - } - - if !target.contains("windows") { - sources.push("emutls.c"); - } - - if target.contains("msvc") { - if target.contains("x86_64") { - sources.extend(vec![ - "x86_64/floatdidf.c", - "x86_64/floatdisf.c", - "x86_64/floatdixf.c", - ]); - } - } else { - if !target.contains("freebsd") { - sources.push("gcc_personality_v0.c"); - } - - if target.contains("x86_64") { - sources.extend(vec![ - "x86_64/chkstk.S", - "x86_64/chkstk2.S", - "x86_64/floatdidf.c", - "x86_64/floatdisf.c", - "x86_64/floatdixf.c", - "x86_64/floatundidf.S", - "x86_64/floatundisf.S", - "x86_64/floatundixf.S", - ]); - } - - if target.contains("i386") || - target.contains("i586") || - target.contains("i686") { - sources.extend(vec![ - "i386/ashldi3.S", - "i386/ashrdi3.S", - "i386/chkstk.S", - "i386/chkstk2.S", - "i386/divdi3.S", - "i386/floatdidf.S", - "i386/floatdisf.S", - "i386/floatdixf.S", - "i386/floatundidf.S", - "i386/floatundisf.S", - "i386/floatundixf.S", - "i386/lshrdi3.S", - "i386/moddi3.S", - "i386/muldi3.S", - "i386/udivdi3.S", - "i386/umoddi3.S", - ]); - } - } - - if target.contains("arm") && !target.contains("ios") { - sources.extend(vec![ - "arm/aeabi_cdcmp.S", - "arm/aeabi_cdcmpeq_check_nan.c", - "arm/aeabi_cfcmp.S", - "arm/aeabi_cfcmpeq_check_nan.c", - "arm/aeabi_dcmp.S", - "arm/aeabi_div0.c", - "arm/aeabi_drsub.c", - "arm/aeabi_fcmp.S", - "arm/aeabi_frsub.c", - "arm/aeabi_idivmod.S", - "arm/aeabi_ldivmod.S", - "arm/aeabi_memcmp.S", - "arm/aeabi_memcpy.S", - "arm/aeabi_memmove.S", - "arm/aeabi_memset.S", - "arm/aeabi_uidivmod.S", - "arm/aeabi_uldivmod.S", - "arm/bswapdi2.S", - "arm/bswapsi2.S", - "arm/clzdi2.S", - "arm/clzsi2.S", - "arm/comparesf2.S", - "arm/divmodsi4.S", - "arm/divsi3.S", - "arm/modsi3.S", - "arm/switch16.S", - "arm/switch32.S", - "arm/switch8.S", - "arm/switchu8.S", - "arm/sync_synchronize.S", - "arm/udivmodsi4.S", - "arm/udivsi3.S", - "arm/umodsi3.S", - ]); - } - - if target.contains("armv7") { - sources.extend(vec![ - "arm/sync_fetch_and_add_4.S", - "arm/sync_fetch_and_add_8.S", - "arm/sync_fetch_and_and_4.S", - "arm/sync_fetch_and_and_8.S", - "arm/sync_fetch_and_max_4.S", - "arm/sync_fetch_and_max_8.S", - "arm/sync_fetch_and_min_4.S", - "arm/sync_fetch_and_min_8.S", - "arm/sync_fetch_and_nand_4.S", - "arm/sync_fetch_and_nand_8.S", - "arm/sync_fetch_and_or_4.S", - "arm/sync_fetch_and_or_8.S", - "arm/sync_fetch_and_sub_4.S", - "arm/sync_fetch_and_sub_8.S", - "arm/sync_fetch_and_umax_4.S", - "arm/sync_fetch_and_umax_8.S", - "arm/sync_fetch_and_umin_4.S", - "arm/sync_fetch_and_umin_8.S", - "arm/sync_fetch_and_xor_4.S", - "arm/sync_fetch_and_xor_8.S", - ]); - } - - if target.contains("eabihf") { - sources.extend(vec![ - "arm/adddf3vfp.S", - "arm/addsf3vfp.S", - "arm/divdf3vfp.S", - "arm/divsf3vfp.S", - "arm/eqdf2vfp.S", - "arm/eqsf2vfp.S", - "arm/extendsfdf2vfp.S", - "arm/fixdfsivfp.S", - "arm/fixsfsivfp.S", - "arm/fixunsdfsivfp.S", - "arm/fixunssfsivfp.S", - "arm/floatsidfvfp.S", - "arm/floatsisfvfp.S", - "arm/floatunssidfvfp.S", - "arm/floatunssisfvfp.S", - "arm/gedf2vfp.S", - "arm/gesf2vfp.S", - "arm/gtdf2vfp.S", - "arm/gtsf2vfp.S", - "arm/ledf2vfp.S", - "arm/lesf2vfp.S", - "arm/ltdf2vfp.S", - "arm/ltsf2vfp.S", - "arm/muldf3vfp.S", - "arm/mulsf3vfp.S", - "arm/negdf2vfp.S", - "arm/negsf2vfp.S", - "arm/nedf2vfp.S", - "arm/nesf2vfp.S", - "arm/restore_vfp_d8_d15_regs.S", - "arm/save_vfp_d8_d15_regs.S", - "arm/subdf3vfp.S", - "arm/subsf3vfp.S", - "arm/truncdfsf2vfp.S", - "arm/unorddf2vfp.S", - "arm/unordsf2vfp.S", - ]); - } - - if target.contains("aarch64") { - sources.extend(vec![ - "comparetf2.c", - "extenddftf2.c", - "extendsftf2.c", - "fixtfdi.c", - "fixtfsi.c", - "fixtfti.c", - "fixunstfdi.c", - "fixunstfsi.c", - "fixunstfti.c", - "floatditf.c", - "floatsitf.c", - "floatunditf.c", - "floatunsitf.c", - "multc3.c", - "trunctfdf2.c", - "trunctfsf2.c", - ]); - } - - let mut out_of_date = false; - for src in sources { - let src = build.src.join("src/compiler-rt/lib/builtins").join(src); - out_of_date = out_of_date || !up_to_date(&src, &output); - cfg.file(src); - } - if !out_of_date { - return - } - cfg.compile("libcompiler-rt.a"); -} - /// Compiles the `rust_test_helpers.c` library which we used in various /// `run-pass` test suites for ABI testing. pub fn test_helpers(build: &Build, target: &str) { diff --git a/src/bootstrap/step.rs b/src/bootstrap/step.rs index 12929664886c..5f391b70fbe8 100644 --- a/src/bootstrap/step.rs +++ b/src/bootstrap/step.rs @@ -82,7 +82,6 @@ macro_rules! targets { // There aren't really any parameters to this, but empty structs // with braces are unstable so we just pick something that works. (llvm, Llvm { _dummy: () }), - (compiler_rt, CompilerRt { _dummy: () }), (test_helpers, TestHelpers { _dummy: () }), (debugger_scripts, DebuggerScripts { stage: u32 }), @@ -334,8 +333,7 @@ impl<'a> Step<'a> { vec![self.libstd(compiler)] } Source::Libstd { compiler } => { - vec![self.compiler_rt(()), - self.rustc(compiler.stage).target(compiler.host)] + vec![self.rustc(compiler.stage).target(compiler.host)] } Source::LibrustcLink { compiler, host } => { vec![self.librustc(compiler), @@ -348,7 +346,6 @@ impl<'a> Step<'a> { vec![self.libstd(compiler), self.target(host).rustc(compiler.stage)] } - Source::CompilerRt { _dummy } => Vec::new(), Source::Llvm { _dummy } => Vec::new(), Source::TestHelpers { _dummy } => Vec::new(), Source::DebuggerScripts { stage: _ } => Vec::new(), diff --git a/src/libcompiler_builtins/Cargo.toml b/src/libcompiler_builtins/Cargo.toml new file mode 100644 index 000000000000..a52873fc326b --- /dev/null +++ b/src/libcompiler_builtins/Cargo.toml @@ -0,0 +1,15 @@ +[package] +authors = ["The Rust Project Developers"] +build = "build.rs" +name = "compiler_builtins" +version = "0.0.0" + +[lib] +name = "compiler_builtins" +path = "lib.rs" + +[dependencies] +core = { path = "../libcore" } + +[build-dependencies] +gcc = "0.3.27" diff --git a/src/libcompiler_builtins/build.rs b/src/libcompiler_builtins/build.rs new file mode 100644 index 000000000000..fb8e45c1fe13 --- /dev/null +++ b/src/libcompiler_builtins/build.rs @@ -0,0 +1,402 @@ +// 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. + +//! Compiles the `compiler-rt` library, or at least the builtins part of it. +//! +//! Note that while compiler-rt has a build system associated with it, we +//! specifically don't use it here. The compiler-rt build system, written in +//! CMake, is actually *very* difficult to work with in terms of getting it to +//! compile on all the relevant platforms we want it to compile on. In the end +//! it became so much pain to work with local patches, work around the oddities +//! of the build system, etc, that we're just building everything by hand now. +//! +//! In general compiler-rt is just a bunch of intrinsics that are in practice +//! *very* stable. We just need to make sure that all the relevant functions and +//! such are compiled somewhere and placed in an object file somewhere. +//! Eventually, these should all be written in Rust! +//! +//! So below you'll find a listing of every single file in the compiler-rt repo +//! that we're compiling. We just reach in and compile with the `gcc` crate +//! which should have all the relevant flags and such already configured. +//! +//! The risk here is that if we update compiler-rt we may need to compile some +//! new intrinsics, but to be honest we surely don't use all of the intrinsics +//! listed below today so the likelihood of us actually needing a new intrinsic +//! is quite low. The failure case is also just that someone reports a link +//! error (if any) and then we just add it to the list. Overall, that cost is +//! far far less than working with compiler-rt's build system over time. + +extern crate gcc; + +use std::collections::BTreeMap; +use std::env; +use std::path::Path; + +struct Sources { + // SYMBOL -> PATH TO SOURCE + map: BTreeMap<&'static str, &'static str>, +} + +impl Sources { + fn new() -> Sources { + Sources { map: BTreeMap::new() } + } + + fn extend(&mut self, sources: &[&'static str]) { + // NOTE Some intrinsics have both a generic implementation (e.g. `floatdidf.c`) and an arch + // optimized implementation (`x86_64/floatdidf.c`). In those cases, we keep the arch + // optimized implementation and discard the generic implementation. If we don't and keep + // both implementations, the linker will yell at us about duplicate symbols! + for &src in sources { + let symbol = Path::new(src).file_stem().unwrap().to_str().unwrap(); + if src.contains("/") { + // Arch-optimized implementation (preferred) + self.map.insert(symbol, src); + } else { + // Generic implementation + if !self.map.contains_key(symbol) { + self.map.insert(symbol, src); + } + } + } + } +} + +fn main() { + let target = env::var("TARGET").unwrap(); + let cfg = &mut gcc::Config::new(); + + if target.contains("msvc") { + // Don't pull in extra libraries on MSVC + cfg.flag("/Zl"); + + // Emulate C99 and C++11's __func__ for MSVC prior to 2013 CTP + cfg.define("__func__", Some("__FUNCTION__")); + } else { + // Turn off various features of gcc and such, mostly copying + // compiler-rt's build system already + cfg.flag("-fno-builtin"); + cfg.flag("-fvisibility=hidden"); + cfg.flag("-fomit-frame-pointer"); + cfg.flag("-ffreestanding"); + } + + let mut sources = Sources::new(); + sources.extend(&["absvdi2.c", + "absvsi2.c", + "adddf3.c", + "addsf3.c", + "addvdi3.c", + "addvsi3.c", + "apple_versioning.c", + "ashldi3.c", + "ashrdi3.c", + "clear_cache.c", + "clzdi2.c", + "clzsi2.c", + "cmpdi2.c", + "comparedf2.c", + "comparesf2.c", + "ctzdi2.c", + "ctzsi2.c", + "divdc3.c", + "divdf3.c", + "divdi3.c", + "divmoddi4.c", + "divmodsi4.c", + "divsc3.c", + "divsf3.c", + "divsi3.c", + "divxc3.c", + "extendsfdf2.c", + "extendhfsf2.c", + "ffsdi2.c", + "fixdfdi.c", + "fixdfsi.c", + "fixsfdi.c", + "fixsfsi.c", + "fixunsdfdi.c", + "fixunsdfsi.c", + "fixunssfdi.c", + "fixunssfsi.c", + "fixunsxfdi.c", + "fixunsxfsi.c", + "fixxfdi.c", + "floatdidf.c", + "floatdisf.c", + "floatdixf.c", + "floatsidf.c", + "floatsisf.c", + "floatundidf.c", + "floatundisf.c", + "floatundixf.c", + "floatunsidf.c", + "floatunsisf.c", + "int_util.c", + "lshrdi3.c", + "moddi3.c", + "modsi3.c", + "muldc3.c", + "muldf3.c", + "muldi3.c", + "mulodi4.c", + "mulosi4.c", + "muloti4.c", + "mulsc3.c", + "mulsf3.c", + "mulvdi3.c", + "mulvsi3.c", + "mulxc3.c", + "negdf2.c", + "negdi2.c", + "negsf2.c", + "negvdi2.c", + "negvsi2.c", + "paritydi2.c", + "paritysi2.c", + "popcountdi2.c", + "popcountsi2.c", + "powidf2.c", + "powisf2.c", + "powixf2.c", + "subdf3.c", + "subsf3.c", + "subvdi3.c", + "subvsi3.c", + "truncdfhf2.c", + "truncdfsf2.c", + "truncsfhf2.c", + "ucmpdi2.c", + "udivdi3.c", + "udivmoddi4.c", + "udivmodsi4.c", + "udivsi3.c", + "umoddi3.c", + "umodsi3.c"]); + + if !target.contains("ios") { + sources.extend(&["absvti2.c", + "addtf3.c", + "addvti3.c", + "ashlti3.c", + "ashrti3.c", + "clzti2.c", + "cmpti2.c", + "ctzti2.c", + "divtf3.c", + "divti3.c", + "ffsti2.c", + "fixdfti.c", + "fixsfti.c", + "fixunsdfti.c", + "fixunssfti.c", + "fixunsxfti.c", + "fixxfti.c", + "floattidf.c", + "floattisf.c", + "floattixf.c", + "floatuntidf.c", + "floatuntisf.c", + "floatuntixf.c", + "lshrti3.c", + "modti3.c", + "multf3.c", + "multi3.c", + "mulvti3.c", + "negti2.c", + "negvti2.c", + "parityti2.c", + "popcountti2.c", + "powitf2.c", + "subtf3.c", + "subvti3.c", + "trampoline_setup.c", + "ucmpti2.c", + "udivmodti4.c", + "udivti3.c", + "umodti3.c"]); + } + + if target.contains("apple") { + sources.extend(&["atomic_flag_clear.c", + "atomic_flag_clear_explicit.c", + "atomic_flag_test_and_set.c", + "atomic_flag_test_and_set_explicit.c", + "atomic_signal_fence.c", + "atomic_thread_fence.c"]); + } + + if !target.contains("windows") { + sources.extend(&["emutls.c"]); + } + + if target.contains("msvc") { + if target.contains("x86_64") { + sources.extend(&["x86_64/floatdidf.c", "x86_64/floatdisf.c", "x86_64/floatdixf.c"]); + } + } else { + if !target.contains("freebsd") { + sources.extend(&["gcc_personality_v0.c"]); + } + + if target.contains("x86_64") { + sources.extend(&["x86_64/chkstk.S", + "x86_64/chkstk2.S", + "x86_64/floatdidf.c", + "x86_64/floatdisf.c", + "x86_64/floatdixf.c", + "x86_64/floatundidf.S", + "x86_64/floatundisf.S", + "x86_64/floatundixf.S"]); + } + + if target.contains("i386") || target.contains("i586") || target.contains("i686") { + sources.extend(&["i386/ashldi3.S", + "i386/ashrdi3.S", + "i386/chkstk.S", + "i386/chkstk2.S", + "i386/divdi3.S", + "i386/floatdidf.S", + "i386/floatdisf.S", + "i386/floatdixf.S", + "i386/floatundidf.S", + "i386/floatundisf.S", + "i386/floatundixf.S", + "i386/lshrdi3.S", + "i386/moddi3.S", + "i386/muldi3.S", + "i386/udivdi3.S", + "i386/umoddi3.S"]); + } + } + + if target.contains("arm") && !target.contains("ios") { + sources.extend(&["arm/aeabi_cdcmp.S", + "arm/aeabi_cdcmpeq_check_nan.c", + "arm/aeabi_cfcmp.S", + "arm/aeabi_cfcmpeq_check_nan.c", + "arm/aeabi_dcmp.S", + "arm/aeabi_div0.c", + "arm/aeabi_drsub.c", + "arm/aeabi_fcmp.S", + "arm/aeabi_frsub.c", + "arm/aeabi_idivmod.S", + "arm/aeabi_ldivmod.S", + "arm/aeabi_memcmp.S", + "arm/aeabi_memcpy.S", + "arm/aeabi_memmove.S", + "arm/aeabi_memset.S", + "arm/aeabi_uidivmod.S", + "arm/aeabi_uldivmod.S", + "arm/bswapdi2.S", + "arm/bswapsi2.S", + "arm/clzdi2.S", + "arm/clzsi2.S", + "arm/comparesf2.S", + "arm/divmodsi4.S", + "arm/divsi3.S", + "arm/modsi3.S", + "arm/switch16.S", + "arm/switch32.S", + "arm/switch8.S", + "arm/switchu8.S", + "arm/sync_synchronize.S", + "arm/udivmodsi4.S", + "arm/udivsi3.S", + "arm/umodsi3.S"]); + } + + if target.contains("armv7") { + sources.extend(&["arm/sync_fetch_and_add_4.S", + "arm/sync_fetch_and_add_8.S", + "arm/sync_fetch_and_and_4.S", + "arm/sync_fetch_and_and_8.S", + "arm/sync_fetch_and_max_4.S", + "arm/sync_fetch_and_max_8.S", + "arm/sync_fetch_and_min_4.S", + "arm/sync_fetch_and_min_8.S", + "arm/sync_fetch_and_nand_4.S", + "arm/sync_fetch_and_nand_8.S", + "arm/sync_fetch_and_or_4.S", + "arm/sync_fetch_and_or_8.S", + "arm/sync_fetch_and_sub_4.S", + "arm/sync_fetch_and_sub_8.S", + "arm/sync_fetch_and_umax_4.S", + "arm/sync_fetch_and_umax_8.S", + "arm/sync_fetch_and_umin_4.S", + "arm/sync_fetch_and_umin_8.S", + "arm/sync_fetch_and_xor_4.S", + "arm/sync_fetch_and_xor_8.S"]); + } + + if target.contains("eabihf") { + sources.extend(&["arm/adddf3vfp.S", + "arm/addsf3vfp.S", + "arm/divdf3vfp.S", + "arm/divsf3vfp.S", + "arm/eqdf2vfp.S", + "arm/eqsf2vfp.S", + "arm/extendsfdf2vfp.S", + "arm/fixdfsivfp.S", + "arm/fixsfsivfp.S", + "arm/fixunsdfsivfp.S", + "arm/fixunssfsivfp.S", + "arm/floatsidfvfp.S", + "arm/floatsisfvfp.S", + "arm/floatunssidfvfp.S", + "arm/floatunssisfvfp.S", + "arm/gedf2vfp.S", + "arm/gesf2vfp.S", + "arm/gtdf2vfp.S", + "arm/gtsf2vfp.S", + "arm/ledf2vfp.S", + "arm/lesf2vfp.S", + "arm/ltdf2vfp.S", + "arm/ltsf2vfp.S", + "arm/muldf3vfp.S", + "arm/mulsf3vfp.S", + "arm/negdf2vfp.S", + "arm/negsf2vfp.S", + "arm/nedf2vfp.S", + "arm/nesf2vfp.S", + "arm/restore_vfp_d8_d15_regs.S", + "arm/save_vfp_d8_d15_regs.S", + "arm/subdf3vfp.S", + "arm/subsf3vfp.S", + "arm/truncdfsf2vfp.S", + "arm/unorddf2vfp.S", + "arm/unordsf2vfp.S"]); + } + + if target.contains("aarch64") { + sources.extend(&["comparetf2.c", + "extenddftf2.c", + "extendsftf2.c", + "fixtfdi.c", + "fixtfsi.c", + "fixtfti.c", + "fixunstfdi.c", + "fixunstfsi.c", + "fixunstfti.c", + "floatditf.c", + "floatsitf.c", + "floatunditf.c", + "floatunsitf.c", + "multc3.c", + "trunctfdf2.c", + "trunctfsf2.c"]); + } + + for src in sources.map.values() { + cfg.file(Path::new("../compiler-rt/lib/builtins").join(src)); + } + + cfg.compile("libcompiler-rt.a"); +} diff --git a/src/libcompiler_builtins/lib.rs b/src/libcompiler_builtins/lib.rs new file mode 100644 index 000000000000..ad1d1edbeba2 --- /dev/null +++ b/src/libcompiler_builtins/lib.rs @@ -0,0 +1,16 @@ +// 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. + +#![cfg_attr(not(stage0), feature(compiler_builtins))] +#![no_std] +#![cfg_attr(not(stage0), compiler_builtins)] + +#![crate_name = "compiler_builtins"] +#![crate_type = "rlib"] diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index d1722ac6f2f7..b8465e63b1c8 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -210,6 +210,7 @@ pub trait CrateStore<'tcx> { fn is_explicitly_linked(&self, cnum: ast::CrateNum) -> bool; fn is_allocator(&self, cnum: ast::CrateNum) -> bool; fn is_panic_runtime(&self, cnum: ast::CrateNum) -> bool; + fn is_compiler_builtins(&self, cnum: ast::CrateNum) -> bool; fn panic_strategy(&self, cnum: ast::CrateNum) -> PanicStrategy; fn extern_crate(&self, cnum: ast::CrateNum) -> Option; fn crate_attrs(&self, cnum: ast::CrateNum) -> Vec; @@ -405,6 +406,7 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { fn is_explicitly_linked(&self, cnum: ast::CrateNum) -> bool { bug!("is_explicitly_linked") } fn is_allocator(&self, cnum: ast::CrateNum) -> bool { bug!("is_allocator") } fn is_panic_runtime(&self, cnum: ast::CrateNum) -> bool { bug!("is_panic_runtime") } + fn is_compiler_builtins(&self, cnum: ast::CrateNum) -> bool { bug!("is_compiler_builtins") } fn panic_strategy(&self, cnum: ast::CrateNum) -> PanicStrategy { bug!("panic_strategy") } diff --git a/src/librustc_back/target/asmjs_unknown_emscripten.rs b/src/librustc_back/target/asmjs_unknown_emscripten.rs index 07eb191471c4..9ccfdbb129c7 100644 --- a/src/librustc_back/target/asmjs_unknown_emscripten.rs +++ b/src/librustc_back/target/asmjs_unknown_emscripten.rs @@ -18,7 +18,6 @@ pub fn target() -> Result { dynamic_linking: false, executables: true, exe_suffix: ".js".to_string(), - no_compiler_rt: true, linker_is_gnu: true, allow_asm: false, obj_is_bitcode: true, diff --git a/src/librustc_back/target/le32_unknown_nacl.rs b/src/librustc_back/target/le32_unknown_nacl.rs index 25132f8a044d..9ba6591f587c 100644 --- a/src/librustc_back/target/le32_unknown_nacl.rs +++ b/src/librustc_back/target/le32_unknown_nacl.rs @@ -22,7 +22,6 @@ pub fn target() -> TargetResult { dynamic_linking: false, executables: true, exe_suffix: ".pexe".to_string(), - no_compiler_rt: false, linker_is_gnu: true, allow_asm: false, max_atomic_width: 32, diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs index d48370b23b69..1a26ffaf1e13 100644 --- a/src/librustc_back/target/mod.rs +++ b/src/librustc_back/target/mod.rs @@ -306,9 +306,6 @@ pub struct TargetOptions { pub allows_weak_linkage: bool, /// Whether the linker support rpaths or not. Defaults to false. pub has_rpath: bool, - /// Whether to disable linking to compiler-rt. Defaults to false, as LLVM - /// will emit references to the functions that compiler-rt provides. - pub no_compiler_rt: bool, /// Whether to disable linking to the default libraries, typically corresponds /// to `-nodefaultlibs`. Defaults to true. pub no_default_libraries: bool, @@ -381,7 +378,6 @@ impl Default for TargetOptions { linker_is_gnu: false, allows_weak_linkage: true, has_rpath: false, - no_compiler_rt: false, no_default_libraries: true, position_independent_executables: false, pre_link_objects_exe: Vec::new(), @@ -524,7 +520,6 @@ impl Target { key!(linker_is_gnu, bool); key!(allows_weak_linkage, bool); key!(has_rpath, bool); - key!(no_compiler_rt, bool); key!(no_default_libraries, bool); key!(position_independent_executables, bool); key!(archive_format); @@ -667,7 +662,6 @@ impl ToJson for Target { target_option_val!(linker_is_gnu); target_option_val!(allows_weak_linkage); target_option_val!(has_rpath); - target_option_val!(no_compiler_rt); target_option_val!(no_default_libraries); target_option_val!(position_independent_executables); target_option_val!(archive_format); diff --git a/src/librustc_metadata/csearch.rs b/src/librustc_metadata/csearch.rs index d7ca93235fdd..21cf3240321b 100644 --- a/src/librustc_metadata/csearch.rs +++ b/src/librustc_metadata/csearch.rs @@ -346,6 +346,10 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { self.get_crate_data(cnum).is_panic_runtime() } + fn is_compiler_builtins(&self, cnum: ast::CrateNum) -> bool { + self.get_crate_data(cnum).is_compiler_builtins() + } + fn panic_strategy(&self, cnum: ast::CrateNum) -> PanicStrategy { self.get_crate_data(cnum).panic_strategy() } diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs index 952d7008d0f2..bc3d92c11a1e 100644 --- a/src/librustc_metadata/cstore.rs +++ b/src/librustc_metadata/cstore.rs @@ -340,6 +340,11 @@ impl CrateMetadata { attr::contains_name(&attrs, "needs_panic_runtime") } + pub fn is_compiler_builtins(&self) -> bool { + let attrs = decoder::get_crate_attributes(self.data()); + attr::contains_name(&attrs, "compiler_builtins") + } + pub fn panic_strategy(&self) -> PanicStrategy { decoder::get_panic_strategy(self.data()) } diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index b970c63a2243..3ba12ddba293 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -573,10 +573,6 @@ fn write_rlib_bytecode_object_v1(writer: &mut Write, fn link_staticlib(sess: &Session, objects: &[PathBuf], out_filename: &Path, tempdir: &Path) { let mut ab = link_rlib(sess, None, objects, out_filename, tempdir); - if !sess.target.target.options.no_compiler_rt { - ab.add_native_library("compiler-rt"); - } - let mut all_native_libs = vec![]; each_linked_rlib(sess, &mut |cnum, path| { @@ -640,9 +636,6 @@ fn link_natively(sess: &Session, let mut linker = trans.linker_info.to_linker(&mut cmd, &sess); link_args(&mut *linker, sess, crate_type, tmpdir, objects, out_filename, outputs); - if !sess.target.target.options.no_compiler_rt { - linker.link_staticlib("compiler-rt"); - } } cmd.args(&sess.target.target.options.late_link_args); for obj in &sess.target.target.options.post_link_objects { @@ -939,6 +932,12 @@ fn add_upstream_rust_crates(cmd: &mut Linker, // symbols from the dylib. let src = sess.cstore.used_crate_source(cnum); match data[cnum as usize - 1] { + // We must always link the `compiler_builtins` crate statically. Even if it was already + // "included" in a dylib (e.g. `libstd` when `-C prefer-dynamic` is used) + _ if sess.cstore.is_compiler_builtins(cnum) => { + add_static_crate(cmd, sess, tmpdir, crate_type, + &src.rlib.unwrap().0, sess.cstore.is_no_builtins(cnum)) + } Linkage::NotLinked | Linkage::IncludedFromDylib => {} Linkage::Static => { diff --git a/src/libstd/Cargo.toml b/src/libstd/Cargo.toml index 3ce6841fdd4c..21e6acc37f3d 100644 --- a/src/libstd/Cargo.toml +++ b/src/libstd/Cargo.toml @@ -19,6 +19,7 @@ collections = { path = "../libcollections" } core = { path = "../libcore" } libc = { path = "../rustc/libc_shim" } rand = { path = "../librand" } +compiler_builtins = { path = "../libcompiler_builtins" } rustc_unicode = { path = "../librustc_unicode" } unwind = { path = "../libunwind" } diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 4a637b5cfcff..d227fb1404f4 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -322,6 +322,9 @@ extern crate unwind; #[cfg(stage0)] extern crate alloc_system; +// compiler-rt intrinsics +extern crate compiler_builtins; + // Make std testable by not duplicating lang items and other globals. See #2912 #[cfg(test)] extern crate std as realstd; diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 8b8a41fc2048..27b97a0ad665 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -298,6 +298,10 @@ declare_features! ( // elide `'static` lifetimes in `static`s and `const`s (active, static_in_const, "1.13.0", Some(35897)), + + // Used to identify the `compiler_builtins` crate + // rustc internal + (active, compiler_builtins, "1.13.0", None), ); declare_features! ( @@ -537,6 +541,12 @@ pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeGat libcore functions that are inlined \ across crates and will never be stable", cfg_fn!(rustc_attrs))), + ("compiler_builtins", Whitelisted, Gated("compiler_builtins", + "the `#[compiler_builtins]` attribute is used to \ + identify the `compiler_builtins` crate which \ + contains compiler-rt intrinsics and will never be \ + stable", + cfg_fn!(compiler_builtins))), ("allow_internal_unstable", Normal, Gated("allow_internal_unstable", EXPLAIN_ALLOW_INTERNAL_UNSTABLE, diff --git a/src/rustc/std_shim/Cargo.lock b/src/rustc/std_shim/Cargo.lock index d47b541b4c3b..747322b32f32 100644 --- a/src/rustc/std_shim/Cargo.lock +++ b/src/rustc/std_shim/Cargo.lock @@ -43,6 +43,14 @@ dependencies = [ "rustc_unicode 0.0.0", ] +[[package]] +name = "compiler_builtins" +version = "0.0.0" +dependencies = [ + "core 0.0.0", + "gcc 0.3.27 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "core" version = "0.0.0" @@ -100,6 +108,7 @@ dependencies = [ "alloc_system 0.0.0", "build_helper 0.1.0", "collections 0.0.0", + "compiler_builtins 0.0.0", "core 0.0.0", "gcc 0.3.27 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.0.0", diff --git a/src/test/compile-fail/feature-gate-compiler-builtins.rs b/src/test/compile-fail/feature-gate-compiler-builtins.rs new file mode 100644 index 000000000000..f9334f1d3b07 --- /dev/null +++ b/src/test/compile-fail/feature-gate-compiler-builtins.rs @@ -0,0 +1,14 @@ +// 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. + +#![compiler_builtins] //~ ERROR the `#[compiler_builtins]` attribute is + +fn main() {} + From e6da837e990a8617a3d90e906221bb32fa3fee38 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 4 Sep 2016 10:40:22 -0500 Subject: [PATCH 319/443] it's libcompiler-rt.lib on windows --- mk/main.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mk/main.mk b/mk/main.mk index dd0136e13621..275dbb55d748 100644 --- a/mk/main.mk +++ b/mk/main.mk @@ -456,7 +456,7 @@ TSREQ$(1)_T_$(2)_H_$(3) = \ $$(HSREQ$(1)_H_$(3)) \ $$(foreach obj,$$(REQUIRED_OBJECTS_$(2)),\ $$(TLIB$(1)_T_$(2)_H_$(3))/$$(obj)) \ - $$(TLIB0_T_$(2)_H_$(3))/libcompiler-rt.a + $$(TLIB0_T_$(2)_H_$(3))/$$(call CFG_STATIC_LIB_NAME_$(2),compiler-rt) # ^ This copies `libcompiler-rt.a` to the stage0 sysroot # ^ TODO(stage0) update this to not copy `libcompiler-rt.a` to stage0 From e5d0bb12ececde44cfe5bf67224a7557a5b5c8fb Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 4 Sep 2016 12:57:18 -0500 Subject: [PATCH 320/443] no emutls for you, windows --- mk/rt.mk | 2 -- 1 file changed, 2 deletions(-) diff --git a/mk/rt.mk b/mk/rt.mk index bcbed333e0f7..a67bded288e2 100644 --- a/mk/rt.mk +++ b/mk/rt.mk @@ -554,8 +554,6 @@ ifeq ($$(findstring msvc,$(1)),) ifeq ($$(findstring freebsd,$(1)),) $(call ADD_INTRINSIC,$(1),gcc_personality_v0.o) endif - -$(call ADD_INTRINSIC,$(1),emutls.o) endif ifeq ($$(findstring aarch64,$(1)),aarch64) From 521ffe9dbe8ed03ea8b2efdfe2b2bc1d6e1d7847 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sun, 4 Sep 2016 16:24:26 -0500 Subject: [PATCH 321/443] it's also compiler-rt.lib on windows-gnu --- src/bootstrap/util.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/util.rs b/src/bootstrap/util.rs index dfc1c7a243b5..6c0a32a54d91 100644 --- a/src/bootstrap/util.rs +++ b/src/bootstrap/util.rs @@ -23,7 +23,7 @@ use filetime::FileTime; /// Returns the `name` as the filename of a static library for `target`. pub fn staticlib(name: &str, target: &str) -> String { - if target.contains("windows-msvc") { + if target.contains("windows") { format!("{}.lib", name) } else { format!("lib{}.a", name) From 5798003438469313c0616270b8b285d9afbb4730 Mon Sep 17 00:00:00 2001 From: athulappadan Date: Tue, 13 Sep 2016 10:13:52 +0530 Subject: [PATCH 322/443] Doc correction: btree --- src/libcollections/btree/set.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcollections/btree/set.rs b/src/libcollections/btree/set.rs index 49da3aa480c3..fc2a7f825474 100644 --- a/src/libcollections/btree/set.rs +++ b/src/libcollections/btree/set.rs @@ -674,7 +674,7 @@ impl<'a, T: 'a + Ord + Copy> Extend<&'a T> for BTreeSet { #[stable(feature = "rust1", since = "1.0.0")] impl Default for BTreeSet { - /// Makes a empty `BTreeSet` with a reasonable choice of B. + /// Makes an empty `BTreeSet` with a reasonable choice of B. fn default() -> BTreeSet { BTreeSet::new() } From 194a91b0ce12d85a6a7ae1db20b3f4aa8408b80d Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 12 Sep 2016 21:46:35 -0700 Subject: [PATCH 323/443] rustbuild: Fix dependency tracking with new Cargo The recent Cargo update changed filenames, which broke a lot of incremental rustbuild builds. What it thought were the output files were indeed no longer the output files! (wreaking havoc). This commit updates this to stop guessing filenames of Cargo and just manage stamp files instead. --- src/bootstrap/compile.rs | 45 +++++++++++++++++++++++++++++++++------- src/bootstrap/lib.rs | 2 ++ 2 files changed, 39 insertions(+), 8 deletions(-) diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index e87669ba08ca..11fe5fe6caad 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -16,12 +16,14 @@ //! compiler. This module is also responsible for assembling the sysroot as it //! goes along from the output of the previous stage. +use std::cmp; use std::collections::HashMap; -use std::fs; +use std::fs::{self, File}; use std::path::{Path, PathBuf}; use std::process::Command; use build_helper::output; +use filetime::FileTime; use util::{exe, staticlib, libdir, mtime, is_dylib, copy}; use {Build, Compiler, Mode}; @@ -66,6 +68,7 @@ pub fn std<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) { } build.run(&mut cargo); + update_mtime(&libstd_stamp(build, compiler, target)); std_link(build, target, compiler, compiler.host); } @@ -141,11 +144,12 @@ pub fn test<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) { println!("Building stage{} test artifacts ({} -> {})", compiler.stage, compiler.host, target); let out_dir = build.cargo_out(compiler, Mode::Libtest, target); - build.clear_if_dirty(&out_dir, &libstd_shim(build, compiler, target)); + build.clear_if_dirty(&out_dir, &libstd_stamp(build, compiler, target)); let mut cargo = build.cargo(compiler, Mode::Libtest, target, "build"); cargo.arg("--manifest-path") .arg(build.src.join("src/rustc/test_shim/Cargo.toml")); build.run(&mut cargo); + update_mtime(&libtest_stamp(build, compiler, target)); test_link(build, target, compiler, compiler.host); } @@ -173,7 +177,7 @@ pub fn rustc<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) { compiler.stage, compiler.host, target); let out_dir = build.cargo_out(compiler, Mode::Librustc, target); - build.clear_if_dirty(&out_dir, &libtest_shim(build, compiler, target)); + build.clear_if_dirty(&out_dir, &libtest_stamp(build, compiler, target)); let mut cargo = build.cargo(compiler, Mode::Librustc, target, "build"); cargo.arg("--features").arg(build.rustc_features()) @@ -238,14 +242,14 @@ pub fn rustc_link(build: &Build, /// Cargo's output path for the standard library in a given stage, compiled /// by a particular compiler for the specified target. -fn libstd_shim(build: &Build, compiler: &Compiler, target: &str) -> PathBuf { - build.cargo_out(compiler, Mode::Libstd, target).join("libstd_shim.rlib") +fn libstd_stamp(build: &Build, compiler: &Compiler, target: &str) -> PathBuf { + build.cargo_out(compiler, Mode::Libstd, target).join(".libstd.stamp") } /// Cargo's output path for libtest in a given stage, compiled by a particular /// compiler for the specified target. -fn libtest_shim(build: &Build, compiler: &Compiler, target: &str) -> PathBuf { - build.cargo_out(compiler, Mode::Libtest, target).join("libtest_shim.rlib") +fn libtest_stamp(build: &Build, compiler: &Compiler, target: &str) -> PathBuf { + build.cargo_out(compiler, Mode::Libtest, target).join(".libtest.stamp") } fn compiler_file(compiler: &Path, file: &str) -> PathBuf { @@ -358,10 +362,35 @@ pub fn tool(build: &Build, stage: u32, host: &str, tool: &str) { // Maybe when libstd is compiled it should clear out the rustc of the // corresponding stage? // let out_dir = build.cargo_out(stage, &host, Mode::Librustc, target); - // build.clear_if_dirty(&out_dir, &libstd_shim(build, stage, &host, target)); + // build.clear_if_dirty(&out_dir, &libstd_stamp(build, stage, &host, target)); let mut cargo = build.cargo(&compiler, Mode::Tool, host, "build"); cargo.arg("--manifest-path") .arg(build.src.join(format!("src/tools/{}/Cargo.toml", tool))); build.run(&mut cargo); } + +/// Updates the mtime of a stamp file if necessary, only changing it if it's +/// older than some other file in the same directory. +/// +/// We don't know what file Cargo is going to output (because there's a hash in +/// the file name) but we know where it's going to put it. We use this helper to +/// detect changes to that output file by looking at the modification time for +/// all files in a directory and updating the stamp if any are newer. +fn update_mtime(path: &Path) { + let mut max = None; + if let Ok(entries) = path.parent().unwrap().read_dir() { + for entry in entries.map(|e| t!(e)) { + if t!(entry.file_type()).is_file() { + let meta = t!(entry.metadata()); + let time = FileTime::from_last_modification_time(&meta); + max = cmp::max(max, Some(time)); + } + } + } + + if !max.is_none() && max <= Some(mtime(path)) { + return + } + t!(File::create(path)); +} diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 94c14f7ea254..c2dbfe1bbc58 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -585,6 +585,8 @@ impl Build { if mtime(&stamp) < mtime(input) { self.verbose(&format!("Dirty - {}", dir.display())); let _ = fs::remove_dir_all(dir); + } else if stamp.exists() { + return } t!(fs::create_dir_all(dir)); t!(File::create(stamp)); From 2140c4ba36301a71f43f4d488c45bc8ca27bf386 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 12 Sep 2016 21:24:40 -0700 Subject: [PATCH 324/443] rustc: Always link compiler-builtins last All crates depend on compiler-builtins, so we need to always include the crate last. --- src/librustc_trans/back/link.rs | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index 3ba12ddba293..3433b866691c 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -926,17 +926,19 @@ fn add_upstream_rust_crates(cmd: &mut Linker, // crates. let deps = sess.cstore.used_crates(LinkagePreference::RequireDynamic); + let mut compiler_builtins = None; + for &(cnum, _) in &deps { // We may not pass all crates through to the linker. Some crates may // appear statically in an existing dylib, meaning we'll pick up all the // symbols from the dylib. let src = sess.cstore.used_crate_source(cnum); match data[cnum as usize - 1] { - // We must always link the `compiler_builtins` crate statically. Even if it was already - // "included" in a dylib (e.g. `libstd` when `-C prefer-dynamic` is used) + // compiler-builtins are always placed last to ensure that they're + // linked correctly. _ if sess.cstore.is_compiler_builtins(cnum) => { - add_static_crate(cmd, sess, tmpdir, crate_type, - &src.rlib.unwrap().0, sess.cstore.is_no_builtins(cnum)) + assert!(compiler_builtins.is_none()); + compiler_builtins = Some(cnum); } Linkage::NotLinked | Linkage::IncludedFromDylib => {} @@ -950,6 +952,15 @@ fn add_upstream_rust_crates(cmd: &mut Linker, } } + // We must always link the `compiler_builtins` crate statically. Even if it + // was already "included" in a dylib (e.g. `libstd` when `-C prefer-dynamic` + // is used) + if let Some(cnum) = compiler_builtins { + let src = sess.cstore.used_crate_source(cnum); + add_static_crate(cmd, sess, tmpdir, crate_type, + &src.rlib.unwrap().0, sess.cstore.is_no_builtins(cnum)); + } + // Converts a library file-stem into a cc -l argument fn unlib<'a>(config: &config::Config, stem: &'a str) -> &'a str { if stem.starts_with("lib") && !config.target.options.is_like_windows { From 50f94f6c95c944f08c4af264f48260e42efefd47 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Fri, 2 Sep 2016 22:01:35 +0000 Subject: [PATCH 325/443] Avoid needless reexpansions. --- src/libsyntax/ext/base.rs | 15 ++++++++++----- src/libsyntax_ext/format.rs | 19 ++++++++----------- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index edd38ea23e2f..f6eb6f1da4f1 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -13,7 +13,7 @@ pub use self::SyntaxExtension::*; use ast; use ast::{Name, PatKind}; use attr::HasAttrs; -use codemap::{self, CodeMap, ExpnInfo}; +use codemap::{self, CodeMap, ExpnInfo, Spanned, respan}; use syntax_pos::{Span, ExpnId, NO_EXPANSION}; use errors::DiagnosticBuilder; use ext; @@ -805,8 +805,8 @@ impl<'a> ExtCtxt<'a> { /// Extract a string literal from the macro expanded version of `expr`, /// emitting `err_msg` if `expr` is not a string literal. This does not stop /// compilation on error, merely emits a non-fatal error and returns None. -pub fn expr_to_string(cx: &mut ExtCtxt, expr: P, err_msg: &str) - -> Option<(InternedString, ast::StrStyle)> { +pub fn expr_to_spanned_string(cx: &mut ExtCtxt, expr: P, err_msg: &str) + -> Option> { // Update `expr.span`'s expn_id now in case expr is an `include!` macro invocation. let expr = expr.map(|mut expr| { expr.span.expn_id = cx.backtrace; @@ -817,7 +817,7 @@ pub fn expr_to_string(cx: &mut ExtCtxt, expr: P, err_msg: &str) let expr = cx.expander().fold_expr(expr); match expr.node { ast::ExprKind::Lit(ref l) => match l.node { - ast::LitKind::Str(ref s, style) => return Some(((*s).clone(), style)), + ast::LitKind::Str(ref s, style) => return Some(respan(expr.span, (s.clone(), style))), _ => cx.span_err(l.span, err_msg) }, _ => cx.span_err(expr.span, err_msg) @@ -825,6 +825,11 @@ pub fn expr_to_string(cx: &mut ExtCtxt, expr: P, err_msg: &str) None } +pub fn expr_to_string(cx: &mut ExtCtxt, expr: P, err_msg: &str) + -> Option<(InternedString, ast::StrStyle)> { + expr_to_spanned_string(cx, expr, err_msg).map(|s| s.node) +} + /// Non-fatally assert that `tts` is empty. Note that this function /// returns even when `tts` is non-empty, macros that *need* to stop /// compilation should call @@ -851,7 +856,7 @@ pub fn get_single_str_from_tts(cx: &mut ExtCtxt, cx.span_err(sp, &format!("{} takes 1 argument", name)); return None } - let ret = cx.expander().fold_expr(panictry!(p.parse_expr())); + let ret = panictry!(p.parse_expr()); if p.token != token::Eof { cx.span_err(sp, &format!("{} takes 1 argument", name)); } diff --git a/src/libsyntax_ext/format.rs b/src/libsyntax_ext/format.rs index 06b16095d196..892ebcfa7612 100644 --- a/src/libsyntax_ext/format.rs +++ b/src/libsyntax_ext/format.rs @@ -17,7 +17,6 @@ use syntax::ast; use syntax::ext::base::*; use syntax::ext::base; use syntax::ext::build::AstBuilder; -use syntax::fold::Folder; use syntax::parse::token::{self, keywords}; use syntax::ptr::P; use syntax_pos::{Span, DUMMY_SP}; @@ -702,10 +701,12 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, let arg_types: Vec<_> = (0..args.len()).map(|_| Vec::new()).collect(); let arg_unique_types: Vec<_> = (0..args.len()).map(|_| Vec::new()).collect(); let macsp = ecx.call_site(); - // Expand the format literal so that efmt.span will have a backtrace. This - // is essential for locating a bug when the format literal is generated in - // a macro. (e.g. println!("{}"), which uses concat!($fmt, "\n")). - let efmt = ecx.expander().fold_expr(efmt); + let msg = "format argument must be a string literal."; + let fmt = match expr_to_spanned_string(ecx, efmt, msg) { + Some(fmt) => fmt, + None => return DummyResult::raw_expr(sp), + }; + let mut cx = Context { ecx: ecx, args: args, @@ -723,14 +724,10 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, str_pieces: Vec::new(), all_pieces_simple: true, macsp: macsp, - fmtsp: efmt.span, - }; - let fmt = match expr_to_string(cx.ecx, efmt, "format argument must be a string literal.") { - Some((fmt, _)) => fmt, - None => return DummyResult::raw_expr(sp), + fmtsp: fmt.span, }; - let mut parser = parse::Parser::new(&fmt); + let mut parser = parse::Parser::new(&fmt.node.0); let mut pieces = vec![]; loop { From 60440b226d2f70bdae803443ff7ad2e2af2c9b10 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Sun, 4 Sep 2016 22:49:45 +0000 Subject: [PATCH 326/443] Refactor `noop_fold_stmt_kind` out of `noop_fold_stmt`. --- src/libsyntax/fold.rs | 50 +++++++++++-------------------------------- 1 file changed, 13 insertions(+), 37 deletions(-) diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 7500bfe9caa8..9fb4d0203f41 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -1320,51 +1320,27 @@ pub fn noop_fold_exprs(es: Vec>, folder: &mut T) -> Vec(Stmt {node, span, id}: Stmt, folder: &mut T) - -> SmallVector { +pub fn noop_fold_stmt(Stmt {node, span, id}: Stmt, folder: &mut T) -> SmallVector { let id = folder.new_id(id); let span = folder.new_span(span); + noop_fold_stmt_kind(node, folder).into_iter().map(|node| { + Stmt { id: id, node: node, span: span } + }).collect() +} +pub fn noop_fold_stmt_kind(node: StmtKind, folder: &mut T) -> SmallVector { match node { - StmtKind::Local(local) => SmallVector::one(Stmt { - id: id, - node: StmtKind::Local(folder.fold_local(local)), - span: span, - }), - StmtKind::Item(item) => folder.fold_item(item).into_iter().map(|item| Stmt { - id: id, - node: StmtKind::Item(item), - span: span, - }).collect(), + StmtKind::Local(local) => SmallVector::one(StmtKind::Local(folder.fold_local(local))), + StmtKind::Item(item) => folder.fold_item(item).into_iter().map(StmtKind::Item).collect(), StmtKind::Expr(expr) => { - if let Some(expr) = folder.fold_opt_expr(expr) { - SmallVector::one(Stmt { - id: id, - node: StmtKind::Expr(expr), - span: span, - }) - } else { - SmallVector::zero() - } + folder.fold_opt_expr(expr).into_iter().map(StmtKind::Expr).collect() } StmtKind::Semi(expr) => { - if let Some(expr) = folder.fold_opt_expr(expr) { - SmallVector::one(Stmt { - id: id, - node: StmtKind::Semi(expr), - span: span, - }) - } else { - SmallVector::zero() - } + folder.fold_opt_expr(expr).into_iter().map(StmtKind::Semi).collect() } - StmtKind::Mac(mac) => SmallVector::one(Stmt { - id: id, - node: StmtKind::Mac(mac.map(|(mac, semi, attrs)| { - (folder.fold_mac(mac), semi, fold_attrs(attrs.into(), folder).into()) - })), - span: span, - }) + StmtKind::Mac(mac) => SmallVector::one(StmtKind::Mac(mac.map(|(mac, semi, attrs)| { + (folder.fold_mac(mac), semi, fold_attrs(attrs.into(), folder).into()) + }))), } } From a9821e1658240bb2c056f260a4b6bc9789301fae Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Mon, 5 Sep 2016 03:46:05 +0000 Subject: [PATCH 327/443] Refactor `ExtCtxt` to use a `Resolver` instead of a `MacroLoader`. --- src/librustc/middle/cstore.rs | 4 ++++ src/librustc_driver/driver.rs | 15 +++++++-------- src/librustc_metadata/macro_import.rs | 4 ++-- src/librustc_resolve/lib.rs | 18 +++++++++++++++++- src/libsyntax/ext/base.rs | 12 ++++++------ src/libsyntax/ext/expand.rs | 12 ++++++------ src/libsyntax/test.rs | 6 +++--- src/libsyntax_ext/rustc_macro_registrar.rs | 4 ++-- src/test/compile-fail-fulldeps/qquote.rs | 4 ++-- src/test/run-fail-fulldeps/qquote.rs | 4 ++-- src/test/run-pass-fulldeps/qquote.rs | 4 ++-- 11 files changed, 53 insertions(+), 34 deletions(-) diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index b33bc520fe21..5bbc0cd9d907 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -39,6 +39,7 @@ use std::rc::Rc; use std::path::PathBuf; use syntax::ast; use syntax::attr; +use syntax::ext::base::LoadedMacro; use syntax::ptr::P; use syntax::parse::token::InternedString; use syntax_pos::Span; @@ -488,6 +489,9 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { fn metadata_encoding_version(&self) -> &[u8] { bug!("metadata_encoding_version") } } +pub trait MacroLoader { + fn load_crate(&mut self, extern_crate: &ast::Item, allows_macros: bool) -> Vec; +} /// Metadata encoding and decoding can make use of thread-local encoding and /// decoding contexts. These allow implementers of serialize::Encodable and diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index ba6c4b9b84c3..0d9bf14f12fb 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -638,6 +638,12 @@ pub fn phase_2_configure_and_expand<'a, F>(sess: &Session, } sess.track_errors(|| sess.lint_store.borrow_mut().process_command_line(sess))?; + let mut macro_loader = + macro_import::MacroLoader::new(sess, &cstore, crate_name, krate.config.clone()); + + let resolver_arenas = Resolver::arenas(); + let mut resolver = Resolver::new(sess, make_glob_map, &mut macro_loader, &resolver_arenas); + krate = time(time_passes, "expansion", || { // Windows dlls do not have rpaths, so they don't know how to find their // dependencies. It's up to us to tell the system where to find all the @@ -672,14 +678,10 @@ pub fn phase_2_configure_and_expand<'a, F>(sess: &Session, trace_mac: sess.opts.debugging_opts.trace_macros, should_test: sess.opts.test, }; - let mut loader = macro_import::MacroLoader::new(sess, - &cstore, - crate_name, - krate.config.clone()); let mut ecx = syntax::ext::base::ExtCtxt::new(&sess.parse_sess, krate.config.clone(), cfg, - &mut loader); + &mut resolver); syntax_ext::register_builtins(&mut ecx.syntax_env); let ret = syntax::ext::expand::expand_crate(&mut ecx, syntax_exts, krate); if cfg!(windows) { @@ -708,9 +710,6 @@ pub fn phase_2_configure_and_expand<'a, F>(sess: &Session, &sess.features.borrow()) }); - let resolver_arenas = Resolver::arenas(); - let mut resolver = Resolver::new(sess, make_glob_map, &resolver_arenas); - let krate = time(sess.time_passes(), "assigning node ids", || resolver.assign_node_ids(krate)); if sess.opts.debugging_opts.input_stats { diff --git a/src/librustc_metadata/macro_import.rs b/src/librustc_metadata/macro_import.rs index 22691975050e..e41f076d64a8 100644 --- a/src/librustc_metadata/macro_import.rs +++ b/src/librustc_metadata/macro_import.rs @@ -18,6 +18,7 @@ use creader::{CrateReader, Macros}; use cstore::CStore; use rustc::hir::def_id::DefIndex; +use rustc::middle; use rustc::session::Session; use rustc::util::nodemap::FnvHashMap; use rustc_back::dynamic_lib::DynamicLibrary; @@ -26,7 +27,6 @@ use rustc_macro::__internal::Registry; use syntax::ast; use syntax::attr; use syntax::ext::base::LoadedMacro; -use syntax::ext; use syntax::parse::token; use syntax_ext::deriving::custom::CustomDerive; use syntax_pos::Span; @@ -55,7 +55,7 @@ pub fn call_bad_macro_reexport(a: &Session, b: Span) { pub type MacroSelection = FnvHashMap; -impl<'a> ext::base::MacroLoader for MacroLoader<'a> { +impl<'a> middle::cstore::MacroLoader for MacroLoader<'a> { fn load_crate(&mut self, extern_crate: &ast::Item, allows_macros: bool) -> Vec { diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index c5b505fba38e..c1e6d93a970e 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -45,6 +45,7 @@ use self::ParentLink::*; use rustc::hir::map::Definitions; use rustc::hir::{self, PrimTy, TyBool, TyChar, TyFloat, TyInt, TyUint, TyStr}; +use rustc::middle::cstore::MacroLoader; use rustc::session::Session; use rustc::lint; use rustc::hir::def::*; @@ -53,6 +54,8 @@ use rustc::ty; use rustc::hir::{Freevar, FreevarMap, TraitCandidate, TraitMap, GlobMap}; use rustc::util::nodemap::{NodeMap, NodeSet, FnvHashMap, FnvHashSet}; +use syntax::ext; +use syntax::ext::base::LoadedMacro; use syntax::ext::hygiene::Mark; use syntax::ast::{self, FloatTy}; use syntax::ast::{CRATE_NODE_ID, Name, NodeId, CrateNum, IntTy, UintTy}; @@ -1068,6 +1071,8 @@ pub struct Resolver<'a> { arenas: &'a ResolverArenas<'a>, dummy_binding: &'a NameBinding<'a>, new_import_semantics: bool, // true if `#![feature(item_like_imports)]` + + macro_loader: &'a mut MacroLoader, } pub struct ResolverArenas<'a> { @@ -1149,6 +1154,12 @@ impl<'a> hir::lowering::Resolver for Resolver<'a> { } } +impl<'a> ext::base::Resolver for Resolver<'a> { + fn load_crate(&mut self, extern_crate: &ast::Item, allows_macros: bool) -> Vec { + self.macro_loader.load_crate(extern_crate, allows_macros) + } +} + trait Named { fn name(&self) -> Name; } @@ -1166,7 +1177,10 @@ impl Named for hir::PathSegment { } impl<'a> Resolver<'a> { - pub fn new(session: &'a Session, make_glob_map: MakeGlobMap, arenas: &'a ResolverArenas<'a>) + pub fn new(session: &'a Session, + make_glob_map: MakeGlobMap, + macro_loader: &'a mut MacroLoader, + arenas: &'a ResolverArenas<'a>) -> Resolver<'a> { let root_def_id = DefId::local(CRATE_DEF_INDEX); let graph_root = @@ -1227,6 +1241,8 @@ impl<'a> Resolver<'a> { vis: ty::Visibility::Public, }), new_import_semantics: session.features.borrow().item_like_imports, + + macro_loader: macro_loader, } } diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index f6eb6f1da4f1..d0e11643c64c 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -546,7 +546,7 @@ fn initial_syntax_expander_table<'feat>(ecfg: &expand::ExpansionConfig<'feat>) syntax_expanders } -pub trait MacroLoader { +pub trait Resolver { fn load_crate(&mut self, extern_crate: &ast::Item, allows_macros: bool) -> Vec; } @@ -556,8 +556,8 @@ pub enum LoadedMacro { CustomDerive(String, Box), } -pub struct DummyMacroLoader; -impl MacroLoader for DummyMacroLoader { +pub struct DummyResolver; +impl Resolver for DummyResolver { fn load_crate(&mut self, _: &ast::Item, _: bool) -> Vec { Vec::new() } @@ -572,7 +572,7 @@ pub struct ExtCtxt<'a> { pub backtrace: ExpnId, pub ecfg: expand::ExpansionConfig<'a>, pub crate_root: Option<&'static str>, - pub loader: &'a mut MacroLoader, + pub resolver: &'a mut Resolver, pub exported_macros: Vec, @@ -584,7 +584,7 @@ pub struct ExtCtxt<'a> { impl<'a> ExtCtxt<'a> { pub fn new(parse_sess: &'a parse::ParseSess, cfg: ast::CrateConfig, ecfg: expand::ExpansionConfig<'a>, - loader: &'a mut MacroLoader) + resolver: &'a mut Resolver) -> ExtCtxt<'a> { ExtCtxt { syntax_env: initial_syntax_expander_table(&ecfg), @@ -594,7 +594,7 @@ impl<'a> ExtCtxt<'a> { ecfg: ecfg, crate_root: None, exported_macros: Vec::new(), - loader: loader, + resolver: resolver, derive_modes: HashMap::new(), recursion_count: 0, } diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 4715eda83749..44db1dd17ae6 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -644,7 +644,7 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { // We need to error on `#[macro_use] extern crate` when it isn't at the // crate root, because `$crate` won't work properly. let is_crate_root = self.cx.syntax_env.is_crate_root(); - for def in self.cx.loader.load_crate(&*item, is_crate_root) { + for def in self.cx.resolver.load_crate(&*item, is_crate_root) { match def { LoadedMacro::Def(def) => self.cx.insert_macro(def), LoadedMacro::CustomDerive(name, ext) => { @@ -809,7 +809,7 @@ fn mark_tts(tts: &[TokenTree], m: Mark) -> Vec { mod tests { use super::{expand_crate, ExpansionConfig}; use ast; - use ext::base::{ExtCtxt, DummyMacroLoader}; + use ext::base::{ExtCtxt, DummyResolver}; use parse; use util::parser_testing::{string_to_parser}; use visit; @@ -850,7 +850,7 @@ mod tests { src, Vec::new(), &sess).unwrap(); // should fail: - let mut loader = DummyMacroLoader; + let mut loader = DummyResolver; let mut ecx = ExtCtxt::new(&sess, vec![], test_ecfg(), &mut loader); expand_crate(&mut ecx, vec![], crate_ast); } @@ -865,7 +865,7 @@ mod tests { "".to_string(), src, Vec::new(), &sess).unwrap(); - let mut loader = DummyMacroLoader; + let mut loader = DummyResolver; let mut ecx = ExtCtxt::new(&sess, vec![], test_ecfg(), &mut loader); expand_crate(&mut ecx, vec![], crate_ast); } @@ -879,7 +879,7 @@ mod tests { "".to_string(), src, Vec::new(), &sess).unwrap(); - let mut loader = DummyMacroLoader; + let mut loader = DummyResolver; let mut ecx = ExtCtxt::new(&sess, vec![], test_ecfg(), &mut loader); expand_crate(&mut ecx, vec![], crate_ast); } @@ -888,7 +888,7 @@ mod tests { let ps = parse::ParseSess::new(); let crate_ast = panictry!(string_to_parser(&ps, crate_str).parse_crate_mod()); // the cfg argument actually does matter, here... - let mut loader = DummyMacroLoader; + let mut loader = DummyResolver; let mut ecx = ExtCtxt::new(&ps, vec![], test_ecfg(), &mut loader); expand_crate(&mut ecx, vec![], crate_ast) } diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index 3108296e778a..dde8a8d271f6 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -28,7 +28,7 @@ use errors; use errors::snippet::{SnippetData}; use config; use entry::{self, EntryPointType}; -use ext::base::{ExtCtxt, DummyMacroLoader}; +use ext::base::{ExtCtxt, DummyResolver}; use ext::build::AstBuilder; use ext::expand::ExpansionConfig; use fold::Folder; @@ -276,13 +276,13 @@ fn generate_test_harness(sess: &ParseSess, let mut cleaner = EntryPointCleaner { depth: 0 }; let krate = cleaner.fold_crate(krate); - let mut loader = DummyMacroLoader; + let mut resolver = DummyResolver; let mut cx: TestCtxt = TestCtxt { sess: sess, span_diagnostic: sd, ext_cx: ExtCtxt::new(sess, vec![], ExpansionConfig::default("test".to_string()), - &mut loader), + &mut resolver), path: Vec::new(), testfns: Vec::new(), reexport_test_harness_main: reexport_test_harness_main, diff --git a/src/libsyntax_ext/rustc_macro_registrar.rs b/src/libsyntax_ext/rustc_macro_registrar.rs index 7693e2416f4b..78fed9d33dd8 100644 --- a/src/libsyntax_ext/rustc_macro_registrar.rs +++ b/src/libsyntax_ext/rustc_macro_registrar.rs @@ -13,7 +13,7 @@ use std::mem; use errors; use syntax::ast::{self, Ident, NodeId}; use syntax::codemap::{ExpnInfo, NameAndSpan, MacroAttribute}; -use syntax::ext::base::{ExtCtxt, DummyMacroLoader}; +use syntax::ext::base::{ExtCtxt, DummyResolver}; use syntax::ext::build::AstBuilder; use syntax::ext::expand::ExpansionConfig; use syntax::parse::ParseSess; @@ -44,7 +44,7 @@ pub fn modify(sess: &ParseSess, num_crate_types: usize, handler: &errors::Handler, features: &Features) -> ast::Crate { - let mut loader = DummyMacroLoader; + let mut loader = DummyResolver; let mut cx = ExtCtxt::new(sess, Vec::new(), ExpansionConfig::default("rustc_macro".to_string()), diff --git a/src/test/compile-fail-fulldeps/qquote.rs b/src/test/compile-fail-fulldeps/qquote.rs index e29ded8a052c..3e5d17e2ffb1 100644 --- a/src/test/compile-fail-fulldeps/qquote.rs +++ b/src/test/compile-fail-fulldeps/qquote.rs @@ -22,11 +22,11 @@ use syntax_pos::DUMMY_SP; fn main() { let ps = syntax::parse::ParseSess::new(); - let mut loader = syntax::ext::base::DummyMacroLoader; + let mut resolver = syntax::ext::base::DummyResolver; let mut cx = syntax::ext::base::ExtCtxt::new( &ps, vec![], syntax::ext::expand::ExpansionConfig::default("qquote".to_string()), - &mut loader); + &mut resolver); cx.bt_push(syntax::codemap::ExpnInfo { call_site: DUMMY_SP, callee: syntax::codemap::NameAndSpan { diff --git a/src/test/run-fail-fulldeps/qquote.rs b/src/test/run-fail-fulldeps/qquote.rs index 47e97abbbaa4..1458583ff583 100644 --- a/src/test/run-fail-fulldeps/qquote.rs +++ b/src/test/run-fail-fulldeps/qquote.rs @@ -25,11 +25,11 @@ use syntax_pos::DUMMY_SP; fn main() { let ps = syntax::parse::ParseSess::new(); - let mut loader = syntax::ext::base::DummyMacroLoader; + let mut resolver = syntax::ext::base::DummyResolver; let mut cx = syntax::ext::base::ExtCtxt::new( &ps, vec![], syntax::ext::expand::ExpansionConfig::default("qquote".to_string()), - &mut loader); + &mut resolver); cx.bt_push(syntax::codemap::ExpnInfo { call_site: DUMMY_SP, callee: syntax::codemap::NameAndSpan { diff --git a/src/test/run-pass-fulldeps/qquote.rs b/src/test/run-pass-fulldeps/qquote.rs index a4f0e35cc5ac..2a53a62a5ab6 100644 --- a/src/test/run-pass-fulldeps/qquote.rs +++ b/src/test/run-pass-fulldeps/qquote.rs @@ -21,11 +21,11 @@ use syntax_pos::DUMMY_SP; fn main() { let ps = syntax::parse::ParseSess::new(); - let mut loader = syntax::ext::base::DummyMacroLoader; + let mut resolver = syntax::ext::base::DummyResolver; let mut cx = syntax::ext::base::ExtCtxt::new( &ps, vec![], syntax::ext::expand::ExpansionConfig::default("qquote".to_string()), - &mut loader); + &mut resolver); cx.bt_push(syntax::codemap::ExpnInfo { call_site: DUMMY_SP, callee: syntax::codemap::NameAndSpan { From 20b43b23230ce063ccf99a4841d85790ad311bdf Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Thu, 8 Sep 2016 00:04:43 +0000 Subject: [PATCH 328/443] Rewrite the unit tests in `ext/expand.rs` as a `compile-fail` test. --- src/libsyntax/ext/expand.rs | 107 ------------------ .../compile-fail/macro-expansion-tests.rs | 46 ++++++++ 2 files changed, 46 insertions(+), 107 deletions(-) create mode 100644 src/test/compile-fail/macro-expansion-tests.rs diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 44db1dd17ae6..d8365391153b 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -803,110 +803,3 @@ impl Folder for Marker { fn mark_tts(tts: &[TokenTree], m: Mark) -> Vec { noop_fold_tts(tts, &mut Marker{mark:m, expn_id: None}) } - - -#[cfg(test)] -mod tests { - use super::{expand_crate, ExpansionConfig}; - use ast; - use ext::base::{ExtCtxt, DummyResolver}; - use parse; - use util::parser_testing::{string_to_parser}; - use visit; - use visit::Visitor; - - // a visitor that extracts the paths - // from a given thingy and puts them in a mutable - // array (passed in to the traversal) - #[derive(Clone)] - struct PathExprFinderContext { - path_accumulator: Vec , - } - - impl Visitor for PathExprFinderContext { - fn visit_expr(&mut self, expr: &ast::Expr) { - if let ast::ExprKind::Path(None, ref p) = expr.node { - self.path_accumulator.push(p.clone()); - } - visit::walk_expr(self, expr); - } - } - - // these following tests are quite fragile, in that they don't test what - // *kind* of failure occurs. - - fn test_ecfg() -> ExpansionConfig<'static> { - ExpansionConfig::default("test".to_string()) - } - - // make sure that macros can't escape fns - #[should_panic] - #[test] fn macros_cant_escape_fns_test () { - let src = "fn bogus() {macro_rules! z (() => (3+4));}\ - fn inty() -> i32 { z!() }".to_string(); - let sess = parse::ParseSess::new(); - let crate_ast = parse::parse_crate_from_source_str( - "".to_string(), - src, - Vec::new(), &sess).unwrap(); - // should fail: - let mut loader = DummyResolver; - let mut ecx = ExtCtxt::new(&sess, vec![], test_ecfg(), &mut loader); - expand_crate(&mut ecx, vec![], crate_ast); - } - - // make sure that macros can't escape modules - #[should_panic] - #[test] fn macros_cant_escape_mods_test () { - let src = "mod foo {macro_rules! z (() => (3+4));}\ - fn inty() -> i32 { z!() }".to_string(); - let sess = parse::ParseSess::new(); - let crate_ast = parse::parse_crate_from_source_str( - "".to_string(), - src, - Vec::new(), &sess).unwrap(); - let mut loader = DummyResolver; - let mut ecx = ExtCtxt::new(&sess, vec![], test_ecfg(), &mut loader); - expand_crate(&mut ecx, vec![], crate_ast); - } - - // macro_use modules should allow macros to escape - #[test] fn macros_can_escape_flattened_mods_test () { - let src = "#[macro_use] mod foo {macro_rules! z (() => (3+4));}\ - fn inty() -> i32 { z!() }".to_string(); - let sess = parse::ParseSess::new(); - let crate_ast = parse::parse_crate_from_source_str( - "".to_string(), - src, - Vec::new(), &sess).unwrap(); - let mut loader = DummyResolver; - let mut ecx = ExtCtxt::new(&sess, vec![], test_ecfg(), &mut loader); - expand_crate(&mut ecx, vec![], crate_ast); - } - - fn expand_crate_str(crate_str: String) -> ast::Crate { - let ps = parse::ParseSess::new(); - let crate_ast = panictry!(string_to_parser(&ps, crate_str).parse_crate_mod()); - // the cfg argument actually does matter, here... - let mut loader = DummyResolver; - let mut ecx = ExtCtxt::new(&ps, vec![], test_ecfg(), &mut loader); - expand_crate(&mut ecx, vec![], crate_ast) - } - - #[test] fn macro_tokens_should_match(){ - expand_crate_str( - "macro_rules! m((a)=>(13)) ;fn main(){m!(a);}".to_string()); - } - - // should be able to use a bound identifier as a literal in a macro definition: - #[test] fn self_macro_parsing(){ - expand_crate_str( - "macro_rules! foo ((zz) => (287;)); - fn f(zz: i32) {foo!(zz);}".to_string() - ); - } - - // create a really evil test case where a $x appears inside a binding of $x - // but *shouldn't* bind because it was inserted by a different macro.... - // can't write this test case until we have macro-generating macros. -} diff --git a/src/test/compile-fail/macro-expansion-tests.rs b/src/test/compile-fail/macro-expansion-tests.rs new file mode 100644 index 000000000000..a064e69bc6d5 --- /dev/null +++ b/src/test/compile-fail/macro-expansion-tests.rs @@ -0,0 +1,46 @@ +// 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. + +mod macros_cant_escape_fns { + fn f() { + macro_rules! m { () => { 3 + 4 } } + } + fn g() -> i32 { m!() } //~ ERROR macro undefined +} + +mod macros_cant_escape_mods { + mod f { + macro_rules! m { () => { 3 + 4 } } + } + fn g() -> i32 { m!() } //~ ERROR macro undefined +} + +mod macros_can_escape_flattened_mods_test { + #[macro_use] + mod f { + macro_rules! m { () => { 3 + 4 } } + } + fn g() -> i32 { m!() } +} + +fn macro_tokens_should_match() { + macro_rules! m { (a) => { 13 } } + m!(a); +} + +// should be able to use a bound identifier as a literal in a macro definition: +fn self_macro_parsing() { + macro_rules! foo { (zz) => { 287; } } + fn f(zz: i32) { + foo!(zz); + } +} + +fn main() {} From 5841678f51b9fcb085dba148639a21d95ef91423 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 12 Sep 2016 22:40:14 -0700 Subject: [PATCH 329/443] rustbuild: Fix cross-compiles to MinGW on Linux Closes #36290 Closes #36291 --- src/bootstrap/compile.rs | 12 +++++++----- src/rtstartup/rsbegin.rs | 11 ++++++++++- src/rtstartup/rsend.rs | 9 ++++++++- src/rustc/std_shim/Cargo.lock | 1 + src/rustc/std_shim/Cargo.toml | 1 + src/rustc/std_shim/lib.rs | 6 ++++++ 6 files changed, 33 insertions(+), 7 deletions(-) diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index e87669ba08ca..618fa3805b37 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -117,14 +117,16 @@ fn build_startup_objects(build: &Build, target: &str, into: &Path) { return } let compiler = Compiler::new(0, &build.config.build); - let compiler = build.compiler_path(&compiler); + let compiler_path = build.compiler_path(&compiler); for file in t!(fs::read_dir(build.src.join("src/rtstartup"))) { let file = t!(file); - build.run(Command::new(&compiler) - .arg("--emit=obj") - .arg("--out-dir").arg(into) - .arg(file.path())); + let mut cmd = Command::new(&compiler_path); + build.add_bootstrap_key(&compiler, &mut cmd); + build.run(cmd.arg("--target").arg(target) + .arg("--emit=obj") + .arg("--out-dir").arg(into) + .arg(file.path())); } for obj in ["crt2.o", "dllcrt2.o"].iter() { diff --git a/src/rtstartup/rsbegin.rs b/src/rtstartup/rsbegin.rs index 150abc226e68..b57b7e843216 100644 --- a/src/rtstartup/rsbegin.rs +++ b/src/rtstartup/rsbegin.rs @@ -22,10 +22,19 @@ // object (usually called `crtX.o), which then invokes initialization callbacks // of other runtime components (registered via yet another special image section). +#![feature(no_core, lang_items)] #![crate_type="rlib"] -#![no_std] +#![no_core] #![allow(non_camel_case_types)] +#[lang = "sized"] +trait Sized {} +#[lang = "sync"] +trait Sync {} +#[lang = "copy"] +trait Copy {} +impl Sync for T {} + #[cfg(all(target_os="windows", target_arch = "x86", target_env="gnu"))] pub mod eh_frames { #[no_mangle] diff --git a/src/rtstartup/rsend.rs b/src/rtstartup/rsend.rs index 915c2355b048..4c48d9af0e1f 100644 --- a/src/rtstartup/rsend.rs +++ b/src/rtstartup/rsend.rs @@ -10,8 +10,15 @@ // See rsbegin.rs for details. +#![feature(no_core, lang_items)] #![crate_type="rlib"] -#![no_std] +#![no_core] + +#[lang = "sized"] +trait Sized {} +#[lang = "sync"] +trait Sync {} +impl Sync for T {} #[cfg(all(target_os="windows", target_arch = "x86", target_env="gnu"))] pub mod eh_frames { diff --git a/src/rustc/std_shim/Cargo.lock b/src/rustc/std_shim/Cargo.lock index d47b541b4c3b..fb0885c132d5 100644 --- a/src/rustc/std_shim/Cargo.lock +++ b/src/rustc/std_shim/Cargo.lock @@ -2,6 +2,7 @@ name = "std_shim" version = "0.1.0" dependencies = [ + "core 0.0.0", "std 0.0.0", ] diff --git a/src/rustc/std_shim/Cargo.toml b/src/rustc/std_shim/Cargo.toml index 693cbe06ba98..58a7bd8a1cb7 100644 --- a/src/rustc/std_shim/Cargo.toml +++ b/src/rustc/std_shim/Cargo.toml @@ -41,6 +41,7 @@ debug-assertions = false [dependencies] std = { path = "../../libstd" } +core = { path = "../../libcore" } # Reexport features from std [features] diff --git a/src/rustc/std_shim/lib.rs b/src/rustc/std_shim/lib.rs index 3cf4cfab135f..2fc5d8d6e532 100644 --- a/src/rustc/std_shim/lib.rs +++ b/src/rustc/std_shim/lib.rs @@ -9,3 +9,9 @@ // except according to those terms. // See comments in Cargo.toml for why this exists + +// There's a bug right now where if we pass --extern std=... and we're cross +// compiling then this doesn't work with `#[macro_use] extern crate std;`. Work +// around this by not having `#[macro_use] extern crate std;` +#![no_std] +extern crate std; From 332ba1286eef931c2e48816cb207e775cc6ccd1b Mon Sep 17 00:00:00 2001 From: Ximin Luo Date: Tue, 13 Sep 2016 10:09:36 +0200 Subject: [PATCH 330/443] mk: add a all-no-docs target to build everything except docs This makes things slightly more efficient for Debian's auto-builders where the docs can be built on just one architecture, and distributed to users of all other architectures as well. --- mk/main.mk | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mk/main.mk b/mk/main.mk index 6130b5813875..fae1546408a9 100644 --- a/mk/main.mk +++ b/mk/main.mk @@ -630,7 +630,8 @@ ALL_TARGET_RULES = $(foreach target,$(CFG_TARGET), \ $(foreach host,$(CFG_HOST), \ all-target-$(target)-host-$(host))) -all: $(ALL_TARGET_RULES) $(GENERATED) docs +all-no-docs: $(ALL_TARGET_RULES) $(GENERATED) +all: all-no-docs docs ###################################################################### # Build system documentation From 72a636975fc5d0bb4af45af7bdd97987cc722a6a Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Wed, 7 Sep 2016 23:21:59 +0000 Subject: [PATCH 331/443] Move macro resolution into `librustc_resolve`. --- src/librustc/session/mod.rs | 9 +- src/librustc_driver/driver.rs | 9 +- src/librustc_resolve/lib.rs | 18 +- src/librustc_resolve/macros.rs | 213 ++++++++++++++++++++ src/libsyntax/ext/base.rs | 298 ++++++---------------------- src/libsyntax/ext/expand.rs | 182 +++++++---------- src/libsyntax/ext/hygiene.rs | 11 +- src/libsyntax/ext/source_util.rs | 4 +- src/libsyntax/ext/tt/macro_rules.rs | 4 +- src/libsyntax_ext/deriving/mod.rs | 9 +- src/libsyntax_ext/lib.rs | 86 +++++--- 11 files changed, 438 insertions(+), 405 deletions(-) create mode 100644 src/librustc_resolve/macros.rs diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 3477ec6f99af..49686d63ee43 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -21,7 +21,7 @@ use util::nodemap::{NodeMap, FnvHashMap}; use util::common::duration_to_secs_str; use mir::transform as mir_pass; -use syntax::ast::{NodeId, Name}; +use syntax::ast::NodeId; use errors::{self, DiagnosticBuilder}; use errors::emitter::{Emitter, EmitterWriter}; use syntax::json::JsonEmitter; @@ -39,7 +39,7 @@ use llvm; use std::path::{Path, PathBuf}; use std::cell::{self, Cell, RefCell}; -use std::collections::{HashMap, HashSet}; +use std::collections::HashMap; use std::env; use std::ffi::CString; use std::rc::Rc; @@ -96,10 +96,6 @@ pub struct Session { pub injected_allocator: Cell>, pub injected_panic_runtime: Cell>, - /// Names of all bang-style macros and syntax extensions - /// available in this crate - pub available_macros: RefCell>, - /// Map from imported macro spans (which consist of /// the localized span for the macro body) to the /// macro name and defintion span in the source crate. @@ -552,7 +548,6 @@ pub fn build_session_(sopts: config::Options, next_node_id: Cell::new(1), injected_allocator: Cell::new(None), injected_panic_runtime: Cell::new(None), - available_macros: RefCell::new(HashSet::new()), imported_macro_spans: RefCell::new(HashMap::new()), incr_comp_session: RefCell::new(IncrCompSession::NotInitialized), perf_stats: PerfStats { diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 0d9bf14f12fb..bf50c96034dd 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -50,6 +50,7 @@ use std::io::{self, Write}; use std::path::{Path, PathBuf}; use syntax::{ast, diagnostics, visit}; use syntax::attr; +use syntax::ext::base::ExtCtxt; use syntax::parse::{self, PResult, token}; use syntax::util::node_count::NodeCounter; use syntax; @@ -643,6 +644,7 @@ pub fn phase_2_configure_and_expand<'a, F>(sess: &Session, let resolver_arenas = Resolver::arenas(); let mut resolver = Resolver::new(sess, make_glob_map, &mut macro_loader, &resolver_arenas); + syntax_ext::register_builtins(&mut resolver, sess.features.borrow().quote); krate = time(time_passes, "expansion", || { // Windows dlls do not have rpaths, so they don't know how to find their @@ -678,16 +680,11 @@ pub fn phase_2_configure_and_expand<'a, F>(sess: &Session, trace_mac: sess.opts.debugging_opts.trace_macros, should_test: sess.opts.test, }; - let mut ecx = syntax::ext::base::ExtCtxt::new(&sess.parse_sess, - krate.config.clone(), - cfg, - &mut resolver); - syntax_ext::register_builtins(&mut ecx.syntax_env); + let mut ecx = ExtCtxt::new(&sess.parse_sess, krate.config.clone(), cfg, &mut resolver); let ret = syntax::ext::expand::expand_crate(&mut ecx, syntax_exts, krate); if cfg!(windows) { env::set_var("PATH", &old_path); } - *sess.available_macros.borrow_mut() = ecx.syntax_env.names; ret }); diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index c1e6d93a970e..6bf45ab8f6fa 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -54,8 +54,6 @@ use rustc::ty; use rustc::hir::{Freevar, FreevarMap, TraitCandidate, TraitMap, GlobMap}; use rustc::util::nodemap::{NodeMap, NodeSet, FnvHashMap, FnvHashSet}; -use syntax::ext; -use syntax::ext::base::LoadedMacro; use syntax::ext::hygiene::Mark; use syntax::ast::{self, FloatTy}; use syntax::ast::{CRATE_NODE_ID, Name, NodeId, CrateNum, IntTy, UintTy}; @@ -82,6 +80,7 @@ use resolve_imports::{ImportDirective, NameResolution}; // registered before they are used. mod diagnostics; +mod macros; mod check_unused; mod build_reduced_graph; mod resolve_imports; @@ -1073,6 +1072,10 @@ pub struct Resolver<'a> { new_import_semantics: bool, // true if `#![feature(item_like_imports)]` macro_loader: &'a mut MacroLoader, + macro_names: FnvHashSet, + + // Maps the `Mark` of an expansion to its containing module or block. + expansion_data: Vec, } pub struct ResolverArenas<'a> { @@ -1154,12 +1157,6 @@ impl<'a> hir::lowering::Resolver for Resolver<'a> { } } -impl<'a> ext::base::Resolver for Resolver<'a> { - fn load_crate(&mut self, extern_crate: &ast::Item, allows_macros: bool) -> Vec { - self.macro_loader.load_crate(extern_crate, allows_macros) - } -} - trait Named { fn name(&self) -> Name; } @@ -1243,6 +1240,8 @@ impl<'a> Resolver<'a> { new_import_semantics: session.features.borrow().item_like_imports, macro_loader: macro_loader, + macro_names: FnvHashSet(), + expansion_data: vec![macros::ExpansionData::default()], } } @@ -2784,8 +2783,7 @@ impl<'a> Resolver<'a> { } fn find_best_match(&mut self, name: &str) -> SuggestionType { - if let Some(macro_name) = self.session.available_macros - .borrow().iter().find(|n| n.as_str() == name) { + if let Some(macro_name) = self.macro_names.iter().find(|n| n.as_str() == name) { return SuggestionType::Macro(format!("{}!", macro_name)); } diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs new file mode 100644 index 000000000000..36f501a54d26 --- /dev/null +++ b/src/librustc_resolve/macros.rs @@ -0,0 +1,213 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use Resolver; +use rustc::util::nodemap::FnvHashMap; +use std::cell::RefCell; +use std::mem; +use std::rc::Rc; +use syntax::ast::{self, Name}; +use syntax::errors::DiagnosticBuilder; +use syntax::ext::base::{self, LoadedMacro, MultiModifier, MultiDecorator}; +use syntax::ext::base::{NormalTT, SyntaxExtension}; +use syntax::ext::expand::{Expansion, Invocation, InvocationKind}; +use syntax::ext::hygiene::Mark; +use syntax::parse::token::intern; +use syntax::util::lev_distance::find_best_match_for_name; +use syntax::visit::{self, Visitor}; + +#[derive(Clone, Default)] +pub struct ExpansionData { + module: Rc, +} + +// FIXME(jseyfried): merge with `::ModuleS`. +#[derive(Default)] +struct ModuleData { + parent: Option>, + macros: RefCell>>, + macros_escape: bool, +} + +impl<'a> base::Resolver for Resolver<'a> { + fn load_crate(&mut self, extern_crate: &ast::Item, allows_macros: bool) -> Vec { + self.macro_loader.load_crate(extern_crate, allows_macros) + } + + fn visit_expansion(&mut self, mark: Mark, expansion: &Expansion) { + expansion.visit_with(&mut ExpansionVisitor { + current_module: self.expansion_data[mark.as_u32() as usize].module.clone(), + resolver: self, + }); + } + + fn add_macro(&mut self, scope: Mark, ident: ast::Ident, ext: Rc) { + if let NormalTT(..) = *ext { + self.macro_names.insert(ident.name); + } + + let mut module = self.expansion_data[scope.as_u32() as usize].module.clone(); + while module.macros_escape { + module = module.parent.clone().unwrap(); + } + module.macros.borrow_mut().insert(ident.name, ext); + } + + fn add_expansions_at_stmt(&mut self, id: ast::NodeId, macros: Vec) { + self.macros_at_scope.insert(id, macros); + } + + fn find_attr_invoc(&mut self, attrs: &mut Vec) -> Option { + for i in 0..attrs.len() { + let name = intern(&attrs[i].name()); + match self.expansion_data[0].module.macros.borrow().get(&name) { + Some(ext) => match **ext { + MultiModifier(..) | MultiDecorator(..) => return Some(attrs.remove(i)), + _ => {} + }, + None => {} + } + } + None + } + + fn resolve_invoc(&mut self, invoc: &Invocation) -> Option> { + let (name, span) = match invoc.kind { + InvocationKind::Bang { ref mac, .. } => { + let path = &mac.node.path; + if path.segments.len() > 1 || path.global || + !path.segments[0].parameters.is_empty() { + self.session.span_err(path.span, + "expected macro name without module separators"); + return None; + } + (path.segments[0].identifier.name, path.span) + } + InvocationKind::Attr { ref attr, .. } => (intern(&*attr.name()), attr.span), + }; + + let mut module = self.expansion_data[invoc.mark().as_u32() as usize].module.clone(); + loop { + if let Some(ext) = module.macros.borrow().get(&name) { + return Some(ext.clone()); + } + match module.parent.clone() { + Some(parent) => module = parent, + None => break, + } + } + + let mut err = + self.session.struct_span_err(span, &format!("macro undefined: '{}!'", name)); + self.suggest_macro_name(&name.as_str(), &mut err); + err.emit(); + None + } +} + +impl<'a> Resolver<'a> { + fn suggest_macro_name(&mut self, name: &str, err: &mut DiagnosticBuilder<'a>) { + if let Some(suggestion) = find_best_match_for_name(self.macro_names.iter(), name, None) { + if suggestion != name { + err.help(&format!("did you mean `{}!`?", suggestion)); + } else { + err.help(&format!("have you added the `#[macro_use]` on the module/import?")); + } + } + } +} + +struct ExpansionVisitor<'b, 'a: 'b> { + resolver: &'b mut Resolver<'a>, + current_module: Rc, +} + +impl<'a, 'b> ExpansionVisitor<'a, 'b> { + fn visit_invoc(&mut self, id: ast::NodeId) { + assert_eq!(id, self.resolver.expansion_data.len() as u32); + self.resolver.expansion_data.push(ExpansionData { + module: self.current_module.clone(), + }); + } + + // does this attribute list contain "macro_use"? + fn contains_macro_use(&mut self, attrs: &[ast::Attribute]) -> bool { + for attr in attrs { + if attr.check_name("macro_escape") { + let msg = "macro_escape is a deprecated synonym for macro_use"; + let mut err = self.resolver.session.struct_span_warn(attr.span, msg); + if let ast::AttrStyle::Inner = attr.node.style { + err.help("consider an outer attribute, #[macro_use] mod ...").emit(); + } else { + err.emit(); + } + } else if !attr.check_name("macro_use") { + continue; + } + + if !attr.is_word() { + self.resolver.session.span_err(attr.span, + "arguments to macro_use are not allowed here"); + } + return true; + } + + false + } +} + +macro_rules! method { + ($visit:ident: $ty:ty, $invoc:path, $walk:ident) => { + fn $visit(&mut self, node: &$ty) { + match node.node { + $invoc(..) => self.visit_invoc(node.id), + _ => visit::$walk(self, node), + } + } + } +} + +impl<'a, 'b> Visitor for ExpansionVisitor<'a, 'b> { + method!(visit_trait_item: ast::TraitItem, ast::TraitItemKind::Macro, walk_trait_item); + method!(visit_impl_item: ast::ImplItem, ast::ImplItemKind::Macro, walk_impl_item); + method!(visit_stmt: ast::Stmt, ast::StmtKind::Mac, walk_stmt); + method!(visit_expr: ast::Expr, ast::ExprKind::Mac, walk_expr); + method!(visit_pat: ast::Pat, ast::PatKind::Mac, walk_pat); + method!(visit_ty: ast::Ty, ast::TyKind::Mac, walk_ty); + + fn visit_item(&mut self, item: &ast::Item) { + match item.node { + ast::ItemKind::Mac(..) if item.id == ast::DUMMY_NODE_ID => {} // Scope placeholder + ast::ItemKind::Mac(..) => self.visit_invoc(item.id), + ast::ItemKind::Mod(..) => { + let module_data = ModuleData { + parent: Some(self.current_module.clone()), + macros: RefCell::new(FnvHashMap()), + macros_escape: self.contains_macro_use(&item.attrs), + }; + let orig_module = mem::replace(&mut self.current_module, Rc::new(module_data)); + visit::walk_item(self, item); + self.current_module = orig_module; + } + _ => visit::walk_item(self, item), + } + } + + fn visit_block(&mut self, block: &ast::Block) { + let module_data = ModuleData { + parent: Some(self.current_module.clone()), + macros: RefCell::new(FnvHashMap()), + macros_escape: false, + }; + let orig_module = mem::replace(&mut self.current_module, Rc::new(module_data)); + visit::walk_block(self, block); + self.current_module = orig_module; + } +} diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index d0e11643c64c..d46e2a9872e8 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -10,27 +10,25 @@ pub use self::SyntaxExtension::*; -use ast; -use ast::{Name, PatKind}; +use ast::{self, Attribute, Name, PatKind}; use attr::HasAttrs; use codemap::{self, CodeMap, ExpnInfo, Spanned, respan}; use syntax_pos::{Span, ExpnId, NO_EXPANSION}; use errors::DiagnosticBuilder; -use ext; -use ext::expand; +use ext::expand::{self, Invocation, Expansion}; +use ext::hygiene::Mark; use ext::tt::macro_rules; use parse; use parse::parser; use parse::token; -use parse::token::{InternedString, intern, str_to_ident}; +use parse::token::{InternedString, str_to_ident}; use ptr::P; use std_inject; use util::small_vector::SmallVector; -use util::lev_distance::find_best_match_for_name; use fold::Folder; use feature_gate; -use std::collections::{HashMap, HashSet}; +use std::collections::HashMap; use std::path::PathBuf; use std::rc::Rc; use tokenstream; @@ -44,7 +42,7 @@ pub enum Annotatable { } impl HasAttrs for Annotatable { - fn attrs(&self) -> &[ast::Attribute] { + fn attrs(&self) -> &[Attribute] { match *self { Annotatable::Item(ref item) => &item.attrs, Annotatable::TraitItem(ref trait_item) => &trait_item.attrs, @@ -52,7 +50,7 @@ impl HasAttrs for Annotatable { } } - fn map_attrs) -> Vec>(self, f: F) -> Self { + fn map_attrs) -> Vec>(self, f: F) -> Self { match self { Annotatable::Item(item) => Annotatable::Item(item.map_attrs(f)), Annotatable::TraitItem(trait_item) => Annotatable::TraitItem(trait_item.map_attrs(f)), @@ -464,91 +462,15 @@ pub enum SyntaxExtension { pub type NamedSyntaxExtension = (Name, SyntaxExtension); -/// The base map of methods for expanding syntax extension -/// AST nodes into full ASTs -fn initial_syntax_expander_table<'feat>(ecfg: &expand::ExpansionConfig<'feat>) - -> SyntaxEnv { - // utility function to simplify creating NormalTT syntax extensions - fn builtin_normal_expander(f: MacroExpanderFn) -> SyntaxExtension { - NormalTT(Box::new(f), None, false) - } - - let mut syntax_expanders = SyntaxEnv::new(); - syntax_expanders.insert(intern("macro_rules"), MacroRulesTT); - - if ecfg.enable_quotes() { - // Quasi-quoting expanders - syntax_expanders.insert(intern("quote_tokens"), - builtin_normal_expander( - ext::quote::expand_quote_tokens)); - syntax_expanders.insert(intern("quote_expr"), - builtin_normal_expander( - ext::quote::expand_quote_expr)); - syntax_expanders.insert(intern("quote_ty"), - builtin_normal_expander( - ext::quote::expand_quote_ty)); - syntax_expanders.insert(intern("quote_item"), - builtin_normal_expander( - ext::quote::expand_quote_item)); - syntax_expanders.insert(intern("quote_pat"), - builtin_normal_expander( - ext::quote::expand_quote_pat)); - syntax_expanders.insert(intern("quote_arm"), - builtin_normal_expander( - ext::quote::expand_quote_arm)); - syntax_expanders.insert(intern("quote_stmt"), - builtin_normal_expander( - ext::quote::expand_quote_stmt)); - syntax_expanders.insert(intern("quote_matcher"), - builtin_normal_expander( - ext::quote::expand_quote_matcher)); - syntax_expanders.insert(intern("quote_attr"), - builtin_normal_expander( - ext::quote::expand_quote_attr)); - syntax_expanders.insert(intern("quote_arg"), - builtin_normal_expander( - ext::quote::expand_quote_arg)); - syntax_expanders.insert(intern("quote_block"), - builtin_normal_expander( - ext::quote::expand_quote_block)); - syntax_expanders.insert(intern("quote_meta_item"), - builtin_normal_expander( - ext::quote::expand_quote_meta_item)); - syntax_expanders.insert(intern("quote_path"), - builtin_normal_expander( - ext::quote::expand_quote_path)); - } - - syntax_expanders.insert(intern("line"), - builtin_normal_expander( - ext::source_util::expand_line)); - syntax_expanders.insert(intern("column"), - builtin_normal_expander( - ext::source_util::expand_column)); - syntax_expanders.insert(intern("file"), - builtin_normal_expander( - ext::source_util::expand_file)); - syntax_expanders.insert(intern("stringify"), - builtin_normal_expander( - ext::source_util::expand_stringify)); - syntax_expanders.insert(intern("include"), - builtin_normal_expander( - ext::source_util::expand_include)); - syntax_expanders.insert(intern("include_str"), - builtin_normal_expander( - ext::source_util::expand_include_str)); - syntax_expanders.insert(intern("include_bytes"), - builtin_normal_expander( - ext::source_util::expand_include_bytes)); - syntax_expanders.insert(intern("module_path"), - builtin_normal_expander( - ext::source_util::expand_mod)); - syntax_expanders -} - pub trait Resolver { - fn load_crate(&mut self, extern_crate: &ast::Item, allows_macros: bool) - -> Vec; + fn load_crate(&mut self, extern_crate: &ast::Item, allows_macros: bool) -> Vec; + + fn visit_expansion(&mut self, mark: Mark, expansion: &Expansion); + fn add_macro(&mut self, scope: Mark, ident: ast::Ident, ext: Rc); + fn add_expansions_at_stmt(&mut self, id: ast::NodeId, macros: Vec); + + fn find_attr_invoc(&mut self, attrs: &mut Vec) -> Option; + fn resolve_invoc(&mut self, invoc: &Invocation) -> Option>; } pub enum LoadedMacro { @@ -558,9 +480,31 @@ pub enum LoadedMacro { pub struct DummyResolver; impl Resolver for DummyResolver { - fn load_crate(&mut self, _: &ast::Item, _: bool) -> Vec { + fn load_crate(&mut self, _extern_crate: &ast::Item, _allows_macros: bool) -> Vec { Vec::new() } + + fn visit_expansion(&mut self, _invoc: Mark, _expansion: &Expansion) {} + fn add_macro(&mut self, _scope: Mark, _ident: ast::Ident, _ext: Rc) {} + fn add_expansions_at_stmt(&mut self, _id: ast::NodeId, _macros: Vec) {} + + fn find_attr_invoc(&mut self, _attrs: &mut Vec) -> Option { None } + fn resolve_invoc(&mut self, _invoc: &Invocation) -> Option> { None } +} + +#[derive(Clone)] +pub struct ModuleData { + pub mod_path: Vec, + pub directory: PathBuf, +} + +#[derive(Clone)] +pub struct ExpansionData { + pub mark: Mark, + pub depth: usize, + pub backtrace: ExpnId, + pub module: Rc, + pub in_block: bool, } /// One of these is made during expansion and incrementally updated as we go; @@ -569,16 +513,12 @@ impl Resolver for DummyResolver { pub struct ExtCtxt<'a> { pub parse_sess: &'a parse::ParseSess, pub cfg: ast::CrateConfig, - pub backtrace: ExpnId, pub ecfg: expand::ExpansionConfig<'a>, pub crate_root: Option<&'static str>, pub resolver: &'a mut Resolver, - pub exported_macros: Vec, - - pub syntax_env: SyntaxEnv, pub derive_modes: HashMap>, - pub recursion_count: usize, + pub current_expansion: ExpansionData, } impl<'a> ExtCtxt<'a> { @@ -587,16 +527,20 @@ impl<'a> ExtCtxt<'a> { resolver: &'a mut Resolver) -> ExtCtxt<'a> { ExtCtxt { - syntax_env: initial_syntax_expander_table(&ecfg), parse_sess: parse_sess, cfg: cfg, - backtrace: NO_EXPANSION, ecfg: ecfg, crate_root: None, exported_macros: Vec::new(), resolver: resolver, derive_modes: HashMap::new(), - recursion_count: 0, + current_expansion: ExpansionData { + mark: Mark::root(), + depth: 0, + backtrace: NO_EXPANSION, + module: Rc::new(ModuleData { mod_path: Vec::new(), directory: PathBuf::new() }), + in_block: false, + }, } } @@ -609,23 +553,22 @@ impl<'a> ExtCtxt<'a> { -> parser::Parser<'a> { parse::tts_to_parser(self.parse_sess, tts.to_vec(), self.cfg()) } - pub fn codemap(&self) -> &'a CodeMap { self.parse_sess.codemap() } pub fn parse_sess(&self) -> &'a parse::ParseSess { self.parse_sess } pub fn cfg(&self) -> ast::CrateConfig { self.cfg.clone() } pub fn call_site(&self) -> Span { - self.codemap().with_expn_info(self.backtrace, |ei| match ei { + self.codemap().with_expn_info(self.backtrace(), |ei| match ei { Some(expn_info) => expn_info.call_site, None => self.bug("missing top span") }) } - pub fn backtrace(&self) -> ExpnId { self.backtrace } + pub fn backtrace(&self) -> ExpnId { self.current_expansion.backtrace } /// Returns span for the macro which originally caused the current expansion to happen. /// /// Stops backtracing at include! boundary. pub fn expansion_cause(&self) -> Span { - let mut expn_id = self.backtrace; + let mut expn_id = self.backtrace(); let mut last_macro = None; loop { if self.codemap().with_expn_info(expn_id, |info| { @@ -646,15 +589,15 @@ impl<'a> ExtCtxt<'a> { } pub fn bt_push(&mut self, ei: ExpnInfo) { - if self.recursion_count > self.ecfg.recursion_limit { + if self.current_expansion.depth > self.ecfg.recursion_limit { self.span_fatal(ei.call_site, &format!("recursion limit reached while expanding the macro `{}`", ei.callee.name())); } let mut call_site = ei.call_site; - call_site.expn_id = self.backtrace; - self.backtrace = self.codemap().record_expansion(ExpnInfo { + call_site.expn_id = self.backtrace(); + self.current_expansion.backtrace = self.codemap().record_expansion(ExpnInfo { call_site: call_site, callee: ei.callee }); @@ -667,14 +610,11 @@ impl<'a> ExtCtxt<'a> { } if def.use_locally { let ext = macro_rules::compile(self, &def); - self.syntax_env.insert(def.ident.name, ext); + self.resolver.add_macro(self.current_expansion.mark, def.ident, Rc::new(ext)); } } - pub fn insert_custom_derive(&mut self, - name: &str, - ext: Box, - sp: Span) { + pub fn insert_custom_derive(&mut self, name: &str, ext: Box, sp: Span) { if !self.ecfg.enable_rustc_macro() { feature_gate::emit_feature_err(&self.parse_sess.span_diagnostic, "rustc_macro", @@ -685,8 +625,7 @@ impl<'a> ExtCtxt<'a> { } let name = token::intern_and_get_ident(name); if self.derive_modes.insert(name.clone(), ext).is_some() { - self.span_err(sp, &format!("cannot shadow existing derive mode `{}`", - name)); + self.span_err(sp, &format!("cannot shadow existing derive mode `{}`", name)); } } @@ -765,20 +704,6 @@ impl<'a> ExtCtxt<'a> { token::intern(st) } - pub fn suggest_macro_name(&mut self, - name: &str, - err: &mut DiagnosticBuilder<'a>) { - let names = &self.syntax_env.names; - if let Some(suggestion) = find_best_match_for_name(names.iter(), name, None) { - if suggestion != name { - err.help(&format!("did you mean `{}!`?", suggestion)); - } else { - err.help(&format!("have you added the `#[macro_use]` on the \ - module/import?")); - } - } - } - pub fn initialize(&mut self, user_exts: Vec, krate: &ast::Crate) { if std_inject::no_core(&krate) { self.crate_root = None; @@ -789,16 +714,16 @@ impl<'a> ExtCtxt<'a> { } for (name, extension) in user_exts { - self.syntax_env.insert(name, extension); + let ident = ast::Ident::with_empty_ctxt(name); + self.resolver.add_macro(Mark::root(), ident, Rc::new(extension)); } - self.syntax_env.current_module = Module(0); - let mut paths = ModulePaths { + let mut module = ModuleData { mod_path: vec![token::str_to_ident(&self.ecfg.crate_name)], directory: PathBuf::from(self.parse_sess.codemap().span_to_filename(krate.span)), }; - paths.directory.pop(); - self.syntax_env.module_data[0].paths = Rc::new(paths); + module.directory.pop(); + self.current_expansion.module = Rc::new(module); } } @@ -809,7 +734,7 @@ pub fn expr_to_spanned_string(cx: &mut ExtCtxt, expr: P, err_msg: &st -> Option> { // Update `expr.span`'s expn_id now in case expr is an `include!` macro invocation. let expr = expr.map(|mut expr| { - expr.span.expn_id = cx.backtrace; + expr.span.expn_id = cx.backtrace(); expr }); @@ -884,104 +809,3 @@ pub fn get_exprs_from_tts(cx: &mut ExtCtxt, } Some(es) } - -/// In order to have some notion of scoping for macros, -/// we want to implement the notion of a transformation -/// environment. -/// -/// This environment maps Names to SyntaxExtensions. -pub struct SyntaxEnv { - module_data: Vec, - pub current_module: Module, - - /// All bang-style macro/extension names - /// encountered so far; to be used for diagnostics in resolve - pub names: HashSet, -} - -#[derive(Copy, Clone, PartialEq, Eq)] -pub struct Module(u32); - -struct ModuleData { - parent: Module, - paths: Rc, - macros: HashMap>, - macros_escape: bool, - in_block: bool, -} - -#[derive(Clone)] -pub struct ModulePaths { - pub mod_path: Vec, - pub directory: PathBuf, -} - -impl SyntaxEnv { - fn new() -> SyntaxEnv { - let mut env = SyntaxEnv { - current_module: Module(0), - module_data: Vec::new(), - names: HashSet::new(), - }; - let paths = Rc::new(ModulePaths { mod_path: Vec::new(), directory: PathBuf::new() }); - env.add_module(false, false, paths); - env - } - - fn data(&self, module: Module) -> &ModuleData { - &self.module_data[module.0 as usize] - } - - pub fn paths(&self) -> Rc { - self.data(self.current_module).paths.clone() - } - - pub fn in_block(&self) -> bool { - self.data(self.current_module).in_block - } - - pub fn add_module(&mut self, macros_escape: bool, in_block: bool, paths: Rc) - -> Module { - let data = ModuleData { - parent: self.current_module, - paths: paths, - macros: HashMap::new(), - macros_escape: macros_escape, - in_block: in_block, - }; - - self.module_data.push(data); - Module(self.module_data.len() as u32 - 1) - } - - pub fn find(&self, name: Name) -> Option> { - let mut module = self.current_module; - let mut module_data; - loop { - module_data = self.data(module); - if let Some(ext) = module_data.macros.get(&name) { - return Some(ext.clone()); - } - if module == module_data.parent { - return None; - } - module = module_data.parent; - } - } - - pub fn insert(&mut self, name: Name, ext: SyntaxExtension) { - if let NormalTT(..) = ext { - self.names.insert(name); - } - - let mut module = self.current_module; - while self.data(module).macros_escape { - module = self.data(module).parent; - } - self.module_data[module.0 as usize].macros.insert(name, Rc::new(ext)); - } - - pub fn is_crate_root(&mut self) -> bool { - self.current_module == Module(0) - } -} diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index d8365391153b..beb1687dfdc7 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -25,6 +25,7 @@ use parse::token::{intern, keywords}; use ptr::P; use tokenstream::TokenTree; use util::small_vector::SmallVector; +use visit::Visitor; use std::mem; use std::path::PathBuf; @@ -32,7 +33,8 @@ use std::rc::Rc; macro_rules! expansions { ($($kind:ident: $ty:ty [$($vec:ident, $ty_elt:ty)*], $kind_name:expr, .$make:ident, - $(.$fold:ident)* $(lift .$fold_elt:ident)*;)*) => { + $(.$fold:ident)* $(lift .$fold_elt:ident)*, + $(.$visit:ident)* $(lift .$visit_elt:ident)*;)*) => { #[derive(Copy, Clone)] pub enum ExpansionKind { OptExpr, $( $kind, )* } pub enum Expansion { OptExpr(Option>), $( $kind($ty), )* } @@ -77,6 +79,17 @@ macro_rules! expansions { }, )*)* } } + + pub fn visit_with(&self, visitor: &mut V) { + match *self { + Expansion::OptExpr(Some(ref expr)) => visitor.visit_expr(expr), + Expansion::OptExpr(None) => {} + $($( Expansion::$kind(ref ast) => visitor.$visit(ast), )*)* + $($( Expansion::$kind(ref ast) => for ast in ast.as_slice() { + visitor.$visit_elt(ast); + }, )*)* + } + } } impl<'a, 'b> Folder for MacroExpander<'a, 'b> { @@ -94,17 +107,17 @@ macro_rules! expansions { } expansions! { - Expr: P [], "expression", .make_expr, .fold_expr; - Pat: P [], "pattern", .make_pat, .fold_pat; - Ty: P [], "type", .make_ty, .fold_ty; + Expr: P [], "expression", .make_expr, .fold_expr, .visit_expr; + Pat: P [], "pattern", .make_pat, .fold_pat, .visit_pat; + Ty: P [], "type", .make_ty, .fold_ty, .visit_ty; Stmts: SmallVector [SmallVector, ast::Stmt], - "statement", .make_stmts, lift .fold_stmt; + "statement", .make_stmts, lift .fold_stmt, lift .visit_stmt; Items: SmallVector> [SmallVector, P], - "item", .make_items, lift .fold_item; + "item", .make_items, lift .fold_item, lift .visit_item; TraitItems: SmallVector [SmallVector, ast::TraitItem], - "trait item", .make_trait_items, lift .fold_trait_item; + "trait item", .make_trait_items, lift .fold_trait_item, lift .visit_trait_item; ImplItems: SmallVector [SmallVector, ast::ImplItem], - "impl item", .make_impl_items, lift .fold_impl_item; + "impl item", .make_impl_items, lift .fold_impl_item, lift .visit_impl_item; } impl ExpansionKind { @@ -127,15 +140,12 @@ impl ExpansionKind { } pub struct Invocation { - kind: InvocationKind, + pub kind: InvocationKind, expansion_kind: ExpansionKind, - mark: Mark, - module: Module, - backtrace: ExpnId, - depth: usize, + expansion_data: ExpansionData, } -enum InvocationKind { +pub enum InvocationKind { Bang { attrs: Vec, mac: ast::Mac, @@ -148,6 +158,19 @@ enum InvocationKind { }, } +impl Invocation { + fn span(&self) -> Span { + match self.kind { + InvocationKind::Bang { span, .. } => span, + InvocationKind::Attr { ref attr, .. } => attr.span, + } + } + + pub fn mark(&self) -> Mark { + self.expansion_data.mark + } +} + pub struct MacroExpander<'a, 'b:'a> { pub cx: &'a mut ExtCtxt<'b>, pub single_step: bool, @@ -170,7 +193,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { let items = Expansion::Items(SmallVector::many(krate.module.items)); krate.module.items = self.expand(items).make_items().into(); - krate.exported_macros = self.cx.exported_macros.clone(); + krate.exported_macros = mem::replace(&mut self.cx.exported_macros, Vec::new()); if self.cx.parse_sess.span_diagnostic.err_count() > err_count { self.cx.parse_sess.span_diagnostic.abort_if_errors(); @@ -181,21 +204,23 @@ impl<'a, 'b> MacroExpander<'a, 'b> { // Fully expand all the invocations in `expansion`. fn expand(&mut self, expansion: Expansion) -> Expansion { - self.cx.recursion_count = 0; + let orig_expansion_data = self.cx.current_expansion.clone(); + self.cx.current_expansion.depth = 0; + let (expansion, mut invocations) = self.collect_invocations(expansion); invocations.reverse(); let mut expansions = vec![vec![(0, expansion)]]; while let Some(invoc) = invocations.pop() { - let Invocation { mark, module, depth, backtrace, .. } = invoc; - self.cx.syntax_env.current_module = module; - self.cx.recursion_count = depth; - self.cx.backtrace = backtrace; + let ExpansionData { depth, mark, .. } = invoc.expansion_data; + self.cx.current_expansion = invoc.expansion_data.clone(); - let expansion = self.expand_invoc(invoc); + let expansion = match self.cx.resolver.resolve_invoc(&invoc) { + Some(ext) => self.expand_invoc(invoc, ext), + None => invoc.expansion_kind.dummy(invoc.span()), + }; - self.cx.syntax_env.current_module = module; - self.cx.recursion_count = depth + 1; + self.cx.current_expansion.depth = depth + 1; let (expansion, new_invocations) = self.collect_invocations(expansion); if expansions.len() == depth { @@ -207,6 +232,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } } + self.cx.current_expansion = orig_expansion_data; + let mut placeholder_expander = PlaceholderExpander::new(); while let Some(expansions) = expansions.pop() { for (mark, expansion) in expansions.into_iter().rev() { @@ -233,30 +260,27 @@ impl<'a, 'b> MacroExpander<'a, 'b> { }; (expansion.fold_with(&mut collector), collector.invocations) }; - self.cx.cfg = crate_config; + + let mark = self.cx.current_expansion.mark; + self.cx.resolver.visit_expansion(mark, &result.0); result } - fn expand_invoc(&mut self, invoc: Invocation) -> Expansion { + fn expand_invoc(&mut self, invoc: Invocation, ext: Rc) -> Expansion { match invoc.kind { - InvocationKind::Bang { .. } => self.expand_bang_invoc(invoc), - InvocationKind::Attr { .. } => self.expand_attr_invoc(invoc), + InvocationKind::Bang { .. } => self.expand_bang_invoc(invoc, ext), + InvocationKind::Attr { .. } => self.expand_attr_invoc(invoc, ext), } } - fn expand_attr_invoc(&mut self, invoc: Invocation) -> Expansion { + fn expand_attr_invoc(&mut self, invoc: Invocation, ext: Rc) -> Expansion { let Invocation { expansion_kind: kind, .. } = invoc; let (attr, item) = match invoc.kind { InvocationKind::Attr { attr, item } => (attr, item), _ => unreachable!(), }; - let extension = match self.cx.syntax_env.find(intern(&attr.name())) { - Some(extension) => extension, - None => unreachable!(), - }; - attr::mark_used(&attr); self.cx.bt_push(ExpnInfo { call_site: attr.span, @@ -267,7 +291,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } }); - match *extension { + match *ext { MultiModifier(ref mac) => { let item = mac.expand(self.cx, attr.span, &attr.node.value, item); kind.expect_from_annotatables(item) @@ -284,8 +308,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } /// Expand a macro invocation. Returns the result of expansion. - fn expand_bang_invoc(&mut self, invoc: Invocation) -> Expansion { - let Invocation { mark, expansion_kind: kind, .. } = invoc; + fn expand_bang_invoc(&mut self, invoc: Invocation, ext: Rc) -> Expansion { + let (mark, kind) = (invoc.mark(), invoc.expansion_kind); let (attrs, mac, ident, span) = match invoc.kind { InvocationKind::Bang { attrs, mac, ident, span } => (attrs, mac, ident, span), _ => unreachable!(), @@ -306,19 +330,9 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } let extname = path.segments[0].identifier.name; - let extension = if let Some(extension) = self.cx.syntax_env.find(extname) { - extension - } else { - let mut err = - self.cx.struct_span_err(path.span, &format!("macro undefined: '{}!'", &extname)); - self.cx.suggest_macro_name(&extname.as_str(), &mut err); - err.emit(); - return kind.dummy(span); - }; - let ident = ident.unwrap_or(keywords::Invalid.ident()); let marked_tts = mark_tts(&tts, mark); - let opt_expanded = match *extension { + let opt_expanded = match *ext { NormalTT(ref expandfun, exp_span, allow_internal_unstable) => { if ident.name != keywords::Invalid.name() { let msg = @@ -442,10 +456,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { self.invocations.push(Invocation { kind: kind, expansion_kind: expansion_kind, - mark: mark, - module: self.cx.syntax_env.current_module, - backtrace: self.cx.backtrace, - depth: self.cx.recursion_count, + expansion_data: ExpansionData { mark: mark, ..self.cx.current_expansion.clone() }, }); placeholder(expansion_kind, mark.as_u32()) } @@ -462,50 +473,15 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { } // If `item` is an attr invocation, remove and return the macro attribute. - fn classify_item(&self, mut item: T) -> (T, Option) { + fn classify_item(&mut self, mut item: T) -> (T, Option) { let mut attr = None; item = item.map_attrs(|mut attrs| { - for i in 0..attrs.len() { - if let Some(extension) = self.cx.syntax_env.find(intern(&attrs[i].name())) { - match *extension { - MultiModifier(..) | MultiDecorator(..) => { - attr = Some(attrs.remove(i)); - break; - } - _ => {} - } - } - } + attr = self.cx.resolver.find_attr_invoc(&mut attrs); attrs }); (item, attr) } - // does this attribute list contain "macro_use" ? - fn contains_macro_use(&mut self, attrs: &[ast::Attribute]) -> bool { - for attr in attrs { - let mut is_use = attr.check_name("macro_use"); - if attr.check_name("macro_escape") { - let msg = "macro_escape is a deprecated synonym for macro_use"; - let mut err = self.cx.struct_span_warn(attr.span, msg); - is_use = true; - if let ast::AttrStyle::Inner = attr.node.style { - err.help("consider an outer attribute, #[macro_use] mod ...").emit(); - } else { - err.emit(); - } - }; - - if is_use { - if !attr.is_word() { - self.cx.span_err(attr.span, "arguments to macro_use are not allowed here"); - } - return true; - } - } - false - } - fn configure(&mut self, node: T) -> Option { self.cfg.configure(node) } @@ -574,11 +550,9 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { } fn fold_block(&mut self, block: P) -> P { - let paths = self.cx.syntax_env.paths(); - let module = self.cx.syntax_env.add_module(false, true, paths); - let orig_module = mem::replace(&mut self.cx.syntax_env.current_module, module); + let orig_in_block = mem::replace(&mut self.cx.current_expansion.in_block, true); let result = noop_fold_block(block, self); - self.cx.syntax_env.current_module = orig_module; + self.cx.current_expansion.in_block = orig_in_block; result } @@ -613,8 +587,8 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { }) } ast::ItemKind::Mod(ast::Mod { inner, .. }) => { - let mut paths = (*self.cx.syntax_env.paths()).clone(); - paths.mod_path.push(item.ident); + let mut module = (*self.cx.current_expansion.module).clone(); + module.mod_path.push(item.ident); // Detect if this is an inline module (`mod m { ... }` as opposed to `mod m;`). // In the non-inline case, `inner` is never the dummy span (c.f. `parse_item_mod`). @@ -622,28 +596,26 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { let inline_module = item.span.contains(inner) || inner == syntax_pos::DUMMY_SP; if inline_module { - paths.directory.push(&*{ + module.directory.push(&*{ ::attr::first_attr_value_str_by_name(&item.attrs, "path") .unwrap_or(item.ident.name.as_str()) }); } else { - paths.directory = + module.directory = PathBuf::from(self.cx.parse_sess.codemap().span_to_filename(inner)); - paths.directory.pop(); + module.directory.pop(); } - let macro_use = self.contains_macro_use(&item.attrs); - let in_block = self.cx.syntax_env.in_block(); - let module = self.cx.syntax_env.add_module(macro_use, in_block, Rc::new(paths)); - let module = mem::replace(&mut self.cx.syntax_env.current_module, module); + let orig_module = + mem::replace(&mut self.cx.current_expansion.module, Rc::new(module)); let result = noop_fold_item(item, self); - self.cx.syntax_env.current_module = module; - result - }, + self.cx.current_expansion.module = orig_module; + return result; + } ast::ItemKind::ExternCrate(..) => { // We need to error on `#[macro_use] extern crate` when it isn't at the // crate root, because `$crate` won't work properly. - let is_crate_root = self.cx.syntax_env.is_crate_root(); + let is_crate_root = self.cx.current_expansion.module.mod_path.len() == 1; for def in self.cx.resolver.load_crate(&*item, is_crate_root) { match def { LoadedMacro::Def(def) => self.cx.insert_macro(def), diff --git a/src/libsyntax/ext/hygiene.rs b/src/libsyntax/ext/hygiene.rs index 27e8eab62e11..34126fac4ac7 100644 --- a/src/libsyntax/ext/hygiene.rs +++ b/src/libsyntax/ext/hygiene.rs @@ -29,7 +29,7 @@ pub struct SyntaxContextData { pub prev_ctxt: SyntaxContext, } -/// A mark represents a unique id associated with a macro expansion. +/// A mark is a unique id associated with a macro expansion. #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default)] pub struct Mark(u32); @@ -41,6 +41,11 @@ impl Mark { }) } + /// The mark of the theoretical expansion that generates freshly parsed, unexpanded AST. + pub fn root() -> Self { + Mark(0) + } + pub fn as_u32(&self) -> u32 { self.0 } @@ -56,8 +61,8 @@ impl HygieneData { fn new() -> Self { HygieneData { syntax_contexts: vec![SyntaxContextData { - outer_mark: Mark(0), // the null mark - prev_ctxt: SyntaxContext(0), // the empty context + outer_mark: Mark::root(), + prev_ctxt: SyntaxContext::empty(), }], markings: HashMap::new(), next_mark: Mark(1), diff --git a/src/libsyntax/ext/source_util.rs b/src/libsyntax/ext/source_util.rs index 105b22611173..e75e41d0c2d4 100644 --- a/src/libsyntax/ext/source_util.rs +++ b/src/libsyntax/ext/source_util.rs @@ -74,8 +74,8 @@ pub fn expand_stringify(cx: &mut ExtCtxt, sp: Span, tts: &[tokenstream::TokenTre pub fn expand_mod(cx: &mut ExtCtxt, sp: Span, tts: &[tokenstream::TokenTree]) -> Box { base::check_zero_tts(cx, sp, tts, "module_path!"); - let paths = cx.syntax_env.paths(); - let string = paths.mod_path.iter().map(|x| x.to_string()).collect::>().join("::"); + let mod_path = &cx.current_expansion.module.mod_path; + let string = mod_path.iter().map(|x| x.to_string()).collect::>().join("::"); base::MacEager::expr(cx.expr_str( sp, diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index ed80ec9cbc49..51ef45b97be6 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -211,8 +211,8 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt, imported_from, rhs); let mut p = Parser::new(cx.parse_sess(), cx.cfg(), Box::new(trncbr)); - p.directory = cx.syntax_env.paths().directory.clone(); - p.restrictions = match cx.syntax_env.in_block() { + p.directory = cx.current_expansion.module.directory.clone(); + p.restrictions = match cx.current_expansion.in_block { true => Restrictions::NO_NONINLINE_MOD, false => Restrictions::empty(), }; diff --git a/src/libsyntax_ext/deriving/mod.rs b/src/libsyntax_ext/deriving/mod.rs index fcbce3638908..6162beb80ecc 100644 --- a/src/libsyntax_ext/deriving/mod.rs +++ b/src/libsyntax_ext/deriving/mod.rs @@ -11,8 +11,7 @@ //! The compiler code necessary to implement the `#[derive]` extensions. use syntax::ast::{self, MetaItem}; -use syntax::ext::base::{Annotatable, ExtCtxt, SyntaxEnv}; -use syntax::ext::base::MultiModifier; +use syntax::ext::base::{Annotatable, ExtCtxt}; use syntax::ext::build::AstBuilder; use syntax::feature_gate; use syntax::codemap; @@ -89,7 +88,7 @@ fn allow_unstable(cx: &mut ExtCtxt, span: Span, attr_name: &str) -> Span { } } -fn expand_derive(cx: &mut ExtCtxt, +pub fn expand_derive(cx: &mut ExtCtxt, span: Span, mitem: &MetaItem, annotatable: Annotatable) @@ -243,10 +242,6 @@ fn expand_derive(cx: &mut ExtCtxt, macro_rules! derive_traits { ($( $name:expr => $func:path, )+) => { - pub fn register_all(env: &mut SyntaxEnv) { - env.insert(intern("derive"), MultiModifier(Box::new(expand_derive))); - } - pub fn is_builtin_trait(name: &str) -> bool { match name { $( $name )|+ => true, diff --git a/src/libsyntax_ext/lib.rs b/src/libsyntax_ext/lib.rs index 2065d92fd6ed..3a6212e5445c 100644 --- a/src/libsyntax_ext/lib.rs +++ b/src/libsyntax_ext/lib.rs @@ -34,11 +34,6 @@ extern crate syntax_pos; extern crate rustc_macro; extern crate rustc_errors as errors; -use syntax::ext::base::{MacroExpanderFn, NormalTT}; -use syntax::ext::base::{SyntaxEnv, SyntaxExtension}; -use syntax::parse::token::intern; - - mod asm; mod cfg; mod concat; @@ -53,28 +48,67 @@ pub mod rustc_macro_registrar; // for custom_derive pub mod deriving; -pub fn register_builtins(env: &mut SyntaxEnv) { - // utility function to simplify creating NormalTT syntax extensions - fn builtin_normal_expander(f: MacroExpanderFn) -> SyntaxExtension { - NormalTT(Box::new(f), None, false) +use std::rc::Rc; +use syntax::ast; +use syntax::ext::base::{MacroExpanderFn, MacroRulesTT, NormalTT, MultiModifier}; +use syntax::ext::hygiene::Mark; +use syntax::parse::token::intern; + +pub fn register_builtins(resolver: &mut syntax::ext::base::Resolver, enable_quotes: bool) { + let mut register = |name, ext| { + resolver.add_macro(Mark::root(), ast::Ident::with_empty_ctxt(intern(name)), Rc::new(ext)); + }; + + register("macro_rules", MacroRulesTT); + + macro_rules! register { + ($( $name:ident: $f:expr, )*) => { $( + register(stringify!($name), NormalTT(Box::new($f as MacroExpanderFn), None, false)); + )* } } - env.insert(intern("asm"), builtin_normal_expander(asm::expand_asm)); - env.insert(intern("cfg"), builtin_normal_expander(cfg::expand_cfg)); - env.insert(intern("concat"), - builtin_normal_expander(concat::expand_syntax_ext)); - env.insert(intern("concat_idents"), - builtin_normal_expander(concat_idents::expand_syntax_ext)); - env.insert(intern("env"), builtin_normal_expander(env::expand_env)); - env.insert(intern("option_env"), - builtin_normal_expander(env::expand_option_env)); - env.insert(intern("format_args"), - // format_args uses `unstable` things internally. - NormalTT(Box::new(format::expand_format_args), None, true)); - env.insert(intern("log_syntax"), - builtin_normal_expander(log_syntax::expand_syntax_ext)); - env.insert(intern("trace_macros"), - builtin_normal_expander(trace_macros::expand_trace_macros)); + if enable_quotes { + use syntax::ext::quote::*; + register! { + quote_tokens: expand_quote_tokens, + quote_expr: expand_quote_expr, + quote_ty: expand_quote_ty, + quote_item: expand_quote_item, + quote_pat: expand_quote_pat, + quote_arm: expand_quote_arm, + quote_stmt: expand_quote_stmt, + quote_matcher: expand_quote_matcher, + quote_attr: expand_quote_attr, + quote_arg: expand_quote_arg, + quote_block: expand_quote_block, + quote_meta_item: expand_quote_meta_item, + quote_path: expand_quote_path, + } + } - deriving::register_all(env); + use syntax::ext::source_util::*; + register! { + line: expand_line, + column: expand_column, + file: expand_file, + stringify: expand_stringify, + include: expand_include, + include_str: expand_include_str, + include_bytes: expand_include_bytes, + module_path: expand_mod, + + asm: asm::expand_asm, + cfg: cfg::expand_cfg, + concat: concat::expand_syntax_ext, + concat_idents: concat_idents::expand_syntax_ext, + env: env::expand_env, + option_env: env::expand_option_env, + log_syntax: log_syntax::expand_syntax_ext, + trace_macros: trace_macros::expand_trace_macros, + } + + // format_args uses `unstable` things internally. + register("format_args", NormalTT(Box::new(format::expand_format_args), None, true)); + + register("derive", MultiModifier(Box::new(deriving::expand_derive))); } From c86c8d41a26b2037e80c9fd028a59313a78b3a66 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Mon, 5 Sep 2016 00:10:27 +0000 Subject: [PATCH 332/443] Perform node id assignment and `macros_at_scope` construction during the `InvocationCollector` and `PlaceholderExpander` folds. --- src/librustc_driver/driver.rs | 2 - src/librustc_resolve/assign_ids.rs | 92 ------------------------------ src/librustc_resolve/lib.rs | 1 - src/librustc_resolve/macros.rs | 4 ++ src/libsyntax/ext/base.rs | 3 + src/libsyntax/ext/expand.rs | 24 ++++++-- src/libsyntax/ext/placeholders.rs | 61 ++++++++++++++++++-- 7 files changed, 83 insertions(+), 104 deletions(-) delete mode 100644 src/librustc_resolve/assign_ids.rs diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index bf50c96034dd..007222b2edf6 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -707,8 +707,6 @@ pub fn phase_2_configure_and_expand<'a, F>(sess: &Session, &sess.features.borrow()) }); - let krate = time(sess.time_passes(), "assigning node ids", || resolver.assign_node_ids(krate)); - if sess.opts.debugging_opts.input_stats { println!("Post-expansion node count: {}", count_nodes(&krate)); } diff --git a/src/librustc_resolve/assign_ids.rs b/src/librustc_resolve/assign_ids.rs deleted file mode 100644 index a9e3c6ffe9ed..000000000000 --- a/src/librustc_resolve/assign_ids.rs +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use Resolver; -use rustc::session::Session; -use rustc::util::nodemap::FnvHashMap; -use syntax::ast; -use syntax::ext::hygiene::Mark; -use syntax::fold::{self, Folder}; -use syntax::ptr::P; -use syntax::util::move_map::MoveMap; -use syntax::util::small_vector::SmallVector; - -use std::mem; - -impl<'a> Resolver<'a> { - pub fn assign_node_ids(&mut self, krate: ast::Crate) -> ast::Crate { - NodeIdAssigner { - sess: self.session, - macros_at_scope: &mut self.macros_at_scope, - }.fold_crate(krate) - } -} - -struct NodeIdAssigner<'a> { - sess: &'a Session, - macros_at_scope: &'a mut FnvHashMap>, -} - -impl<'a> Folder for NodeIdAssigner<'a> { - fn new_id(&mut self, old_id: ast::NodeId) -> ast::NodeId { - assert_eq!(old_id, ast::DUMMY_NODE_ID); - self.sess.next_node_id() - } - - fn fold_block(&mut self, block: P) -> P { - block.map(|mut block| { - block.id = self.new_id(block.id); - - let stmt = block.stmts.pop(); - let mut macros = Vec::new(); - block.stmts = block.stmts.move_flat_map(|stmt| { - if let ast::StmtKind::Item(ref item) = stmt.node { - if let ast::ItemKind::Mac(..) = item.node { - macros.push(item.ident.ctxt.data().outer_mark); - return None; - } - } - - let stmt = self.fold_stmt(stmt).pop().unwrap(); - if !macros.is_empty() { - self.macros_at_scope.insert(stmt.id, mem::replace(&mut macros, Vec::new())); - } - Some(stmt) - }); - - stmt.and_then(|mut stmt| { - // Avoid wasting a node id on a trailing expression statement, - // which shares a HIR node with the expression itself. - if let ast::StmtKind::Expr(expr) = stmt.node { - let expr = self.fold_expr(expr); - stmt.id = expr.id; - stmt.node = ast::StmtKind::Expr(expr); - Some(stmt) - } else { - self.fold_stmt(stmt).pop() - } - }).map(|stmt| { - if !macros.is_empty() { - self.macros_at_scope.insert(stmt.id, mem::replace(&mut macros, Vec::new())); - } - block.stmts.push(stmt); - }); - - block - }) - } - - fn fold_item(&mut self, item: P) -> SmallVector> { - match item.node { - ast::ItemKind::Mac(..) => SmallVector::zero(), - _ => fold::noop_fold_item(item, self), - } - } -} diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 6bf45ab8f6fa..ad0507c9fb7e 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -84,7 +84,6 @@ mod macros; mod check_unused; mod build_reduced_graph; mod resolve_imports; -mod assign_ids; enum SuggestionType { Macro(String), diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 36f501a54d26..67ee4c307d3c 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -41,6 +41,10 @@ impl<'a> base::Resolver for Resolver<'a> { self.macro_loader.load_crate(extern_crate, allows_macros) } + fn next_node_id(&mut self) -> ast::NodeId { + self.session.next_node_id() + } + fn visit_expansion(&mut self, mark: Mark, expansion: &Expansion) { expansion.visit_with(&mut ExpansionVisitor { current_module: self.expansion_data[mark.as_u32() as usize].module.clone(), diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index d46e2a9872e8..1e8f8ef9ddd6 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -464,6 +464,7 @@ pub type NamedSyntaxExtension = (Name, SyntaxExtension); pub trait Resolver { fn load_crate(&mut self, extern_crate: &ast::Item, allows_macros: bool) -> Vec; + fn next_node_id(&mut self) -> ast::NodeId; fn visit_expansion(&mut self, mark: Mark, expansion: &Expansion); fn add_macro(&mut self, scope: Mark, ident: ast::Ident, ext: Rc); @@ -479,10 +480,12 @@ pub enum LoadedMacro { } pub struct DummyResolver; + impl Resolver for DummyResolver { fn load_crate(&mut self, _extern_crate: &ast::Item, _allows_macros: bool) -> Vec { Vec::new() } + fn next_node_id(&mut self) -> ast::NodeId { ast::DUMMY_NODE_ID } fn visit_expansion(&mut self, _invoc: Mark, _expansion: &Expansion) {} fn add_macro(&mut self, _scope: Mark, _ident: ast::Ident, _ext: Rc) {} diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index beb1687dfdc7..eef38ea28e0f 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -195,6 +195,10 @@ impl<'a, 'b> MacroExpander<'a, 'b> { krate.module.items = self.expand(items).make_items().into(); krate.exported_macros = mem::replace(&mut self.cx.exported_macros, Vec::new()); + for def in &mut krate.exported_macros { + def.id = self.cx.resolver.next_node_id() + } + if self.cx.parse_sess.span_diagnostic.err_count() > err_count { self.cx.parse_sess.span_diagnostic.abort_if_errors(); } @@ -234,7 +238,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { self.cx.current_expansion = orig_expansion_data; - let mut placeholder_expander = PlaceholderExpander::new(); + let mut placeholder_expander = PlaceholderExpander::new(self.cx); while let Some(expansions) = expansions.pop() { for (mark, expansion) in expansions.into_iter().rev() { let expansion = expansion.fold_with(&mut placeholder_expander); @@ -530,9 +534,14 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { None => return SmallVector::zero(), }; - let (mac, style, attrs) = match stmt.node { - StmtKind::Mac(mac) => mac.unwrap(), - _ => return noop_fold_stmt(stmt, self), + let (mac, style, attrs) = if let StmtKind::Mac(mac) = stmt.node { + mac.unwrap() + } else { + // The placeholder expander gives ids to statements, so we avoid folding the id here. + let ast::Stmt { id, node, span } = stmt; + return noop_fold_stmt_kind(node, self).into_iter().map(|node| { + ast::Stmt { id: id, node: node, span: span } + }).collect() }; let mut placeholder = @@ -624,7 +633,7 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { } } } - SmallVector::one(item) + noop_fold_item(item, self) }, _ => noop_fold_item(item, self), } @@ -687,6 +696,11 @@ 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) } + + fn new_id(&mut self, id: ast::NodeId) -> ast::NodeId { + assert_eq!(id, ast::DUMMY_NODE_ID); + self.cx.resolver.next_node_id() + } } pub struct ExpansionConfig<'feat> { diff --git a/src/libsyntax/ext/placeholders.rs b/src/libsyntax/ext/placeholders.rs index abadcf867b14..7635705daa05 100644 --- a/src/libsyntax/ext/placeholders.rs +++ b/src/libsyntax/ext/placeholders.rs @@ -10,13 +10,16 @@ use ast; use codemap::{DUMMY_SP, dummy_spanned}; +use ext::base::ExtCtxt; use ext::expand::{Expansion, ExpansionKind}; use fold::*; use parse::token::keywords; use ptr::P; +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 { @@ -69,13 +72,15 @@ pub fn macro_scope_placeholder() -> Expansion { placeholder(ExpansionKind::Items, ast::DUMMY_NODE_ID) } -pub struct PlaceholderExpander { +pub struct PlaceholderExpander<'a, 'b: 'a> { expansions: HashMap, + cx: &'a mut ExtCtxt<'b>, } -impl PlaceholderExpander { - pub fn new() -> Self { +impl<'a, 'b> PlaceholderExpander<'a, 'b> { + pub fn new(cx: &'a mut ExtCtxt<'b>) -> Self { PlaceholderExpander { + cx: cx, expansions: HashMap::new(), } } @@ -89,7 +94,7 @@ impl PlaceholderExpander { } } -impl Folder for PlaceholderExpander { +impl<'a, 'b> Folder for PlaceholderExpander<'a, 'b> { fn fold_item(&mut self, item: P) -> SmallVector> { match item.node { // Scope placeholder @@ -155,6 +160,54 @@ impl Folder for PlaceholderExpander { _ => noop_fold_ty(ty, self), } } + + 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; + + // Scope placeholder + if let ast::StmtKind::Item(ref item) = stmt.node { + if let ast::ItemKind::Mac(..) = item.node { + macros.push(item.ident.ctxt.data().outer_mark); + return None; + } + } + + match stmt.node { + // Avoid wasting a node id on a trailing expression statement, + // which shares a HIR node with the expression itself. + ast::StmtKind::Expr(ref expr) if remaining_stmts == 0 => stmt.id = expr.id, + + _ => { + assert_eq!(stmt.id, ast::DUMMY_NODE_ID); + stmt.id = self.cx.resolver.next_node_id(); + } + } + + if !macros.is_empty() { + let macros = mem::replace(&mut macros, Vec::new()); + self.cx.resolver.add_expansions_at_stmt(stmt.id, macros); + } + + Some(stmt) + }); + + block + }) + } + + fn fold_mod(&mut self, module: ast::Mod) -> ast::Mod { + let mut module = noop_fold_mod(module, self); + module.items = module.items.move_flat_map(|item| match item.node { + ast::ItemKind::Mac(_) => None, // remove scope placeholders from modules + _ => Some(item), + }); + module + } } pub fn reconstructed_macro_rules(def: &ast::MacroDef, path: &ast::Path) -> Expansion { From f3c2dca3539e6edc745f9c91898cb97d281865c1 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Tue, 6 Sep 2016 01:45:23 +0000 Subject: [PATCH 333/443] Remove scope placeholders from the crate root. --- src/libsyntax/ext/expand.rs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index eef38ea28e0f..0eb9d4bc0c2f 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -191,8 +191,15 @@ impl<'a, 'b> MacroExpander<'a, 'b> { fn expand_crate(&mut self, mut krate: ast::Crate) -> ast::Crate { let err_count = self.cx.parse_sess.span_diagnostic.err_count(); - let items = Expansion::Items(SmallVector::many(krate.module.items)); - krate.module.items = self.expand(items).make_items().into(); + let mut krate_item = placeholder(ExpansionKind::Items, ast::DUMMY_NODE_ID) + .make_items().pop().unwrap().unwrap(); + krate_item.node = ast::ItemKind::Mod(krate.module); + let krate_item = Expansion::Items(SmallVector::one(P(krate_item))); + + krate.module = match self.expand(krate_item).make_items().pop().unwrap().unwrap().node { + ast::ItemKind::Mod(module) => module, + _ => unreachable!(), + }; krate.exported_macros = mem::replace(&mut self.cx.exported_macros, Vec::new()); for def in &mut krate.exported_macros { @@ -596,6 +603,10 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { }) } ast::ItemKind::Mod(ast::Mod { inner, .. }) => { + if item.ident == keywords::Invalid.ident() { + return noop_fold_item(item, self); + } + let mut module = (*self.cx.current_expansion.module).clone(); module.mod_path.push(item.ident); From 78c00398780db6f59ebf43e765fa9368dad436d2 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Tue, 6 Sep 2016 07:52:09 +0000 Subject: [PATCH 334/443] Expand generated test harnesses and macro registries. --- src/librustc_driver/driver.rs | 2 ++ src/libsyntax/test.rs | 30 +++++++++++----------- src/libsyntax_ext/rustc_macro_registrar.rs | 23 ++++++++--------- 3 files changed, 27 insertions(+), 28 deletions(-) diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 007222b2edf6..36e9fccdf5fd 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -690,6 +690,7 @@ pub fn phase_2_configure_and_expand<'a, F>(sess: &Session, krate = time(time_passes, "maybe building test harness", || { syntax::test::modify_for_testing(&sess.parse_sess, + &mut resolver, sess.opts.test, krate, sess.diagnostic()) @@ -700,6 +701,7 @@ pub fn phase_2_configure_and_expand<'a, F>(sess: &Session, let is_rustc_macro_crate = crate_types.contains(&config::CrateTypeRustcMacro); let num_crate_types = crate_types.len(); syntax_ext::rustc_macro_registrar::modify(&sess.parse_sess, + &mut resolver, krate, is_rustc_macro_crate, num_crate_types, diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index dde8a8d271f6..46c9a4606cce 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -28,7 +28,7 @@ use errors; use errors::snippet::{SnippetData}; use config; use entry::{self, EntryPointType}; -use ext::base::{ExtCtxt, DummyResolver}; +use ext::base::{ExtCtxt, Resolver}; use ext::build::AstBuilder; use ext::expand::ExpansionConfig; use fold::Folder; @@ -70,6 +70,7 @@ struct TestCtxt<'a> { // Traverse the crate, collecting all the test functions, eliding any // existing main functions, and synthesizing a main test harness pub fn modify_for_testing(sess: &ParseSess, + resolver: &mut Resolver, should_test: bool, krate: ast::Crate, span_diagnostic: &errors::Handler) -> ast::Crate { @@ -82,7 +83,7 @@ pub fn modify_for_testing(sess: &ParseSess, "reexport_test_harness_main"); if should_test { - generate_test_harness(sess, reexport_test_harness_main, krate, span_diagnostic) + generate_test_harness(sess, resolver, reexport_test_harness_main, krate, span_diagnostic) } else { krate } @@ -248,27 +249,28 @@ fn mk_reexport_mod(cx: &mut TestCtxt, tests: Vec, }).chain(tested_submods.into_iter().map(|(r, sym)| { let path = cx.ext_cx.path(DUMMY_SP, vec![super_, r, sym]); cx.ext_cx.item_use_simple_(DUMMY_SP, ast::Visibility::Public, r, path) - })); + })).collect(); let reexport_mod = ast::Mod { inner: DUMMY_SP, - items: items.collect(), + items: items, }; let sym = token::gensym_ident("__test_reexports"); - let it = P(ast::Item { + let it = cx.ext_cx.expander().fold_item(P(ast::Item { ident: sym.clone(), attrs: Vec::new(), id: ast::DUMMY_NODE_ID, node: ast::ItemKind::Mod(reexport_mod), vis: ast::Visibility::Public, span: DUMMY_SP, - }); + })).pop().unwrap(); (it, sym) } fn generate_test_harness(sess: &ParseSess, + resolver: &mut Resolver, reexport_test_harness_main: Option, krate: ast::Crate, sd: &errors::Handler) -> ast::Crate { @@ -276,13 +278,10 @@ fn generate_test_harness(sess: &ParseSess, let mut cleaner = EntryPointCleaner { depth: 0 }; let krate = cleaner.fold_crate(krate); - let mut resolver = DummyResolver; let mut cx: TestCtxt = TestCtxt { sess: sess, span_diagnostic: sd, - ext_cx: ExtCtxt::new(sess, vec![], - ExpansionConfig::default("test".to_string()), - &mut resolver), + ext_cx: ExtCtxt::new(sess, vec![], ExpansionConfig::default("test".to_string()), resolver), path: Vec::new(), testfns: Vec::new(), reexport_test_harness_main: reexport_test_harness_main, @@ -511,16 +510,17 @@ fn mk_test_module(cx: &mut TestCtxt) -> (P, Option>) { items: vec![import, mainfn, tests], }; let item_ = ast::ItemKind::Mod(testmod); - let mod_ident = token::gensym_ident("__test"); - let item = P(ast::Item { + + let mut expander = cx.ext_cx.expander(); + let item = expander.fold_item(P(ast::Item { id: ast::DUMMY_NODE_ID, ident: mod_ident, attrs: vec![], node: item_, vis: ast::Visibility::Public, span: DUMMY_SP, - }); + })).pop().unwrap(); let reexport = cx.reexport_test_harness_main.as_ref().map(|s| { // building `use = __test::main` let reexport_ident = token::str_to_ident(&s); @@ -529,14 +529,14 @@ fn mk_test_module(cx: &mut TestCtxt) -> (P, Option>) { nospan(ast::ViewPathSimple(reexport_ident, path_node(vec![mod_ident, token::str_to_ident("main")]))); - P(ast::Item { + expander.fold_item(P(ast::Item { id: ast::DUMMY_NODE_ID, ident: keywords::Invalid.ident(), attrs: vec![], node: ast::ItemKind::Use(P(use_path)), vis: ast::Visibility::Inherited, span: DUMMY_SP - }) + })).pop().unwrap() }); debug!("Synthetic test module:\n{}\n", pprust::item_to_string(&item)); diff --git a/src/libsyntax_ext/rustc_macro_registrar.rs b/src/libsyntax_ext/rustc_macro_registrar.rs index 78fed9d33dd8..c07e79179398 100644 --- a/src/libsyntax_ext/rustc_macro_registrar.rs +++ b/src/libsyntax_ext/rustc_macro_registrar.rs @@ -13,12 +13,13 @@ use std::mem; use errors; use syntax::ast::{self, Ident, NodeId}; use syntax::codemap::{ExpnInfo, NameAndSpan, MacroAttribute}; -use syntax::ext::base::{ExtCtxt, DummyResolver}; +use syntax::ext::base::ExtCtxt; use syntax::ext::build::AstBuilder; use syntax::ext::expand::ExpansionConfig; use syntax::parse::ParseSess; use syntax::parse::token::{self, InternedString}; use syntax::feature_gate::Features; +use syntax::fold::Folder; use syntax::ptr::P; use syntax_pos::{Span, DUMMY_SP}; use syntax::visit::{self, Visitor}; @@ -39,16 +40,14 @@ struct CollectCustomDerives<'a> { } pub fn modify(sess: &ParseSess, + resolver: &mut ::syntax::ext::base::Resolver, mut krate: ast::Crate, is_rustc_macro_crate: bool, num_crate_types: usize, handler: &errors::Handler, features: &Features) -> ast::Crate { - let mut loader = DummyResolver; - let mut cx = ExtCtxt::new(sess, - Vec::new(), - ExpansionConfig::default("rustc_macro".to_string()), - &mut loader); + let ecfg = ExpansionConfig::default("rustc_macro".to_string()); + let mut cx = ExtCtxt::new(sess, Vec::new(), ecfg, resolver); let mut collect = CollectCustomDerives { derives: Vec::new(), @@ -268,13 +267,11 @@ fn mk_registrar(cx: &mut ExtCtxt, i.vis = ast::Visibility::Public; i }); - let module = cx.item_mod(span, - span, - ast::Ident::with_empty_ctxt(token::gensym("registrar")), - Vec::new(), - vec![krate, func]); - module.map(|mut i| { + let ident = ast::Ident::with_empty_ctxt(token::gensym("registrar")); + let module = cx.item_mod(span, span, ident, Vec::new(), vec![krate, func]).map(|mut i| { i.vis = ast::Visibility::Public; i - }) + }); + + cx.expander().fold_item(module).pop().unwrap() } From b54e1e399741579612f13e2df98a25ea9447989d Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Tue, 6 Sep 2016 05:42:45 +0000 Subject: [PATCH 335/443] Differentiate between monotonic and non-monotonic expansion and only assign node ids during monotonic expansion. --- src/libsyntax/ext/base.rs | 8 +++++++- src/libsyntax/ext/expand.rs | 24 ++++++++++++++-------- src/libsyntax/ext/placeholders.rs | 10 ++++++--- src/libsyntax/test.rs | 4 ++-- src/libsyntax_ext/rustc_macro_registrar.rs | 2 +- 5 files changed, 32 insertions(+), 16 deletions(-) diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 1e8f8ef9ddd6..fb4816d3847e 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -549,7 +549,13 @@ impl<'a> ExtCtxt<'a> { /// Returns a `Folder` for deeply expanding all macros in an AST node. pub fn expander<'b>(&'b mut self) -> expand::MacroExpander<'b, 'a> { - expand::MacroExpander::new(self, false, false) + expand::MacroExpander::new(self, false) + } + + /// Returns a `Folder` that deeply expands all macros and assigns all node ids in an AST node. + /// Once node ids are assigned, the node may not be expanded, removed, or otherwise modified. + pub fn monotonic_expander<'b>(&'b mut self) -> expand::MacroExpander<'b, 'a> { + expand::MacroExpander::new(self, true) } pub fn new_parser_from_tts(&self, tts: &[tokenstream::TokenTree]) diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 0eb9d4bc0c2f..62e299684b76 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -175,16 +175,16 @@ pub struct MacroExpander<'a, 'b:'a> { pub cx: &'a mut ExtCtxt<'b>, pub single_step: bool, pub keep_macs: bool, + monotonic: bool, // c.f. `cx.monotonic_expander()` } impl<'a, 'b> MacroExpander<'a, 'b> { - pub fn new(cx: &'a mut ExtCtxt<'b>, - single_step: bool, - keep_macs: bool) -> MacroExpander<'a, 'b> { + pub fn new(cx: &'a mut ExtCtxt<'b>, monotonic: bool) -> Self { MacroExpander { cx: cx, - single_step: single_step, - keep_macs: keep_macs + monotonic: monotonic, + single_step: false, + keep_macs: false, } } @@ -245,7 +245,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { self.cx.current_expansion = orig_expansion_data; - let mut placeholder_expander = PlaceholderExpander::new(self.cx); + let mut placeholder_expander = PlaceholderExpander::new(self.cx, self.monotonic); while let Some(expansions) = expansions.pop() { for (mark, expansion) in expansions.into_iter().rev() { let expansion = expansion.fold_with(&mut placeholder_expander); @@ -268,6 +268,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { }, cx: self.cx, invocations: Vec::new(), + monotonic: self.monotonic, }; (expansion.fold_with(&mut collector), collector.invocations) }; @@ -450,6 +451,7 @@ struct InvocationCollector<'a, 'b: 'a> { cx: &'a mut ExtCtxt<'b>, cfg: StripUnconfigured<'a>, invocations: Vec, + monotonic: bool, } macro_rules! fully_configure { @@ -709,8 +711,12 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> { } fn new_id(&mut self, id: ast::NodeId) -> ast::NodeId { - assert_eq!(id, ast::DUMMY_NODE_ID); - self.cx.resolver.next_node_id() + if self.monotonic { + assert_eq!(id, ast::DUMMY_NODE_ID); + self.cx.resolver.next_node_id() + } else { + id + } } } @@ -763,7 +769,7 @@ pub fn expand_crate(cx: &mut ExtCtxt, user_exts: Vec, c: Crate) -> Crate { cx.initialize(user_exts, &c); - cx.expander().expand_crate(c) + cx.monotonic_expander().expand_crate(c) } // Expands crate using supplied MacroExpander - allows for diff --git a/src/libsyntax/ext/placeholders.rs b/src/libsyntax/ext/placeholders.rs index 7635705daa05..47f366a88768 100644 --- a/src/libsyntax/ext/placeholders.rs +++ b/src/libsyntax/ext/placeholders.rs @@ -75,13 +75,15 @@ pub fn macro_scope_placeholder() -> Expansion { pub struct PlaceholderExpander<'a, 'b: 'a> { expansions: HashMap, cx: &'a mut ExtCtxt<'b>, + monotonic: bool, } impl<'a, 'b> PlaceholderExpander<'a, 'b> { - pub fn new(cx: &'a mut ExtCtxt<'b>) -> Self { + pub fn new(cx: &'a mut ExtCtxt<'b>, monotonic: bool) -> Self { PlaceholderExpander { cx: cx, expansions: HashMap::new(), + monotonic: monotonic, } } @@ -182,13 +184,15 @@ impl<'a, 'b> Folder for PlaceholderExpander<'a, 'b> { // which shares a HIR node with the expression itself. ast::StmtKind::Expr(ref expr) if remaining_stmts == 0 => stmt.id = expr.id, - _ => { + _ if self.monotonic => { assert_eq!(stmt.id, ast::DUMMY_NODE_ID); stmt.id = self.cx.resolver.next_node_id(); } + + _ => {} } - if !macros.is_empty() { + if self.monotonic && !macros.is_empty() { let macros = mem::replace(&mut macros, Vec::new()); self.cx.resolver.add_expansions_at_stmt(stmt.id, macros); } diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index 46c9a4606cce..6327e8f71bcd 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -257,7 +257,7 @@ fn mk_reexport_mod(cx: &mut TestCtxt, tests: Vec, }; let sym = token::gensym_ident("__test_reexports"); - let it = cx.ext_cx.expander().fold_item(P(ast::Item { + let it = cx.ext_cx.monotonic_expander().fold_item(P(ast::Item { ident: sym.clone(), attrs: Vec::new(), id: ast::DUMMY_NODE_ID, @@ -512,7 +512,7 @@ fn mk_test_module(cx: &mut TestCtxt) -> (P, Option>) { let item_ = ast::ItemKind::Mod(testmod); let mod_ident = token::gensym_ident("__test"); - let mut expander = cx.ext_cx.expander(); + let mut expander = cx.ext_cx.monotonic_expander(); let item = expander.fold_item(P(ast::Item { id: ast::DUMMY_NODE_ID, ident: mod_ident, diff --git a/src/libsyntax_ext/rustc_macro_registrar.rs b/src/libsyntax_ext/rustc_macro_registrar.rs index c07e79179398..ce3e53cdf97f 100644 --- a/src/libsyntax_ext/rustc_macro_registrar.rs +++ b/src/libsyntax_ext/rustc_macro_registrar.rs @@ -273,5 +273,5 @@ fn mk_registrar(cx: &mut ExtCtxt, i }); - cx.expander().fold_item(module).pop().unwrap() + cx.monotonic_expander().fold_item(module).pop().unwrap() } From 265620225d2fa122c27bb6221bf5afe1797e9e6e Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 13 Sep 2016 07:59:42 -0700 Subject: [PATCH 336/443] rustc: Don't pass --whole-archive for compiler-builtins This flag is intended for rlibs included once, not rlibs that are repeatedly included. --- src/libcompiler_builtins/build.rs | 10 ++++--- src/librustc_trans/back/link.rs | 44 ++++++++++++++++++++----------- 2 files changed, 35 insertions(+), 19 deletions(-) diff --git a/src/libcompiler_builtins/build.rs b/src/libcompiler_builtins/build.rs index fb8e45c1fe13..09c400b52bc8 100644 --- a/src/libcompiler_builtins/build.rs +++ b/src/libcompiler_builtins/build.rs @@ -50,10 +50,12 @@ impl Sources { } fn extend(&mut self, sources: &[&'static str]) { - // NOTE Some intrinsics have both a generic implementation (e.g. `floatdidf.c`) and an arch - // optimized implementation (`x86_64/floatdidf.c`). In those cases, we keep the arch - // optimized implementation and discard the generic implementation. If we don't and keep - // both implementations, the linker will yell at us about duplicate symbols! + // NOTE Some intrinsics have both a generic implementation (e.g. + // `floatdidf.c`) and an arch optimized implementation + // (`x86_64/floatdidf.c`). In those cases, we keep the arch optimized + // implementation and discard the generic implementation. If we don't + // and keep both implementations, the linker will yell at us about + // duplicate symbols! for &src in sources { let symbol = Path::new(src).file_stem().unwrap().to_str().unwrap(); if src.contains("/") { diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index 3433b866691c..288249a7d993 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -943,8 +943,7 @@ fn add_upstream_rust_crates(cmd: &mut Linker, Linkage::NotLinked | Linkage::IncludedFromDylib => {} Linkage::Static => { - add_static_crate(cmd, sess, tmpdir, crate_type, - &src.rlib.unwrap().0, sess.cstore.is_no_builtins(cnum)) + add_static_crate(cmd, sess, tmpdir, crate_type, cnum); } Linkage::Dynamic => { add_dynamic_crate(cmd, sess, &src.dylib.unwrap().0) @@ -956,9 +955,7 @@ fn add_upstream_rust_crates(cmd: &mut Linker, // was already "included" in a dylib (e.g. `libstd` when `-C prefer-dynamic` // is used) if let Some(cnum) = compiler_builtins { - let src = sess.cstore.used_crate_source(cnum); - add_static_crate(cmd, sess, tmpdir, crate_type, - &src.rlib.unwrap().0, sess.cstore.is_no_builtins(cnum)); + add_static_crate(cmd, sess, tmpdir, crate_type, cnum); } // Converts a library file-stem into a cc -l argument @@ -1006,8 +1003,9 @@ fn add_upstream_rust_crates(cmd: &mut Linker, sess: &Session, tmpdir: &Path, crate_type: config::CrateType, - cratepath: &Path, - is_a_no_builtins_crate: bool) { + cnum: ast::CrateNum) { + let src = sess.cstore.used_crate_source(cnum); + let cratepath = &src.rlib.unwrap().0; if !sess.lto() && crate_type != config::CrateTypeDylib { cmd.link_rlib(&fix_windows_verbatim_for_gcc(cratepath)); return @@ -1031,7 +1029,13 @@ fn add_upstream_rust_crates(cmd: &mut Linker, } let canonical = f.replace("-", "_"); let canonical_name = name.replace("-", "_"); - if sess.lto() && !is_a_no_builtins_crate && + + // If we're performing LTO and this is a rust-generated object + // file, then we don't need the object file as it's part of the + // LTO module. Note that `#![no_builtins]` is excluded from LTO, + // though, so we let that object file slide. + if sess.lto() && + !sess.cstore.is_no_builtins(cnum) && canonical.starts_with(&canonical_name) && canonical.ends_with(".o") { let num = &f[name.len()..f.len() - 2]; @@ -1043,13 +1047,23 @@ fn add_upstream_rust_crates(cmd: &mut Linker, any_objects = true; } - if any_objects { - archive.build(); - if crate_type == config::CrateTypeDylib { - cmd.link_whole_rlib(&fix_windows_verbatim_for_gcc(&dst)); - } else { - cmd.link_rlib(&fix_windows_verbatim_for_gcc(&dst)); - } + if !any_objects { + return + } + archive.build(); + + // If we're creating a dylib, then we need to include the + // whole of each object in our archive into that artifact. This is + // because a `dylib` can be reused as an intermediate artifact. + // + // Note, though, that we don't want to include the whole of a + // compiler-builtins crate (e.g. compiler-rt) because it'll get + // repeatedly linked anyway. + if crate_type == config::CrateTypeDylib && + !sess.cstore.is_compiler_builtins(cnum) { + cmd.link_whole_rlib(&fix_windows_verbatim_for_gcc(&dst)); + } else { + cmd.link_rlib(&fix_windows_verbatim_for_gcc(&dst)); } }); } From 5a881e920ec39c80310ff832867f2ef51168a1de Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Mon, 12 Sep 2016 18:09:49 -0400 Subject: [PATCH 337/443] Make sure that projection bounds in ty::TraitObject are sorted in a way that is stable across compilation sessions and crate boundaries. --- src/librustc/ty/context.rs | 2 +- src/librustc/ty/mod.rs | 4 ---- src/librustc/ty/sty.rs | 21 ++++++++++++--------- src/librustc/ty/trait_def.rs | 10 ++++++++-- src/librustc_metadata/decoder.rs | 4 +++- src/librustc_typeck/collect.rs | 5 ++++- 6 files changed, 28 insertions(+), 18 deletions(-) diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 20601493d68f..6d7a2d6cba1c 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -1303,7 +1303,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } pub fn mk_trait(self, mut obj: TraitObject<'tcx>) -> Ty<'tcx> { - obj.projection_bounds.sort_by(|a, b| a.sort_key().cmp(&b.sort_key())); + obj.projection_bounds.sort_by_key(|b| b.sort_key(self)); self.mk_ty(TyTrait(box obj)) } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index f634c8e37d7b..14eb2fb7914c 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1018,10 +1018,6 @@ impl<'tcx> PolyProjectionPredicate<'tcx> { pub fn item_name(&self) -> Name { self.0.projection_ty.item_name // safe to skip the binder to access a name } - - pub fn sort_key(&self) -> (DefId, Name) { - self.0.projection_ty.sort_key() - } } pub trait ToPolyTraitRef<'tcx> { diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index a755dd056cd8..5fdc7abc0af5 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -23,7 +23,7 @@ use std::mem; use std::ops; use syntax::abi; use syntax::ast::{self, Name}; -use syntax::parse::token::keywords; +use syntax::parse::token::{keywords, InternedString}; use serialize::{Decodable, Decoder, Encodable, Encoder}; @@ -440,12 +440,6 @@ pub struct ProjectionTy<'tcx> { pub item_name: Name, } -impl<'tcx> ProjectionTy<'tcx> { - pub fn sort_key(&self) -> (DefId, Name) { - (self.trait_ref.def_id, self.item_name) - } -} - #[derive(Clone, PartialEq, Eq, Hash, Debug)] pub struct BareFnTy<'tcx> { pub unsafety: hir::Unsafety, @@ -738,8 +732,17 @@ impl<'a, 'tcx, 'gcx> PolyExistentialProjection<'tcx> { self.0.item_name // safe to skip the binder to access a name } - pub fn sort_key(&self) -> (DefId, Name) { - (self.0.trait_ref.def_id, self.0.item_name) + pub fn sort_key(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> (u64, InternedString) { + // We want something here that is stable across crate boundaries. + // The DefId isn't but the `deterministic_hash` of the corresponding + // DefPath is. + let trait_def = tcx.lookup_trait_def(self.0.trait_ref.def_id); + let def_path_hash = trait_def.def_path_hash; + + // An `ast::Name` is also not stable (it's just an index into an + // interning table), so map to the corresponding `InternedString`. + let item_name = self.0.item_name.as_str(); + (def_path_hash, item_name) } pub fn with_self_ty(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, diff --git a/src/librustc/ty/trait_def.rs b/src/librustc/ty/trait_def.rs index 61285e8f8b0a..268b2fcaa4ad 100644 --- a/src/librustc/ty/trait_def.rs +++ b/src/librustc/ty/trait_def.rs @@ -70,7 +70,11 @@ pub struct TraitDef<'tcx> { pub specialization_graph: RefCell, /// Various flags - pub flags: Cell + pub flags: Cell, + + /// The ICH of this trait's DefPath, cached here so it doesn't have to be + /// recomputed all the time. + pub def_path_hash: u64, } impl<'a, 'gcx, 'tcx> TraitDef<'tcx> { @@ -78,7 +82,8 @@ impl<'a, 'gcx, 'tcx> TraitDef<'tcx> { paren_sugar: bool, generics: &'tcx ty::Generics<'tcx>, trait_ref: ty::TraitRef<'tcx>, - associated_type_names: Vec) + associated_type_names: Vec, + def_path_hash: u64) -> TraitDef<'tcx> { TraitDef { paren_sugar: paren_sugar, @@ -90,6 +95,7 @@ impl<'a, 'gcx, 'tcx> TraitDef<'tcx> { blanket_impls: RefCell::new(vec![]), flags: Cell::new(ty::TraitFlags::NO_TRAIT_FLAGS), specialization_graph: RefCell::new(traits::specialization_graph::Graph::new()), + def_path_hash: def_path_hash, } } diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index d2840fbe4fe4..824e892072f5 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -385,12 +385,14 @@ pub fn get_trait_def<'a, 'tcx>(cdata: Cmd, let unsafety = parse_unsafety(item_doc); let associated_type_names = parse_associated_type_names(item_doc); let paren_sugar = parse_paren_sugar(item_doc); + let def_path = def_path(cdata, item_id); ty::TraitDef::new(unsafety, paren_sugar, generics, item_trait_ref(item_doc, tcx, cdata), - associated_type_names) + associated_type_names, + def_path.deterministic_hash(tcx)) } pub fn get_adt_def<'a, 'tcx>(cdata: Cmd, diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 7d111cdc4156..04aca8c0947c 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1290,12 +1290,15 @@ fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, } }).collect(); + let def_path_hash = tcx.def_path(def_id).deterministic_hash(tcx); + let trait_ref = ty::TraitRef::new(def_id, substs); let trait_def = ty::TraitDef::new(unsafety, paren_sugar, ty_generics, trait_ref, - associated_type_names); + associated_type_names, + def_path_hash); tcx.intern_trait_def(trait_def) } From 5c923f0159105bf9491a86cd5bd7eb20807387b6 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Mon, 12 Sep 2016 18:24:45 -0400 Subject: [PATCH 338/443] Remove redundant sorting of projection bounds in tyencode. --- src/librustc_metadata/tyencode.rs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/librustc_metadata/tyencode.rs b/src/librustc_metadata/tyencode.rs index 8030abf6330e..dbefd3eacc24 100644 --- a/src/librustc_metadata/tyencode.rs +++ b/src/librustc_metadata/tyencode.rs @@ -104,14 +104,7 @@ pub fn enc_ty<'a, 'tcx>(w: &mut Cursor>, cx: &ctxt<'a, 'tcx>, t: Ty<'tcx enc_region(w, cx, obj.region_bound); - // Encode projection_bounds in a stable order - let mut projection_bounds: Vec<_> = obj.projection_bounds - .iter() - .map(|b| (b.item_name().as_str(), b)) - .collect(); - projection_bounds.sort_by_key(|&(ref name, _)| name.clone()); - - for tp in projection_bounds.iter().map(|&(_, tp)| tp) { + for tp in &obj.projection_bounds { write!(w, "P"); enc_existential_projection(w, cx, &tp.0); } From 94d75013bcf6fc8e79cd7c0c76c37e68c458db6f Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 13 Sep 2016 08:40:14 -0400 Subject: [PATCH 339/443] Remove redundant sorting of projections in TypeIdHasher. --- src/librustc/ty/util.rs | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 6b3ebaa895fa..c6020838b532 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -458,15 +458,11 @@ impl<'a, 'gcx, 'tcx> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tcx> { data.region_bound.visit_with(self); self.hash(data.builtin_bounds); - // Only projection bounds are left, sort and hash them. - let mut projection_bounds: Vec<_> = data.projection_bounds - .iter() - .map(|b| (b.item_name().as_str(), b)) - .collect(); - projection_bounds.sort_by_key(|&(ref name, _)| name.clone()); - for (name, bound) in projection_bounds { + // Only projection bounds are left, hash them. + self.hash(data.projection_bounds.len()); + for bound in &data.projection_bounds { self.def_id(bound.0.trait_ref.def_id); - self.hash(name); + self.hash(bound.0.item_name); bound.visit_with(self); } From 75a0dd0fca4e3e3b5eade66fb3dddc2b9868dc52 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 13 Sep 2016 08:45:34 -0400 Subject: [PATCH 340/443] Make TypeIdHasher use DefPath::deterministic_hash() for stability. --- src/librustc/ty/util.rs | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index c6020838b532..a8287ecc046c 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -411,15 +411,11 @@ impl<'a, 'gcx, 'tcx> TypeIdHasher<'a, 'gcx, 'tcx> { } fn def_id(&mut self, did: DefId) { - // Hash the crate identification information. - let name = self.tcx.crate_name(did.krate); - let disambiguator = self.tcx.crate_disambiguator(did.krate); - self.hash((name, disambiguator)); - - // Hash the item path within that crate. - // FIXME(#35379) This should use a deterministic - // DefPath hashing mechanism, not the DefIndex. - self.hash(did.index); + // Hash the DefPath corresponding to the DefId, which is independent + // of compiler internal state. + let tcx = self.tcx; + let def_path = tcx.def_path(did); + def_path.deterministic_hash_to(tcx, &mut self.state); } } From 869d14447af84bfb506e19abf2ca97810845c675 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 13 Sep 2016 15:02:17 -0400 Subject: [PATCH 341/443] TypeIdHasher: Let projections be hashed implicitly by the visitor. --- src/librustc/ty/util.rs | 11 ----------- src/test/run-pass/auxiliary/typeid-intrinsic-aux1.rs | 5 +++++ src/test/run-pass/auxiliary/typeid-intrinsic-aux2.rs | 5 +++++ src/test/run-pass/typeid-intrinsic.rs | 9 +++++++++ 4 files changed, 19 insertions(+), 11 deletions(-) diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index a8287ecc046c..344f0e57d642 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -453,17 +453,6 @@ impl<'a, 'gcx, 'tcx> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tcx> { // Hash region and builtin bounds. data.region_bound.visit_with(self); self.hash(data.builtin_bounds); - - // Only projection bounds are left, hash them. - self.hash(data.projection_bounds.len()); - for bound in &data.projection_bounds { - self.def_id(bound.0.trait_ref.def_id); - self.hash(bound.0.item_name); - bound.visit_with(self); - } - - // Bypass super_visit_with, we've visited everything. - return false; } TyTuple(tys) => { self.hash(tys.len()); diff --git a/src/test/run-pass/auxiliary/typeid-intrinsic-aux1.rs b/src/test/run-pass/auxiliary/typeid-intrinsic-aux1.rs index 42c0da6286bd..10e315f269f9 100644 --- a/src/test/run-pass/auxiliary/typeid-intrinsic-aux1.rs +++ b/src/test/run-pass/auxiliary/typeid-intrinsic-aux1.rs @@ -22,6 +22,8 @@ pub type F = Option; pub type G = usize; pub type H = &'static str; pub type I = Box; +pub type I32Iterator = Iterator; +pub type U32Iterator = Iterator; pub fn id_A() -> TypeId { TypeId::of::() } pub fn id_B() -> TypeId { TypeId::of::() } @@ -34,3 +36,6 @@ pub fn id_H() -> TypeId { TypeId::of::() } pub fn id_I() -> TypeId { TypeId::of::() } pub fn foo() -> TypeId { TypeId::of::() } + +pub fn id_i32_iterator() -> TypeId { TypeId::of::() } +pub fn id_u32_iterator() -> TypeId { TypeId::of::() } diff --git a/src/test/run-pass/auxiliary/typeid-intrinsic-aux2.rs b/src/test/run-pass/auxiliary/typeid-intrinsic-aux2.rs index 42c0da6286bd..10e315f269f9 100644 --- a/src/test/run-pass/auxiliary/typeid-intrinsic-aux2.rs +++ b/src/test/run-pass/auxiliary/typeid-intrinsic-aux2.rs @@ -22,6 +22,8 @@ pub type F = Option; pub type G = usize; pub type H = &'static str; pub type I = Box; +pub type I32Iterator = Iterator; +pub type U32Iterator = Iterator; pub fn id_A() -> TypeId { TypeId::of::() } pub fn id_B() -> TypeId { TypeId::of::() } @@ -34,3 +36,6 @@ pub fn id_H() -> TypeId { TypeId::of::() } pub fn id_I() -> TypeId { TypeId::of::() } pub fn foo() -> TypeId { TypeId::of::() } + +pub fn id_i32_iterator() -> TypeId { TypeId::of::() } +pub fn id_u32_iterator() -> TypeId { TypeId::of::() } diff --git a/src/test/run-pass/typeid-intrinsic.rs b/src/test/run-pass/typeid-intrinsic.rs index e99a5f69af40..36650368d57b 100644 --- a/src/test/run-pass/typeid-intrinsic.rs +++ b/src/test/run-pass/typeid-intrinsic.rs @@ -78,4 +78,13 @@ pub fn main() { b.hash(&mut s2); assert_eq!(s1.finish(), s2.finish()); + + // Check projections + + assert_eq!(TypeId::of::(), other1::id_i32_iterator()); + assert_eq!(TypeId::of::(), other1::id_u32_iterator()); + assert_eq!(other1::id_i32_iterator(), other2::id_i32_iterator()); + assert_eq!(other1::id_u32_iterator(), other2::id_u32_iterator()); + assert!(other1::id_i32_iterator() != other1::id_u32_iterator()); + assert!(TypeId::of::() != TypeId::of::()); } From 848cfe20a01b3d43d4c9838bd7d9b0da32dace42 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 13 Sep 2016 12:27:26 -0700 Subject: [PATCH 342/443] Link test to compiler builtins and make unstable This commit fixes a test which now needs to explicitly link to the `compiler_builtins` crate as well as makes the `compiler_builtins` crate unstable. --- src/libcompiler_builtins/lib.rs | 5 ++++- src/libstd/lib.rs | 1 + src/test/run-make/no-duplicate-libs/bar.rs | 3 ++- src/test/run-make/no-duplicate-libs/foo.rs | 3 ++- 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/libcompiler_builtins/lib.rs b/src/libcompiler_builtins/lib.rs index ad1d1edbeba2..fbcf5204d253 100644 --- a/src/libcompiler_builtins/lib.rs +++ b/src/libcompiler_builtins/lib.rs @@ -11,6 +11,9 @@ #![cfg_attr(not(stage0), feature(compiler_builtins))] #![no_std] #![cfg_attr(not(stage0), compiler_builtins)] - +#![unstable(feature = "compiler_builtins_lib", + reason = "internal implementation detail of rustc right now", + issue = "0")] #![crate_name = "compiler_builtins"] #![crate_type = "rlib"] +#![feature(staged_api)] diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index d227fb1404f4..115a24fc83c2 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -224,6 +224,7 @@ #![feature(char_internals)] #![feature(collections)] #![feature(collections_bound)] +#![feature(compiler_builtins_lib)] #![feature(const_fn)] #![feature(core_float)] #![feature(core_intrinsics)] diff --git a/src/test/run-make/no-duplicate-libs/bar.rs b/src/test/run-make/no-duplicate-libs/bar.rs index 8a15afb328a9..b82fdeb8f369 100644 --- a/src/test/run-make/no-duplicate-libs/bar.rs +++ b/src/test/run-make/no-duplicate-libs/bar.rs @@ -8,11 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(lang_items, libc)] +#![feature(lang_items, libc, compiler_builtins_lib)] #![crate_type = "dylib"] #![no_std] extern crate libc; +extern crate compiler_builtins; #[no_mangle] pub extern fn bar() {} diff --git a/src/test/run-make/no-duplicate-libs/foo.rs b/src/test/run-make/no-duplicate-libs/foo.rs index ab8d2eca9363..cbdee356838d 100644 --- a/src/test/run-make/no-duplicate-libs/foo.rs +++ b/src/test/run-make/no-duplicate-libs/foo.rs @@ -8,11 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(lang_items, libc)] +#![feature(lang_items, libc, compiler_builtins_lib)] #![no_std] #![crate_type = "dylib"] extern crate libc; +extern crate compiler_builtins; #[no_mangle] pub extern fn foo() {} From 377c3e1123dd63689ccfddb5d37699f31846caf5 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 13 Sep 2016 15:46:21 -0400 Subject: [PATCH 343/443] Fix rebasing fallout. --- src/librustc_metadata/decoder.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 824e892072f5..624bffb7e036 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -385,7 +385,7 @@ pub fn get_trait_def<'a, 'tcx>(cdata: Cmd, let unsafety = parse_unsafety(item_doc); let associated_type_names = parse_associated_type_names(item_doc); let paren_sugar = parse_paren_sugar(item_doc); - let def_path = def_path(cdata, item_id); + let def_path = def_path(cdata, item_id).unwrap(); ty::TraitDef::new(unsafety, paren_sugar, From 7ec9b81326121ae07feb0a19f76b3f16b98d0c43 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 13 Sep 2016 16:01:39 -0400 Subject: [PATCH 344/443] TypeIdHasher: Remove more redundant explicit visit calls. --- src/librustc/ty/util.rs | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 344f0e57d642..d34fdaa7d71c 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -441,17 +441,7 @@ impl<'a, 'gcx, 'tcx> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tcx> { self.hash(f.sig.variadic()); } TyTrait(ref data) => { - // Trait objects have a list of projection bounds - // that are not guaranteed to be sorted in an order - // that gets preserved across crates, so we need - // to sort them again by the name, in string form. - - // Hash the whole principal trait ref. self.def_id(data.principal.def_id()); - data.principal.visit_with(self); - - // Hash region and builtin bounds. - data.region_bound.visit_with(self); self.hash(data.builtin_bounds); } TyTuple(tys) => { From b49a26ec6fe2faf06360139b4c6ed59684b083b4 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 13 Sep 2016 16:04:27 -0400 Subject: [PATCH 345/443] invoke drop glue with a ptr to (data, meta) This is done by creating a little space on the stack. Hokey, but it's the simplest fix I can see. --- src/librustc_trans/glue.rs | 9 ++++++++- src/librustc_trans/intrinsic.rs | 1 + src/librustc_trans/mir/block.rs | 24 +++++++++++++++++++++--- 3 files changed, 30 insertions(+), 4 deletions(-) diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs index 6b48c6ae26da..3073b1dbfaee 100644 --- a/src/librustc_trans/glue.rs +++ b/src/librustc_trans/glue.rs @@ -296,6 +296,7 @@ fn trans_custom_dtor<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, sized_args = [v0]; &sized_args } else { + // FIXME(#36457) -- we should pass unsized values to drop glue as two arguments unsized_args = [ Load(bcx, get_dataptr(bcx, v0)), Load(bcx, get_meta(bcx, v0)) @@ -440,7 +441,9 @@ pub fn size_and_align_of_dst<'blk, 'tcx>(bcx: &BlockAndBuilder<'blk, 'tcx>, } } -fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, g: DropGlueKind<'tcx>) +fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, + v0: ValueRef, + g: DropGlueKind<'tcx>) -> Block<'blk, 'tcx> { let t = g.ty(); @@ -463,6 +466,7 @@ fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, g: DropGlueK let llval = get_dataptr(bcx, v0); let llbox = Load(bcx, llval); let bcx = drop_ty(bcx, v0, content_ty, DebugLoc::None); + // FIXME(#36457) -- we should pass unsized values to drop glue as two arguments let info = get_meta(bcx, v0); let info = Load(bcx, info); let (llsize, llalign) = @@ -488,6 +492,7 @@ fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, g: DropGlueK // No support in vtable for distinguishing destroying with // versus without calling Drop::drop. Assert caller is // okay with always calling the Drop impl, if any. + // FIXME(#36457) -- we should pass unsized values to drop glue as two arguments assert!(!skip_dtor); let data_ptr = get_dataptr(bcx, v0); let vtable_ptr = Load(bcx, get_meta(bcx, v0)); @@ -543,6 +548,7 @@ fn drop_structural_ty<'blk, 'tcx>(cx: Block<'blk, 'tcx>, let value = if type_is_sized(cx.tcx(), t) { adt::MaybeSizedValue::sized(av) } else { + // FIXME(#36457) -- we should pass unsized values as two arguments let data = Load(cx, get_dataptr(cx, av)); let info = Load(cx, get_meta(cx, av)); adt::MaybeSizedValue::unsized_(data, info) @@ -586,6 +592,7 @@ fn drop_structural_ty<'blk, 'tcx>(cx: Block<'blk, 'tcx>, let val = if type_is_sized(cx.tcx(), field_ty) { llfld_a } else { + // FIXME(#36457) -- we should pass unsized values as two arguments let scratch = alloc_ty(cx, field_ty, "__fat_ptr_iter"); Store(cx, llfld_a, get_dataptr(cx, scratch)); Store(cx, value.meta, get_meta(cx, scratch)); diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs index 2049696ee4f7..fbade107ecfd 100644 --- a/src/librustc_trans/intrinsic.rs +++ b/src/librustc_trans/intrinsic.rs @@ -186,6 +186,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, let ptr = if is_sized { llargs[0] } else { + // FIXME(#36457) -- we should pass unsized values as two arguments let scratch = alloc_ty(bcx, tp_ty, "drop"); call_lifetime_start(bcx, scratch); Store(bcx, llargs[0], get_dataptr(bcx, scratch)); diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs index fbd04d7b3802..baeafbe3e346 100644 --- a/src/librustc_trans/mir/block.rs +++ b/src/librustc_trans/mir/block.rs @@ -242,10 +242,28 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { let lvalue = self.trans_lvalue(&bcx, location); let drop_fn = glue::get_drop_glue(bcx.ccx(), ty); let drop_ty = glue::get_drop_glue_type(bcx.tcx(), ty); - let llvalue = if drop_ty != ty { - bcx.pointercast(lvalue.llval, type_of::type_of(bcx.ccx(), drop_ty).ptr_to()) + let is_sized = common::type_is_sized(bcx.tcx(), ty); + let llvalue = if is_sized { + if drop_ty != ty { + bcx.pointercast(lvalue.llval, type_of::type_of(bcx.ccx(), drop_ty).ptr_to()) + } else { + lvalue.llval + } } else { - lvalue.llval + // FIXME(#36457) Currently drop glue takes sized + // values as a `*(data, meta)`, but elsewhere in + // MIR we pass `(data, meta)` as two separate + // arguments. It would be better to fix drop glue, + // but I am shooting for a quick fix to #35546 + // here that can be cleanly backported to beta, so + // I want to avoid touching all of trans. + bcx.with_block(|bcx| { + let scratch = base::alloc_ty(bcx, ty, "drop"); + base::call_lifetime_start(bcx, scratch); + build::Store(bcx, lvalue.llval, base::get_dataptr(bcx, scratch)); + build::Store(bcx, lvalue.llextra, base::get_meta(bcx, scratch)); + scratch + }) }; if let Some(unwind) = unwind { bcx.invoke(drop_fn, From 4b6c4c08df7f4685daf0fa2cfe127b06216176d6 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 26 Aug 2016 19:23:42 +0300 Subject: [PATCH 346/443] Remove some ancient code providing special support for newtypes --- src/librustc/middle/mem_categorization.rs | 4 --- src/librustc_metadata/encoder.rs | 28 --------------------- src/librustc_resolve/build_reduced_graph.rs | 4 +-- src/librustc_trans/adt.rs | 2 +- src/librustdoc/clean/inline.rs | 11 ++++---- src/librustdoc/doctree.rs | 21 ++++++---------- src/librustdoc/html/render.rs | 2 +- 7 files changed, 16 insertions(+), 56 deletions(-) diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 39d5487e8beb..5594ac413e23 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -223,10 +223,6 @@ fn deref_kind(t: Ty, context: DerefKindContext) -> McResult { Ok(deref_ptr(UnsafePtr(mt.mutbl))) } - ty::TyAdt(..) => { // newtype - Ok(deref_interior(InteriorField(PositionalField(0)))) - } - ty::TyArray(..) | ty::TySlice(_) => { // no deref of indexed content without supplying InteriorOffsetKind if let Some(context) = context { diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 603b7a483b90..e228bf743026 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -252,27 +252,6 @@ impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> { } } -/// Iterates through "auxiliary node IDs", which are node IDs that describe -/// top-level items that are sub-items of the given item. Specifically: -/// -/// * For newtype structs, iterates through the node ID of the constructor. -fn each_auxiliary_node_id(item: &hir::Item, callback: F) -> bool where - F: FnOnce(NodeId) -> bool, -{ - let mut continue_ = true; - match item.node { - hir::ItemStruct(ref struct_def, _) => { - // If this is a newtype struct, return the constructor. - if struct_def.is_tuple() { - continue_ = callback(struct_def.id()); - } - } - _ => {} - } - - continue_ -} - fn encode_reexports(ecx: &EncodeContext, rbml_w: &mut Encoder, id: NodeId) { @@ -313,13 +292,6 @@ impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> { for item_id in &md.item_ids { self.rbml_w.wr_tagged_u64(tag_mod_child, def_to_u64(ecx.tcx.map.local_def_id(item_id.id))); - - let item = ecx.tcx.map.expect_item(item_id.id); - each_auxiliary_node_id(item, |auxiliary_node_id| { - self.rbml_w.wr_tagged_u64(tag_mod_child, - def_to_u64(ecx.tcx.map.local_def_id(auxiliary_node_id))); - true - }); } self.encode_visibility(vis); diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index ad750ccc0129..83f03e7cfc5a 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -261,8 +261,8 @@ impl<'b> Resolver<'b> { let def = Def::Struct(self.definitions.local_def_id(item.id)); self.define(parent, name, TypeNS, (def, sp, vis)); - // If this is a newtype or unit-like struct, define a name - // in the value namespace as well + // If this is a tuple or unit struct, define a name + // in the value namespace as well. if !struct_def.is_struct() { let def = Def::Struct(self.definitions.local_def_id(struct_def.id())); self.define(parent, name, ValueNS, (def, sp, vis)); diff --git a/src/librustc_trans/adt.rs b/src/librustc_trans/adt.rs index e8498363e45a..67e5ec2616d2 100644 --- a/src/librustc_trans/adt.rs +++ b/src/librustc_trans/adt.rs @@ -231,7 +231,7 @@ fn represent_type_uncached<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, } if cases.len() == 1 && hint == attr::ReprAny { - // Equivalent to a struct/tuple/newtype. + // Equivalent to a struct or tuple. return Univariant(mk_struct(cx, &cases[0].tys, false, t)); } diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index f1b907e70d74..709e36989244 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -19,7 +19,7 @@ use rustc::middle::cstore; use rustc::hir::def::Def; use rustc::hir::def_id::DefId; use rustc::hir::print as pprust; -use rustc::ty::{self, TyCtxt}; +use rustc::ty::{self, TyCtxt, VariantKind}; use rustc::util::nodemap::FnvHashSet; use rustc_const_eval::lookup_const_by_id; @@ -207,11 +207,10 @@ fn build_struct<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>, let variant = tcx.lookup_adt_def(did).struct_variant(); clean::Struct { - struct_type: match &variant.fields[..] { - &[] => doctree::Unit, - &[_] if variant.kind == ty::VariantKind::Tuple => doctree::Newtype, - &[..] if variant.kind == ty::VariantKind::Tuple => doctree::Tuple, - _ => doctree::Plain, + struct_type: match variant.kind { + VariantKind::Struct => doctree::Plain, + VariantKind::Tuple => doctree::Tuple, + VariantKind::Unit => doctree::Unit, }, generics: (t.generics, &predicates).clean(cx), fields: variant.fields.clean(cx), diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs index cc62fcfa0aa8..c2404f4294e9 100644 --- a/src/librustdoc/doctree.rs +++ b/src/librustdoc/doctree.rs @@ -82,14 +82,12 @@ impl Module { #[derive(Debug, Clone, RustcEncodable, RustcDecodable, Copy)] pub enum StructType { - /// A normal struct + /// A braced struct Plain, /// A tuple struct Tuple, - /// A newtype struct (tuple struct with one element) - Newtype, /// A unit struct - Unit + Unit, } pub enum TypeBound { @@ -262,15 +260,10 @@ pub struct Import { pub whence: Span, } -pub fn struct_type_from_def(sd: &hir::VariantData) -> StructType { - if !sd.is_struct() { - // We are in a tuple-struct - match sd.fields().len() { - 0 => Unit, - 1 => Newtype, - _ => Tuple - } - } else { - Plain +pub fn struct_type_from_def(vdata: &hir::VariantData) -> StructType { + match *vdata { + hir::VariantData::Struct(..) => Plain, + hir::VariantData::Tuple(..) => Tuple, + hir::VariantData::Unit(..) => Unit, } } diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 6da7423edb89..df6b3239cd86 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -2537,7 +2537,7 @@ fn render_struct(w: &mut fmt::Formatter, it: &clean::Item, } write!(w, "}}")?; } - doctree::Tuple | doctree::Newtype => { + doctree::Tuple => { write!(w, "(")?; for (i, field) in fields.iter().enumerate() { if i > 0 { From 03161e9b12621364d44b7fb85694ddf9901ce50f Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 26 Aug 2016 19:23:42 +0300 Subject: [PATCH 347/443] Remove some more dead code from mem categorization --- src/librustc/middle/mem_categorization.rs | 98 +++++------------------ 1 file changed, 20 insertions(+), 78 deletions(-) diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 5594ac413e23..c419f96e8209 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -67,7 +67,6 @@ pub use self::ElementKind::*; pub use self::MutabilityCategory::*; pub use self::AliasableReason::*; pub use self::Note::*; -pub use self::deref_kind::*; use self::Aliasability::*; @@ -195,47 +194,6 @@ pub struct cmt_<'tcx> { pub type cmt<'tcx> = Rc>; -// We pun on *T to mean both actual deref of a ptr as well -// as accessing of components: -#[derive(Copy, Clone)] -pub enum deref_kind<'tcx> { - deref_ptr(PointerKind<'tcx>), - deref_interior(InteriorKind), -} - -type DerefKindContext = Option; - -// Categorizes a derefable type. Note that we include vectors and strings as -// derefable (we model an index as the combination of a deref and then a -// pointer adjustment). -fn deref_kind(t: Ty, context: DerefKindContext) -> McResult { - match t.sty { - ty::TyBox(_) => { - Ok(deref_ptr(Unique)) - } - - ty::TyRef(r, mt) => { - let kind = ty::BorrowKind::from_mutbl(mt.mutbl); - Ok(deref_ptr(BorrowedPtr(kind, r))) - } - - ty::TyRawPtr(ref mt) => { - Ok(deref_ptr(UnsafePtr(mt.mutbl))) - } - - ty::TyArray(..) | ty::TySlice(_) => { - // no deref of indexed content without supplying InteriorOffsetKind - if let Some(context) = context { - Ok(deref_interior(InteriorElement(context, ElementKind::VecElement))) - } else { - Err(()) - } - } - - _ => Err(()), - } -} - pub trait ast_node { fn id(&self) -> ast::NodeId; fn span(&self) -> Span; @@ -472,7 +430,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { autoderefs, cmt); for deref in 1..autoderefs + 1 { - cmt = self.cat_deref(expr, cmt, deref, None)?; + cmt = self.cat_deref(expr, cmt, deref)?; } return Ok(cmt); } @@ -484,7 +442,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { match expr.node { hir::ExprUnary(hir::UnDeref, ref e_base) => { let base_cmt = self.cat_expr(&e_base)?; - self.cat_deref(expr, base_cmt, 0, None) + self.cat_deref(expr, base_cmt, 0) } hir::ExprField(ref base, f_name) => { @@ -503,7 +461,6 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { hir::ExprIndex(ref base, _) => { let method_call = ty::MethodCall::expr(expr.id()); - let context = InteriorOffsetKind::Index; match self.infcx.node_method_ty(method_call) { Some(method_ty) => { // If this is an index implemented by a method call, then it @@ -525,10 +482,10 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { // is an rvalue. That is what we will be // dereferencing. let base_cmt = self.cat_rvalue_node(expr.id(), expr.span(), ret_ty); - self.cat_deref_common(expr, base_cmt, 1, elem_ty, Some(context), true) + Ok(self.cat_deref_common(expr, base_cmt, 1, elem_ty, true)) } None => { - self.cat_index(expr, self.cat_expr(&base)?, context) + self.cat_index(expr, self.cat_expr(&base)?, InteriorOffsetKind::Index) } } } @@ -903,8 +860,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { fn cat_deref(&self, node: &N, base_cmt: cmt<'tcx>, - deref_cnt: usize, - deref_context: DerefKindContext) + deref_cnt: usize) -> McResult> { let method_call = ty::MethodCall { expr_id: node.id(), @@ -926,12 +882,9 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { let base_cmt_ty = base_cmt.ty; match base_cmt_ty.builtin_deref(true, ty::NoPreference) { Some(mt) => { - let ret = self.cat_deref_common(node, base_cmt, deref_cnt, - mt.ty, - deref_context, - /* implicit: */ false); + let ret = self.cat_deref_common(node, base_cmt, deref_cnt, mt.ty, false); debug!("cat_deref ret {:?}", ret); - ret + Ok(ret) } None => { debug!("Explicit deref of non-derefable type: {:?}", @@ -946,40 +899,29 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { base_cmt: cmt<'tcx>, deref_cnt: usize, deref_ty: Ty<'tcx>, - deref_context: DerefKindContext, implicit: bool) - -> McResult> + -> cmt<'tcx> { - let (m, cat) = match deref_kind(base_cmt.ty, deref_context)? { - deref_ptr(ptr) => { - let ptr = if implicit { - match ptr { - BorrowedPtr(bk, r) => Implicit(bk, r), - _ => span_bug!(node.span(), - "Implicit deref of non-borrowed pointer") - } - } else { - ptr - }; - // for unique ptrs, we inherit mutability from the - // owning reference. - (MutabilityCategory::from_pointer_kind(base_cmt.mutbl, ptr), - Categorization::Deref(base_cmt, deref_cnt, ptr)) - } - deref_interior(interior) => { - (base_cmt.mutbl.inherit(), Categorization::Interior(base_cmt, interior)) + let ptr = match base_cmt.ty.sty { + ty::TyBox(..) => Unique, + ty::TyRawPtr(ref mt) => UnsafePtr(mt.mutbl), + ty::TyRef(r, mt) => { + let bk = ty::BorrowKind::from_mutbl(mt.mutbl); + if implicit { Implicit(bk, r) } else { BorrowedPtr(bk, r) } } + ref ty => bug!("unexpected type in cat_deref_common: {:?}", ty) }; let ret = Rc::new(cmt_ { id: node.id(), span: node.span(), - cat: cat, - mutbl: m, + // For unique ptrs, we inherit mutability from the owning reference. + mutbl: MutabilityCategory::from_pointer_kind(base_cmt.mutbl, ptr), + cat: Categorization::Deref(base_cmt, deref_cnt, ptr), ty: deref_ty, note: NoteNone }); debug!("cat_deref_common ret {:?}", ret); - Ok(ret) + ret } pub fn cat_index(&self, @@ -1202,7 +1144,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { // box p1, &p1, &mut p1. we can ignore the mutability of // PatKind::Ref since that information is already contained // in the type. - let subcmt = self.cat_deref(pat, cmt, 0, None)?; + let subcmt = self.cat_deref(pat, cmt, 0)?; self.cat_pattern_(subcmt, &subpat, op)?; } From b57f1099b577d4d388cc5236fb6990275c028b5b Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 26 Aug 2016 19:23:42 +0300 Subject: [PATCH 348/443] Remove parsing of obsolete pre-1.0 syntaxes --- src/libsyntax/parse/obsolete.rs | 15 ++------- src/libsyntax/parse/parser.rs | 33 +------------------- src/test/parse-fail/obsolete-closure-kind.rs | 18 ----------- 3 files changed, 4 insertions(+), 62 deletions(-) delete mode 100644 src/test/parse-fail/obsolete-closure-kind.rs diff --git a/src/libsyntax/parse/obsolete.rs b/src/libsyntax/parse/obsolete.rs index a1d7ddcdf4bd..a46a788ca080 100644 --- a/src/libsyntax/parse/obsolete.rs +++ b/src/libsyntax/parse/obsolete.rs @@ -19,8 +19,7 @@ use parse::parser; /// The specific types of unsupported syntax #[derive(Copy, Clone, PartialEq, Eq, Hash)] pub enum ObsoleteSyntax { - ClosureKind, - ExternCrateString, + // Nothing here at the moment } pub trait ParserObsoleteMethods { @@ -36,18 +35,10 @@ pub trait ParserObsoleteMethods { impl<'a> ParserObsoleteMethods for parser::Parser<'a> { /// Reports an obsolete syntax non-fatal error. + #[allow(unused_variables)] fn obsolete(&mut self, sp: Span, kind: ObsoleteSyntax) { let (kind_str, desc, error) = match kind { - ObsoleteSyntax::ClosureKind => ( - "`:`, `&mut:`, or `&:`", - "rely on inference instead", - true, - ), - ObsoleteSyntax::ExternCrateString => ( - "\"crate-name\"", - "use an identifier not in quotes instead", - false, // warning for now - ), + // Nothing here at the moment }; self.report(sp, kind, kind_str, desc, error); diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 6a0e40edded5..d0936fd981b5 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -47,7 +47,7 @@ use parse; use parse::classify; use parse::common::SeqSep; use parse::lexer::{Reader, TokenAndSpan}; -use parse::obsolete::{ParserObsoleteMethods, ObsoleteSyntax}; +use parse::obsolete::ObsoleteSyntax; use parse::token::{self, intern, MatchNt, SubstNt, SpecialVarNt, InternedString}; use parse::token::{keywords, SpecialMacroVar}; use parse::{new_sub_parser_from_file, ParseSess}; @@ -1165,36 +1165,6 @@ impl<'a> Parser<'a> { }))) } - /// Parses an obsolete closure kind (`&:`, `&mut:`, or `:`). - pub fn parse_obsolete_closure_kind(&mut self) -> PResult<'a, ()> { - let lo = self.span.lo; - if - self.check(&token::BinOp(token::And)) && - self.look_ahead(1, |t| t.is_keyword(keywords::Mut)) && - self.look_ahead(2, |t| *t == token::Colon) - { - self.bump(); - self.bump(); - self.bump(); - } else if - self.token == token::BinOp(token::And) && - self.look_ahead(1, |t| *t == token::Colon) - { - self.bump(); - self.bump(); - } else if - self.eat(&token::Colon) - { - /* nothing */ - } else { - return Ok(()); - } - - let span = mk_sp(lo, self.span.hi); - self.obsolete(span, ObsoleteSyntax::ClosureKind); - Ok(()) - } - pub fn parse_unsafety(&mut self) -> PResult<'a, Unsafety> { if self.eat_keyword(keywords::Unsafe) { return Ok(Unsafety::Unsafe); @@ -4728,7 +4698,6 @@ impl<'a> Parser<'a> { Vec::new() } else { self.expect(&token::BinOp(token::Or))?; - self.parse_obsolete_closure_kind()?; let args = self.parse_seq_to_before_end( &token::BinOp(token::Or), SeqSep::trailing_allowed(token::Comma), diff --git a/src/test/parse-fail/obsolete-closure-kind.rs b/src/test/parse-fail/obsolete-closure-kind.rs deleted file mode 100644 index 89134e806a75..000000000000 --- a/src/test/parse-fail/obsolete-closure-kind.rs +++ /dev/null @@ -1,18 +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. - -// Test that we generate obsolete syntax errors around usages of closure kinds: `|:|`, `|&:|` and -// `|&mut:|`. - -fn main() { - let a = |:| {}; //~ ERROR obsolete syntax: `:`, `&mut:`, or `&:` - let a = |&:| {}; //~ ERROR obsolete syntax: `:`, `&mut:`, or `&:` - let a = |&mut:| {}; //~ ERROR obsolete syntax: `:`, `&mut:`, or `&:` -} From 693676da4f65a14fbae2c44cd4e2a94ba0ccf6d5 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 13 Sep 2016 18:33:35 -0400 Subject: [PATCH 349/443] add missing test --- src/test/run-pass/issue-35546.rs | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 src/test/run-pass/issue-35546.rs diff --git a/src/test/run-pass/issue-35546.rs b/src/test/run-pass/issue-35546.rs new file mode 100644 index 000000000000..e8d14f1d4214 --- /dev/null +++ b/src/test/run-pass/issue-35546.rs @@ -0,0 +1,28 @@ +// 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. + +// Regression test for #35546. Check that we are able to codegen +// this. Before we had problems because of the drop glue signature +// around dropping a trait object (specifically, when dropping the +// `value` field of `Node`). + +struct Node { + next: Option>>, + value: T, +} + +fn clear(head: &mut Option>>) { + match head.take() { + Some(node) => *head = node.next, + None => (), + } +} + +fn main() {} From 606cdede0deaa6678fe7db3cc12b1a1e063012ee Mon Sep 17 00:00:00 2001 From: Eugene Bulkin Date: Tue, 13 Sep 2016 17:21:54 -0700 Subject: [PATCH 350/443] Add checked operation methods to Duration --- src/libstd/time/duration.rs | 162 ++++++++++++++++++++++++++++++++++++ 1 file changed, 162 insertions(+) diff --git a/src/libstd/time/duration.rs b/src/libstd/time/duration.rs index 79bbe5e7daa4..12e580fe8018 100644 --- a/src/libstd/time/duration.rs +++ b/src/libstd/time/duration.rs @@ -97,6 +97,130 @@ impl Duration { #[stable(feature = "duration", since = "1.3.0")] #[inline] pub fn subsec_nanos(&self) -> u32 { self.nanos } + + /// Checked duration addition. Computes `self + other`, returning `None` + /// if overflow occurred. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// assert_eq!(Duration::new(0, 0).checked_add(Duration::new(0, 1)), Some(Duration::new(0, 1))); + /// assert_eq!(Duration::new(1, 0).checked_add(Duration::new(::u64::MAX, 0)), None); + /// ``` + #[unstable(feature = "duration_checked_ops", issue = "35774")] + #[inline] + pub fn checked_add(self, rhs: Duration) -> Option { + if let Some(mut secs) = self.secs.checked_add(rhs.secs) { + let mut nanos = self.nanos + rhs.nanos; + if nanos >= NANOS_PER_SEC { + nanos -= NANOS_PER_SEC; + if let Some(new_secs) = secs.checked_add(1) { + secs = new_secs; + } else { + return None; + } + } + debug_assert!(nanos < NANOS_PER_SEC); + Some(Duration { + secs: secs, + nanos: nanos, + }) + } else { + None + } + } + + /// Checked duration subtraction. Computes `self + other`, returning `None` + /// if the result would be negative or if underflow occurred. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// assert_eq!(Duration::new(0, 1).checked_sub(Duration::new(0, 0)), Some(Duration::new(0, 1))); + /// assert_eq!(Duration::new(0, 0).checked_sub(Duration::new(0, 1)), None); + /// ``` + #[unstable(feature = "duration_checked_ops", issue = "35774")] + #[inline] + pub fn checked_sub(self, rhs: Duration) -> Option { + if let Some(mut secs) = self.secs.checked_sub(rhs.secs) { + let nanos = if self.nanos >= rhs.nanos { + self.nanos - rhs.nanos + } else { + if let Some(sub_secs) = secs.checked_sub(1) { + secs = sub_secs; + self.nanos + NANOS_PER_SEC - rhs.nanos + } else { + return None; + } + }; + debug_assert!(nanos < NANOS_PER_SEC); + Some(Duration { secs: secs, nanos: nanos }) + } else { + None + } + } + + /// Checked integer multiplication. Computes `self * other`, returning + /// `None` if underflow or overflow occurred. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// assert_eq!(Duration::new(0, 500_000_001).checked_mul(2), Some(Duration::new(1, 2))); + /// assert_eq!(Duration::new(::u64::MAX - 1, 0).checked_mul(2), None); + /// ``` + #[unstable(feature = "duration_checked_ops", issue = "35774")] + #[inline] + pub fn checked_mul(self, rhs: u32) -> Option { + // Multiply nanoseconds as u64, because it cannot overflow that way. + let total_nanos = self.nanos as u64 * rhs as u64; + let extra_secs = total_nanos / (NANOS_PER_SEC as u64); + let nanos = (total_nanos % (NANOS_PER_SEC as u64)) as u32; + if let Some(secs) = self.secs + .checked_mul(rhs as u64) + .and_then(|s| s.checked_add(extra_secs)) { + debug_assert!(nanos < NANOS_PER_SEC); + Some(Duration { + secs: secs, + nanos: nanos, + }) + } else { + None + } + } + + /// Checked duration division. Computes `self / other`, returning `None` + /// if `other == 0` or the operation results in underflow or overflow. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// assert_eq!(Duration::new(2, 0).checked_div(2), Some(Duration::new(1, 0))); + /// assert_eq!(Duration::new(1, 0).checked_div(2), Some(Duration::new(0, 500_000_000))); + /// assert_eq!(Duration::new(2, 0).checked_div(0), None); + /// ``` + #[unstable(feature = "duration_checked_ops", issue = "35774")] + #[inline] + pub fn checked_div(self, rhs: u32) -> Option { + if rhs != 0 { + let secs = self.secs / (rhs as u64); + let carry = self.secs - secs * (rhs as u64); + let extra_nanos = carry * (NANOS_PER_SEC as u64) / (rhs as u64); + let nanos = self.nanos / rhs + (extra_nanos as u32); + debug_assert!(nanos < NANOS_PER_SEC); + Some(Duration { secs: secs, nanos: nanos }) + } else { + None + } + } } #[stable(feature = "duration", since = "1.3.0")] @@ -234,6 +358,15 @@ mod tests { Duration::new(1, 1)); } + #[test] + fn checked_add() { + assert_eq!(Duration::new(0, 0).checked_add(Duration::new(0, 1)), + Some(Duration::new(0, 1))); + assert_eq!(Duration::new(0, 500_000_000).checked_add(Duration::new(0, 500_000_001)), + Some(Duration::new(1, 1))); + assert_eq!(Duration::new(1, 0).checked_add(Duration::new(::u64::MAX, 0)), None); + } + #[test] fn sub() { assert_eq!(Duration::new(0, 1) - Duration::new(0, 0), @@ -244,6 +377,18 @@ mod tests { Duration::new(0, 999_999_999)); } + #[test] + fn checked_sub() { + let zero = Duration::new(0, 0); + let one_nano = Duration::new(0, 1); + let one_sec = Duration::new(1, 0); + assert_eq!(one_nano.checked_sub(zero), Some(Duration::new(0, 1))); + assert_eq!(one_sec.checked_sub(one_nano), + Some(Duration::new(0, 999_999_999))); + assert_eq!(zero.checked_sub(one_nano), None); + assert_eq!(zero.checked_sub(one_sec), None); + } + #[test] #[should_panic] fn sub_bad1() { Duration::new(0, 0) - Duration::new(0, 1); @@ -263,6 +408,16 @@ mod tests { Duration::new(2000, 4000)); } + #[test] + fn checked_mul() { + assert_eq!(Duration::new(0, 1).checked_mul(2), Some(Duration::new(0, 2))); + assert_eq!(Duration::new(1, 1).checked_mul(3), Some(Duration::new(3, 3))); + assert_eq!(Duration::new(0, 500_000_001).checked_mul(4), Some(Duration::new(2, 4))); + assert_eq!(Duration::new(0, 500_000_001).checked_mul(4000), + Some(Duration::new(2000, 4000))); + assert_eq!(Duration::new(::u64::MAX - 1, 0).checked_mul(2), None); + } + #[test] fn div() { assert_eq!(Duration::new(0, 1) / 2, Duration::new(0, 0)); @@ -270,4 +425,11 @@ mod tests { assert_eq!(Duration::new(99, 999_999_000) / 100, Duration::new(0, 999_999_990)); } + + #[test] + fn checked_div() { + assert_eq!(Duration::new(2, 0).checked_div(2), Some(Duration::new(1, 0))); + assert_eq!(Duration::new(1, 0).checked_div(2), Some(Duration::new(0, 500_000_000))); + assert_eq!(Duration::new(2, 0).checked_div(0), None); + } } From 07b41b5555f2582ce741569ce44116451105742c Mon Sep 17 00:00:00 2001 From: Eugene Bulkin Date: Tue, 13 Sep 2016 17:32:24 -0700 Subject: [PATCH 351/443] Fix Duration::checked_mul documentation --- src/libstd/time/duration.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/time/duration.rs b/src/libstd/time/duration.rs index 12e580fe8018..3024a44a208a 100644 --- a/src/libstd/time/duration.rs +++ b/src/libstd/time/duration.rs @@ -164,7 +164,7 @@ impl Duration { } } - /// Checked integer multiplication. Computes `self * other`, returning + /// Checked duration multiplication. Computes `self * other`, returning /// `None` if underflow or overflow occurred. /// /// # Examples From b1bcd185b01e1aee3a6c2e976e915b244626e129 Mon Sep 17 00:00:00 2001 From: Eugene Bulkin Date: Tue, 13 Sep 2016 17:58:45 -0700 Subject: [PATCH 352/443] Implement add, sub, mul and div methods using checked methods for Duration --- src/libstd/time/duration.rs | 39 ++++--------------------------------- 1 file changed, 4 insertions(+), 35 deletions(-) diff --git a/src/libstd/time/duration.rs b/src/libstd/time/duration.rs index 3024a44a208a..a3493f0593c8 100644 --- a/src/libstd/time/duration.rs +++ b/src/libstd/time/duration.rs @@ -228,15 +228,7 @@ impl Add for Duration { type Output = Duration; fn add(self, rhs: Duration) -> Duration { - let mut secs = self.secs.checked_add(rhs.secs) - .expect("overflow when adding durations"); - let mut nanos = self.nanos + rhs.nanos; - if nanos >= NANOS_PER_SEC { - nanos -= NANOS_PER_SEC; - secs = secs.checked_add(1).expect("overflow when adding durations"); - } - debug_assert!(nanos < NANOS_PER_SEC); - Duration { secs: secs, nanos: nanos } + self.checked_add(rhs).expect("overflow when adding durations") } } @@ -252,17 +244,7 @@ impl Sub for Duration { type Output = Duration; fn sub(self, rhs: Duration) -> Duration { - let mut secs = self.secs.checked_sub(rhs.secs) - .expect("overflow when subtracting durations"); - let nanos = if self.nanos >= rhs.nanos { - self.nanos - rhs.nanos - } else { - secs = secs.checked_sub(1) - .expect("overflow when subtracting durations"); - self.nanos + NANOS_PER_SEC - rhs.nanos - }; - debug_assert!(nanos < NANOS_PER_SEC); - Duration { secs: secs, nanos: nanos } + self.checked_sub(rhs).expect("overflow when subtracting durations") } } @@ -278,15 +260,7 @@ impl Mul for Duration { type Output = Duration; fn mul(self, rhs: u32) -> Duration { - // Multiply nanoseconds as u64, because it cannot overflow that way. - let total_nanos = self.nanos as u64 * rhs as u64; - let extra_secs = total_nanos / (NANOS_PER_SEC as u64); - let nanos = (total_nanos % (NANOS_PER_SEC as u64)) as u32; - let secs = self.secs.checked_mul(rhs as u64) - .and_then(|s| s.checked_add(extra_secs)) - .expect("overflow when multiplying duration"); - debug_assert!(nanos < NANOS_PER_SEC); - Duration { secs: secs, nanos: nanos } + self.checked_mul(rhs).expect("overflow when multiplying duration by scalar") } } @@ -302,12 +276,7 @@ impl Div for Duration { type Output = Duration; fn div(self, rhs: u32) -> Duration { - let secs = self.secs / (rhs as u64); - let carry = self.secs - secs * (rhs as u64); - let extra_nanos = carry * (NANOS_PER_SEC as u64) / (rhs as u64); - let nanos = self.nanos / rhs + (extra_nanos as u32); - debug_assert!(nanos < NANOS_PER_SEC); - Duration { secs: secs, nanos: nanos } + self.checked_div(rhs).expect("divide by zero error when dividing duration by scalar") } } From fae439b92f68a67444814243d4951943a43b0273 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Tue, 13 Sep 2016 22:07:38 -0400 Subject: [PATCH 353/443] Add doc examples for std::net::IpAddr construction. --- src/libstd/net/ip.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/libstd/net/ip.rs b/src/libstd/net/ip.rs index c6a7a77e68a6..05ef559422f3 100644 --- a/src/libstd/net/ip.rs +++ b/src/libstd/net/ip.rs @@ -22,6 +22,24 @@ use sys::net::netc as c; use sys_common::{AsInner, FromInner}; /// An IP address, either an IPv4 or IPv6 address. +/// +/// # Examples +/// +/// Constructing an IPv4 address: +/// +/// ``` +/// use std::net::{IpAddr, Ipv4Addr}; +/// +/// IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)); +/// ``` +/// +/// Constructing an IPv6 address: +/// +/// ``` +/// use std::net::{IpAddr, Ipv6Addr}; +/// +/// IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)); +/// ``` #[stable(feature = "ip_addr", since = "1.7.0")] #[derive(Copy, Clone, Eq, PartialEq, Debug, Hash, PartialOrd, Ord)] pub enum IpAddr { From 1b3a588f55c84d4fc36f4889f4c7ef7357ad471a Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 13 Sep 2016 22:09:22 -0400 Subject: [PATCH 354/443] trans: Let the collector find drop-glue for all vtables, not just VTableImpl. --- src/librustc_trans/collector.rs | 13 ++++++----- .../instantiation-through-vtable.rs | 2 -- .../codegen-units/item-collection/unsizing.rs | 2 -- .../partitioning/vtable-through-const.rs | 2 -- src/test/run-pass/issue36260.rs | 22 +++++++++++++++++++ 5 files changed, 29 insertions(+), 12 deletions(-) create mode 100644 src/test/run-pass/issue36260.rs diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index 5a8ab62a2aa2..a58de71ca41e 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -497,7 +497,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { self.output); } } - mir::Rvalue::Box(_) => { + mir::Rvalue::Box(..) => { let exchange_malloc_fn_def_id = self.scx .tcx() @@ -1072,15 +1072,16 @@ fn create_trans_items_for_vtable_methods<'a, 'tcx>(scx: &SharedCrateContext<'a, }); output.extend(items); - - // Also add the destructor - let dg_type = glue::get_drop_glue_type(scx.tcx(), - trait_ref.self_ty()); - output.push(TransItem::DropGlue(DropGlueKind::Ty(dg_type))); } _ => { /* */ } } } + + // Also add the destructor + let dg_type = glue::get_drop_glue_type(scx.tcx(), impl_ty); + if glue::type_needs_drop(scx.tcx(), dg_type) { + output.push(TransItem::DropGlue(DropGlueKind::Ty(dg_type))); + } } } diff --git a/src/test/codegen-units/item-collection/instantiation-through-vtable.rs b/src/test/codegen-units/item-collection/instantiation-through-vtable.rs index 06e547f0dd03..b77252512200 100644 --- a/src/test/codegen-units/item-collection/instantiation-through-vtable.rs +++ b/src/test/codegen-units/item-collection/instantiation-through-vtable.rs @@ -40,5 +40,3 @@ fn main() { //~ TRANS_ITEM fn instantiation_through_vtable::{{impl}}[0]::bar[0] let _ = &s1 as &Trait; } - -//~ TRANS_ITEM drop-glue i8 diff --git a/src/test/codegen-units/item-collection/unsizing.rs b/src/test/codegen-units/item-collection/unsizing.rs index 5c67ab7a8264..45ba441bc8ba 100644 --- a/src/test/codegen-units/item-collection/unsizing.rs +++ b/src/test/codegen-units/item-collection/unsizing.rs @@ -78,5 +78,3 @@ fn main() //~ TRANS_ITEM fn unsizing::{{impl}}[3]::foo[0] let _wrapper_sized = wrapper_sized as Wrapper; } - -//~ TRANS_ITEM drop-glue i8 diff --git a/src/test/codegen-units/partitioning/vtable-through-const.rs b/src/test/codegen-units/partitioning/vtable-through-const.rs index b40bb7f60973..ee5e97cd9c21 100644 --- a/src/test/codegen-units/partitioning/vtable-through-const.rs +++ b/src/test/codegen-units/partitioning/vtable-through-const.rs @@ -89,5 +89,3 @@ fn main() { //~ TRANS_ITEM fn vtable_through_const::mod1[0]::id[0] @@ vtable_through_const[Internal] mod1::ID_CHAR('x'); } - -//~ TRANS_ITEM drop-glue i8 diff --git a/src/test/run-pass/issue36260.rs b/src/test/run-pass/issue36260.rs new file mode 100644 index 000000000000..08dbbb5c9fe1 --- /dev/null +++ b/src/test/run-pass/issue36260.rs @@ -0,0 +1,22 @@ +// 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. + +// Make sure this compiles without getting a linker error because of missing +// drop-glue because the collector missed adding drop-glue for the closure: + +fn create_fn() -> Box { + let text = String::new(); + + Box::new(move || { let _ = &text; }) +} + +fn main() { + let _ = create_fn(); +} From 4715985b07184c3027456bdea74e9fde639b9bcc Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 14 Sep 2016 15:57:16 +1000 Subject: [PATCH 355/443] Remove unused Token::to_binop function. --- src/libsyntax/parse/token.rs | 27 +-------------------------- 1 file changed, 1 insertion(+), 26 deletions(-) diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index ff01d3758154..09bc5607946d 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -14,7 +14,7 @@ pub use self::DelimToken::*; pub use self::Lit::*; pub use self::Token::*; -use ast::{self, BinOpKind}; +use ast::{self}; use ptr::P; use util::interner::Interner; use tokenstream; @@ -258,31 +258,6 @@ impl Token { self.is_path_segment_keyword() || self.is_ident() && !self.is_any_keyword() } - /// Maps a token to its corresponding binary operator. - pub fn to_binop(&self) -> Option { - match *self { - BinOp(Star) => Some(BinOpKind::Mul), - BinOp(Slash) => Some(BinOpKind::Div), - BinOp(Percent) => Some(BinOpKind::Rem), - BinOp(Plus) => Some(BinOpKind::Add), - BinOp(Minus) => Some(BinOpKind::Sub), - BinOp(Shl) => Some(BinOpKind::Shl), - BinOp(Shr) => Some(BinOpKind::Shr), - BinOp(And) => Some(BinOpKind::BitAnd), - BinOp(Caret) => Some(BinOpKind::BitXor), - BinOp(Or) => Some(BinOpKind::BitOr), - Lt => Some(BinOpKind::Lt), - Le => Some(BinOpKind::Le), - Ge => Some(BinOpKind::Ge), - Gt => Some(BinOpKind::Gt), - EqEq => Some(BinOpKind::Eq), - Ne => Some(BinOpKind::Ne), - AndAnd => Some(BinOpKind::And), - OrOr => Some(BinOpKind::Or), - _ => None, - } - } - /// Returns `true` if the token is a given keyword, `kw`. pub fn is_keyword(&self, kw: keywords::Keyword) -> bool { match *self { From 6353e30bb2d7968332217c04ac25e0800500fb33 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 13 Sep 2016 18:31:26 -0400 Subject: [PATCH 356/443] clear obligations-added flag with nested fulfillcx This flag is a debugging measure designed to detect cases where we start a snapshot, create type variables, register obligations involving those type variables in the fulfillment cx, and then have to unroll the snapshot, leaving "dangling type variables" behind. HOWEVER, in some cases the flag is wrong. In particular, we sometimes create a "mini-fulfilment-cx" in which we enroll obligations. As long as this fulfillment cx is fully drained before we return, this is not a problem, as there won't be any escaping obligations in the main cx. So we add a fn to save/restore the flag. --- src/librustc/infer/mod.rs | 27 +++++++++++++++ src/librustc/traits/specialize/mod.rs | 46 ++++++++++++++------------ src/test/compile-fail/issue-36053-2.rs | 21 ++++++++++++ src/test/run-pass/issue-36053.rs | 32 ++++++++++++++++++ 4 files changed, 104 insertions(+), 22 deletions(-) create mode 100644 src/test/compile-fail/issue-36053-2.rs create mode 100644 src/test/run-pass/issue-36053.rs diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 59431f3f02dc..39fc50666a8c 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -830,6 +830,33 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { result.map(move |t| InferOk { value: t, obligations: fields.obligations }) } + // Clear the "obligations in snapshot" flag, invoke the closure, + // then restore the flag to its original value. This flag is a + // debugging measure designed to detect cases where we start a + // snapshot, create type variables, register obligations involving + // those type variables in the fulfillment cx, and then have to + // unroll the snapshot, leaving "dangling type variables" behind. + // In such cases, the flag will be set by the fulfillment cx, and + // an assertion will fail when rolling the snapshot back. Very + // useful, much better than grovelling through megabytes of + // RUST_LOG output. + // + // HOWEVER, in some cases the flag is wrong. In particular, we + // sometimes create a "mini-fulfilment-cx" in which we enroll + // obligations. As long as this fulfillment cx is fully drained + // before we return, this is not a problem, as there won't be any + // escaping obligations in the main cx. In those cases, you can + // use this function. + pub fn save_and_restore_obligations_in_snapshot_flag(&self, func: F) -> R + where F: FnOnce(&Self) -> R + { + let flag = self.obligations_in_snapshot.get(); + self.obligations_in_snapshot.set(false); + let result = func(self); + self.obligations_in_snapshot.set(flag); + result + } + fn start_snapshot(&self) -> CombinedSnapshot { debug!("start_snapshot()"); diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs index f3ba4d16eb0b..2f63526bf6c2 100644 --- a/src/librustc/traits/specialize/mod.rs +++ b/src/librustc/traits/specialize/mod.rs @@ -203,32 +203,34 @@ fn fulfill_implication<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, // attempt to prove all of the predicates for impl2 given those for impl1 // (which are packed up in penv) - let mut fulfill_cx = FulfillmentContext::new(); - for oblig in obligations.into_iter() { - fulfill_cx.register_predicate_obligation(&infcx, oblig); - } - match fulfill_cx.select_all_or_error(infcx) { - Err(errors) => { - // no dice! - debug!("fulfill_implication: for impls on {:?} and {:?}, could not fulfill: {:?} given \ - {:?}", - source_trait_ref, - target_trait_ref, - errors, - infcx.parameter_environment.caller_bounds); - Err(()) + infcx.save_and_restore_obligations_in_snapshot_flag(|infcx| { + let mut fulfill_cx = FulfillmentContext::new(); + for oblig in obligations.into_iter() { + fulfill_cx.register_predicate_obligation(&infcx, oblig); } + match fulfill_cx.select_all_or_error(infcx) { + Err(errors) => { + // no dice! + debug!("fulfill_implication: for impls on {:?} and {:?}, \ + could not fulfill: {:?} given {:?}", + source_trait_ref, + target_trait_ref, + errors, + infcx.parameter_environment.caller_bounds); + Err(()) + } - Ok(()) => { - debug!("fulfill_implication: an impl for {:?} specializes {:?}", - source_trait_ref, - target_trait_ref); + Ok(()) => { + debug!("fulfill_implication: an impl for {:?} specializes {:?}", + source_trait_ref, + target_trait_ref); - // Now resolve the *substitution* we built for the target earlier, replacing - // the inference variables inside with whatever we got from fulfillment. - Ok(infcx.resolve_type_vars_if_possible(&target_substs)) + // Now resolve the *substitution* we built for the target earlier, replacing + // the inference variables inside with whatever we got from fulfillment. + Ok(infcx.resolve_type_vars_if_possible(&target_substs)) + } } - } + }) } pub struct SpecializesCache { diff --git a/src/test/compile-fail/issue-36053-2.rs b/src/test/compile-fail/issue-36053-2.rs new file mode 100644 index 000000000000..7da529487aa8 --- /dev/null +++ b/src/test/compile-fail/issue-36053-2.rs @@ -0,0 +1,21 @@ +// 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. + +// Regression test for #36053. ICE was caused due to obligations +// being added to a special, dedicated fulfillment cx during +// a probe. + +use std::iter::once; +fn main() { + once::<&str>("str").fuse().filter(|a: &str| true).count(); + //~^ ERROR no method named `count` + //~| ERROR E0281 + //~| ERROR E0281 +} diff --git a/src/test/run-pass/issue-36053.rs b/src/test/run-pass/issue-36053.rs new file mode 100644 index 000000000000..2411996cf054 --- /dev/null +++ b/src/test/run-pass/issue-36053.rs @@ -0,0 +1,32 @@ +// 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. + +// Regression test for #36053. ICE was caused due to obligations being +// added to a special, dedicated fulfillment cx during a +// probe. Problem seems to be related to the particular definition of +// `FusedIterator` in std but I was not able to isolate that into an +// external crate. + +#![feature(fused)] +use std::iter::FusedIterator; + +struct Thing<'a>(&'a str); +impl<'a> Iterator for Thing<'a> { + type Item = &'a str; + fn next(&mut self) -> Option<&'a str> { + None + } +} + +impl<'a> FusedIterator for Thing<'a> {} + +fn main() { + Thing("test").fuse().filter(|_| true).count(); +} From 35584629f4f8ad1eb32c4363fb9b5437e1052e5e Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 10 Sep 2016 17:52:26 +0200 Subject: [PATCH 357/443] Update E0049 to new error format --- src/librustc_typeck/check/compare_method.rs | 35 +++++++++++++++++++-- src/librustc_typeck/check/mod.rs | 4 ++- src/test/compile-fail/E0049.rs | 3 +- 3 files changed, 37 insertions(+), 5 deletions(-) diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 1604f34d5755..faad3f9b000c 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -38,7 +38,8 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, impl_m_span: Span, impl_m_body_id: ast::NodeId, trait_m: &ty::Method<'tcx>, - impl_trait_ref: &ty::TraitRef<'tcx>) { + impl_trait_ref: &ty::TraitRef<'tcx>, + trait_item_span: Option) { debug!("compare_impl_method(impl_trait_ref={:?})", impl_trait_ref); @@ -97,14 +98,42 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let num_impl_m_type_params = impl_m.generics.types.len(); let num_trait_m_type_params = trait_m.generics.types.len(); if num_impl_m_type_params != num_trait_m_type_params { - span_err!(tcx.sess, impl_m_span, E0049, + let impl_m_node_id = tcx.map.as_local_node_id(impl_m.def_id).unwrap(); + let span = match tcx.map.expect_impl_item(impl_m_node_id).node { + ImplItemKind::Method(ref impl_m_sig, _) => { + if impl_m_sig.generics.is_parameterized() { + impl_m_sig.generics.span + } else { + impl_m_span + } + } + _ => bug!("{:?} is not a method", impl_m) + }; + + struct_span_err!(tcx.sess, span, E0049, "method `{}` has {} type parameter{} \ but its trait declaration has {} type parameter{}", trait_m.name, num_impl_m_type_params, if num_impl_m_type_params == 1 {""} else {"s"}, num_trait_m_type_params, - if num_trait_m_type_params == 1 {""} else {"s"}); + if num_trait_m_type_params == 1 {""} else {"s"}) + .span_label(trait_item_span.unwrap(), + &format!("expected {}", + &if num_trait_m_type_params != 1 { + format!("{} type parameters", + num_trait_m_type_params) + } else { + format!("{} type parameter", + num_trait_m_type_params) + })) + .span_label(span, &format!("found {}", + &if num_impl_m_type_params != 1 { + format!("{} type parameters", num_impl_m_type_params) + } else { + format!("1 type parameter") + })) + .emit(); return; } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 005cd2e46b89..455bde9421d7 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1015,13 +1015,15 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, _ => span_bug!(impl_item.span, "non-method impl-item for method") }; + let trait_span = tcx.map.span_if_local(ty_trait_item.def_id()); if let &ty::MethodTraitItem(ref trait_method) = ty_trait_item { compare_impl_method(ccx, &impl_method, impl_item.span, body.id, &trait_method, - &impl_trait_ref); + &impl_trait_ref, + trait_span); } else { let mut err = struct_span_err!(tcx.sess, impl_item.span, E0324, "item `{}` is an associated method, \ diff --git a/src/test/compile-fail/E0049.rs b/src/test/compile-fail/E0049.rs index 5867e11e9acc..33ebd3f7aca5 100644 --- a/src/test/compile-fail/E0049.rs +++ b/src/test/compile-fail/E0049.rs @@ -9,13 +9,14 @@ // except according to those terms. trait Foo { - fn foo(x: T) -> Self; + fn foo(x: T) -> Self; //~ NOTE expected 1 type parameter } struct Bar; impl Foo for Bar { fn foo(x: bool) -> Self { Bar } //~ ERROR E0049 + //~| NOTE found 0 type parameters } fn main() { From a4ee9c6e96025fa2b5eb254e4ccdd4c6910f5f60 Mon Sep 17 00:00:00 2001 From: Ulrik Sverdrup Date: Tue, 13 Sep 2016 20:51:39 +0200 Subject: [PATCH 358/443] core: Use primitive indexing in slice's Index/IndexMut [T]'s Index implementation is normally not used for indexing, instead the compiler supplied indexing is used. Use the compiler supplied version in Index/IndexMut. This removes an inconsistency: Compiler supplied bound check failures look like this: thread 'main' panicked at 'index out of bounds: the len is 3 but the index is 4' If you convince Rust to use the Index impl for slices, bounds check failure looks like this instead: thread 'main' panicked at 'assertion failed: index < self.len()' The latter is used if you for example use Index generically:: use std::ops::Index; fn foo(x: &T) where T: Index { &x[4]; } foo(&[1, 2, 3][..]) --- src/libcore/slice.rs | 8 ++++---- src/test/run-fail/bounds-check-no-overflow.rs | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs index b22bdb43414f..975562336596 100644 --- a/src/libcore/slice.rs +++ b/src/libcore/slice.rs @@ -520,8 +520,8 @@ impl ops::Index for [T] { type Output = T; fn index(&self, index: usize) -> &T { - assert!(index < self.len()); - unsafe { self.get_unchecked(index) } + // NB built-in indexing + &(*self)[index] } } @@ -530,8 +530,8 @@ impl ops::Index for [T] { impl ops::IndexMut for [T] { #[inline] fn index_mut(&mut self, index: usize) -> &mut T { - assert!(index < self.len()); - unsafe { self.get_unchecked_mut(index) } + // NB built-in indexing + &mut (*self)[index] } } diff --git a/src/test/run-fail/bounds-check-no-overflow.rs b/src/test/run-fail/bounds-check-no-overflow.rs index 4d502cb2106b..3d1cbb446e84 100644 --- a/src/test/run-fail/bounds-check-no-overflow.rs +++ b/src/test/run-fail/bounds-check-no-overflow.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern:assertion failed: index < self.len() +// error-pattern:index out of bounds use std::usize; use std::mem::size_of; From a6da082e102966284857dc6849a0043e31b367e2 Mon Sep 17 00:00:00 2001 From: Tshepang Lekhonkhobe Date: Wed, 14 Sep 2016 22:41:17 +0200 Subject: [PATCH 359/443] doc: make that sound better --- src/libstd/env.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libstd/env.rs b/src/libstd/env.rs index 63bf051c9bcd..76eb92bd5598 100644 --- a/src/libstd/env.rs +++ b/src/libstd/env.rs @@ -83,7 +83,7 @@ pub struct VarsOs { inner: os_imp::Env } /// environment variables of the current process. /// /// The returned iterator contains a snapshot of the process's environment -/// variables at the time of this invocation, modifications to environment +/// variables at the time of this invocation. Modifications to environment /// variables afterwards will not be reflected in the returned iterator. /// /// # Panics @@ -112,7 +112,7 @@ pub fn vars() -> Vars { /// environment variables of the current process. /// /// The returned iterator contains a snapshot of the process's environment -/// variables at the time of this invocation, modifications to environment +/// variables at the time of this invocation. Modifications to environment /// variables afterwards will not be reflected in the returned iterator. /// /// # Examples From f2eb4f11d0c1e5667678def88235309bd083e7fe Mon Sep 17 00:00:00 2001 From: Eugene Bulkin Date: Wed, 14 Sep 2016 15:41:19 -0700 Subject: [PATCH 360/443] Fix doc-tests for Duration --- src/libstd/time/duration.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/libstd/time/duration.rs b/src/libstd/time/duration.rs index a3493f0593c8..6931c8d63152 100644 --- a/src/libstd/time/duration.rs +++ b/src/libstd/time/duration.rs @@ -106,8 +106,10 @@ impl Duration { /// Basic usage: /// /// ``` + /// use std::time::Duration; + /// /// assert_eq!(Duration::new(0, 0).checked_add(Duration::new(0, 1)), Some(Duration::new(0, 1))); - /// assert_eq!(Duration::new(1, 0).checked_add(Duration::new(::u64::MAX, 0)), None); + /// assert_eq!(Duration::new(1, 0).checked_add(Duration::new(std::u64::MAX, 0)), None); /// ``` #[unstable(feature = "duration_checked_ops", issue = "35774")] #[inline] @@ -140,6 +142,8 @@ impl Duration { /// Basic usage: /// /// ``` + /// use std::time::Duration; + /// /// assert_eq!(Duration::new(0, 1).checked_sub(Duration::new(0, 0)), Some(Duration::new(0, 1))); /// assert_eq!(Duration::new(0, 0).checked_sub(Duration::new(0, 1)), None); /// ``` @@ -172,8 +176,10 @@ impl Duration { /// Basic usage: /// /// ``` + /// use std::time::Duration; + /// /// assert_eq!(Duration::new(0, 500_000_001).checked_mul(2), Some(Duration::new(1, 2))); - /// assert_eq!(Duration::new(::u64::MAX - 1, 0).checked_mul(2), None); + /// assert_eq!(Duration::new(std::u64::MAX - 1, 0).checked_mul(2), None); /// ``` #[unstable(feature = "duration_checked_ops", issue = "35774")] #[inline] @@ -203,6 +209,8 @@ impl Duration { /// Basic usage: /// /// ``` + /// use std::time::Duration; + /// /// assert_eq!(Duration::new(2, 0).checked_div(2), Some(Duration::new(1, 0))); /// assert_eq!(Duration::new(1, 0).checked_div(2), Some(Duration::new(0, 500_000_000))); /// assert_eq!(Duration::new(2, 0).checked_div(0), None); From b6321bd13362d69dc0bc4a1ca8416d58b0ff63d2 Mon Sep 17 00:00:00 2001 From: Eugene Bulkin Date: Wed, 14 Sep 2016 17:13:06 -0700 Subject: [PATCH 361/443] Add feature crate attribute for duration_checked_ops to docs --- src/libstd/time/duration.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/libstd/time/duration.rs b/src/libstd/time/duration.rs index 6931c8d63152..246c57ab2387 100644 --- a/src/libstd/time/duration.rs +++ b/src/libstd/time/duration.rs @@ -106,6 +106,8 @@ impl Duration { /// Basic usage: /// /// ``` + /// #![feature(duration_checked_ops)] + /// /// use std::time::Duration; /// /// assert_eq!(Duration::new(0, 0).checked_add(Duration::new(0, 1)), Some(Duration::new(0, 1))); @@ -142,6 +144,8 @@ impl Duration { /// Basic usage: /// /// ``` + /// #![feature(duration_checked_ops)] + /// /// use std::time::Duration; /// /// assert_eq!(Duration::new(0, 1).checked_sub(Duration::new(0, 0)), Some(Duration::new(0, 1))); @@ -176,6 +180,8 @@ impl Duration { /// Basic usage: /// /// ``` + /// #![feature(duration_checked_ops)] + /// /// use std::time::Duration; /// /// assert_eq!(Duration::new(0, 500_000_001).checked_mul(2), Some(Duration::new(1, 2))); @@ -209,6 +215,8 @@ impl Duration { /// Basic usage: /// /// ``` + /// #![feature(duration_checked_ops)] + /// /// use std::time::Duration; /// /// assert_eq!(Duration::new(2, 0).checked_div(2), Some(Duration::new(1, 0))); From 5cab9525ae12a18ec0583ee1ddba3a9eb31a5cfd Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Wed, 14 Sep 2016 22:49:36 -0400 Subject: [PATCH 362/443] Don't ignore a doc code-block we can compile. --- src/doc/book/traits.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/book/traits.md b/src/doc/book/traits.md index d07fb6b7c45b..b0d954adf677 100644 --- a/src/doc/book/traits.md +++ b/src/doc/book/traits.md @@ -291,7 +291,7 @@ let result = f.write(buf); We need to `use` the `Write` trait first: -```rust,ignore +```rust,no_run use std::io::Write; let mut f = std::fs::File::create("foo.txt").expect("Couldn’t create foo.txt"); From b232f6d9fe9ce822aa38cb164e4dce3e4faf5cc4 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Wed, 14 Sep 2016 22:36:42 +0000 Subject: [PATCH 363/443] Avoid loading and parsing unconfigured non-inline modules. --- src/libsyntax/config.rs | 2 +- src/libsyntax/parse/parser.rs | 27 ++++++++++++++++++--------- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs index 3f5b294cc044..abbbbe1e3d1c 100644 --- a/src/libsyntax/config.rs +++ b/src/libsyntax/config.rs @@ -126,7 +126,7 @@ impl<'a> StripUnconfigured<'a> { } // Determine if a node with the given attributes should be included in this configuation. - fn in_cfg(&mut self, attrs: &[ast::Attribute]) -> bool { + pub fn in_cfg(&mut self, attrs: &[ast::Attribute]) -> bool { attrs.iter().all(|attr| { // When not compiling with --test we should not compile the #[test] functions if !self.should_test && is_test_or_bench(attr) { diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 6a0e40edded5..fd2ae3b49083 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -5291,20 +5291,29 @@ impl<'a> Parser<'a> { /// Parse a `mod { ... }` or `mod ;` item fn parse_item_mod(&mut self, outer_attrs: &[Attribute]) -> PResult<'a, ItemInfo> { - let outer_attrs = ::config::StripUnconfigured { - config: &self.cfg, - sess: self.sess, - should_test: false, // irrelevant - features: None, // don't perform gated feature checking - }.process_cfg_attrs(outer_attrs.to_owned()); + let (in_cfg, outer_attrs) = { + let mut strip_unconfigured = ::config::StripUnconfigured { + config: &self.cfg, + sess: self.sess, + should_test: false, // irrelevant + features: None, // don't perform gated feature checking + }; + let outer_attrs = strip_unconfigured.process_cfg_attrs(outer_attrs.to_owned()); + (strip_unconfigured.in_cfg(&outer_attrs), outer_attrs) + }; let id_span = self.span; let id = self.parse_ident()?; if self.check(&token::Semi) { self.bump(); - // This mod is in an external file. Let's go get it! - let (m, attrs) = self.eval_src_mod(id, &outer_attrs, id_span)?; - Ok((id, m, Some(attrs))) + if in_cfg { + // This mod is in an external file. Let's go get it! + let (m, attrs) = self.eval_src_mod(id, &outer_attrs, id_span)?; + Ok((id, m, Some(attrs))) + } else { + let placeholder = ast::Mod { inner: syntax_pos::DUMMY_SP, items: Vec::new() }; + Ok((id, ItemKind::Mod(placeholder), None)) + } } else { let directory = self.directory.clone(); self.push_directory(id, &outer_attrs); From 6f0ee455023fe24cade7a8ebb0af31c2ac98548e Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Wed, 14 Sep 2016 22:40:56 +0000 Subject: [PATCH 364/443] Add regression test. --- src/test/run-pass/conditional-compile.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/test/run-pass/conditional-compile.rs b/src/test/run-pass/conditional-compile.rs index 5891d9f1aa01..c8e9cbdae1e8 100644 --- a/src/test/run-pass/conditional-compile.rs +++ b/src/test/run-pass/conditional-compile.rs @@ -148,3 +148,6 @@ mod test_methods { fn the(&self); } } + +#[cfg(any())] +mod nonexistent_file; // Check that unconfigured non-inline modules are not loaded or parsed. From af1a3ffbebef27f3dc267e66c15325596d1a2cff Mon Sep 17 00:00:00 2001 From: Ulrik Sverdrup Date: Thu, 15 Sep 2016 09:59:55 +0200 Subject: [PATCH 365/443] Remove data structure specialization for .zip() iterator Go back on half the specialization, the part that changed the Zip struct's fields themselves depending on the types of the iterators. This means that the Zip iterator will always carry two usize fields, which are unused. If a whole for loop using a .zip() iterator is inlined, these are simply removed and have no effect. The same improvement for Zip of for example slice iterators remain, and they still optimize well. However, like when the specialization of zip was merged, the compiler is still very sensistive to the exact context. For example this code only autovectorizes if the function is used, not if the code in zip_sum_i32 is inserted inline it was called: ``` fn zip_sum_i32(xs: &[i32], ys: &[i32]) -> i32 { let mut s = 0; for (&x, &y) in xs.iter().zip(ys) { s += x * y; } s } fn zipdot_i32_default_zip(b: &mut test::Bencher) { let xs = vec![1; 1024]; let ys = vec![1; 1024]; b.iter(|| { zip_sum_i32(&xs, &ys) }) } ``` Include a test that checks that Zip is covariant w.r.t. T and U. --- src/libcore/iter/mod.rs | 52 +++++-------------- .../run-pass/variance-iterators-in-libcore.rs | 17 ++++++ 2 files changed, 31 insertions(+), 38 deletions(-) create mode 100644 src/test/run-pass/variance-iterators-in-libcore.rs diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index b1d3ab1d1feb..dd57fd1b5190 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -643,7 +643,9 @@ impl FusedIterator for Chain pub struct Zip { a: A, b: B, - spec: <(A, B) as ZipImplData>::Data, + // index and len are only used by the specialized version of zip + index: usize, + len: usize, } #[stable(feature = "rust1", since = "1.0.0")] @@ -685,17 +687,6 @@ trait ZipImpl { B: DoubleEndedIterator + ExactSizeIterator; } -// Zip specialization data members -#[doc(hidden)] -trait ZipImplData { - type Data: 'static + Clone + Default + fmt::Debug; -} - -#[doc(hidden)] -impl ZipImplData for T { - default type Data = (); -} - // General Zip impl #[doc(hidden)] impl ZipImpl for Zip @@ -706,7 +697,8 @@ impl ZipImpl for Zip Zip { a: a, b: b, - spec: Default::default(), // unused + index: 0, // unused + len: 0, // unused } } @@ -759,20 +751,6 @@ impl ZipImpl for Zip } } -#[doc(hidden)] -#[derive(Default, Debug, Clone)] -struct ZipImplFields { - index: usize, - len: usize, -} - -#[doc(hidden)] -impl ZipImplData for (A, B) - where A: TrustedRandomAccess, B: TrustedRandomAccess -{ - type Data = ZipImplFields; -} - #[doc(hidden)] impl ZipImpl for Zip where A: TrustedRandomAccess, B: TrustedRandomAccess @@ -782,18 +760,16 @@ impl ZipImpl for Zip Zip { a: a, b: b, - spec: ZipImplFields { - index: 0, - len: len, - } + index: 0, + len: len, } } #[inline] fn next(&mut self) -> Option<(A::Item, B::Item)> { - if self.spec.index < self.spec.len { - let i = self.spec.index; - self.spec.index += 1; + if self.index < self.len { + let i = self.index; + self.index += 1; unsafe { Some((self.a.get_unchecked(i), self.b.get_unchecked(i))) } @@ -804,7 +780,7 @@ impl ZipImpl for Zip #[inline] fn size_hint(&self) -> (usize, Option) { - let len = self.spec.len - self.spec.index; + let len = self.len - self.index; (len, Some(len)) } @@ -813,9 +789,9 @@ impl ZipImpl for Zip where A: DoubleEndedIterator + ExactSizeIterator, B: DoubleEndedIterator + ExactSizeIterator { - if self.spec.index < self.spec.len { - self.spec.len -= 1; - let i = self.spec.len; + if self.index < self.len { + self.len -= 1; + let i = self.len; unsafe { Some((self.a.get_unchecked(i), self.b.get_unchecked(i))) } diff --git a/src/test/run-pass/variance-iterators-in-libcore.rs b/src/test/run-pass/variance-iterators-in-libcore.rs new file mode 100644 index 000000000000..b9677d5ba859 --- /dev/null +++ b/src/test/run-pass/variance-iterators-in-libcore.rs @@ -0,0 +1,17 @@ +// 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. + +#![allow(warnings)] + +use std::iter::Zip; + +fn zip_covariant<'a, A, B>(iter: Zip<&'static A, &'static B>) -> Zip<&'a A, &'a B> { iter } + +fn main() { } From c10176ef66b00af7cdfdcf85e2351381f8b38d07 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Thu, 15 Sep 2016 11:40:16 -0400 Subject: [PATCH 366/443] trans: Only translate #[inline] functions if they are used somewhere. --- src/librustc_trans/base.rs | 6 ++- src/librustc_trans/collector.rs | 2 +- src/librustc_trans/partitioning.rs | 71 +----------------------------- src/librustc_trans/trans_item.rs | 33 +++++++------- 4 files changed, 25 insertions(+), 87 deletions(-) diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index a6581ae605b5..fcfe53d0c851 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -1591,7 +1591,11 @@ pub fn filter_reachable_ids(tcx: TyCtxt, reachable: NodeSet) -> NodeSet { node: hir::ImplItemKind::Method(..), .. }) => { let def_id = tcx.map.local_def_id(id); let generics = tcx.lookup_generics(def_id); - generics.parent_types == 0 && generics.types.is_empty() + let attributes = tcx.get_attrs(def_id); + (generics.parent_types == 0 && generics.types.is_empty()) && + // Functions marked with #[inline] are only ever translated + // with "internal" linkage and are never exported. + !attr::requests_inline(&attributes[..]) } _ => false diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index 5a8ab62a2aa2..f193c0482f70 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -401,7 +401,7 @@ fn record_inlining_canditates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, callees: &[TransItem<'tcx>], inlining_map: &mut InliningMap<'tcx>) { let is_inlining_candidate = |trans_item: &TransItem<'tcx>| { - trans_item.is_from_extern_crate() || trans_item.requests_inline(tcx) + trans_item.needs_local_copy(tcx) }; let inlining_candidates = callees.into_iter() diff --git a/src/librustc_trans/partitioning.rs b/src/librustc_trans/partitioning.rs index a161bd199b1f..798e883c9557 100644 --- a/src/librustc_trans/partitioning.rs +++ b/src/librustc_trans/partitioning.rs @@ -261,12 +261,6 @@ pub fn partition<'a, 'tcx, I>(scx: &SharedCrateContext<'a, 'tcx>, { let tcx = scx.tcx(); - if let PartitioningStrategy::FixedUnitCount(1) = strategy { - // If there is only a single codegen-unit, we can use a very simple - // scheme and don't have to bother with doing much analysis. - return vec![single_codegen_unit(tcx, trans_items, reachable)]; - } - // In the first step, we place all regular translation items into their // respective 'home' codegen unit. Regular translation items are all // functions and statics defined in the local crate. @@ -320,7 +314,7 @@ fn place_root_translation_items<'a, 'tcx, I>(scx: &SharedCrateContext<'a, 'tcx>, let mut codegen_units = FnvHashMap(); for trans_item in trans_items { - let is_root = !trans_item.is_instantiated_only_on_demand(); + let is_root = !trans_item.is_instantiated_only_on_demand(tcx); if is_root { let characteristic_def_id = characteristic_def_id_of_trans_item(scx, trans_item); @@ -454,7 +448,6 @@ fn place_inlined_translation_items<'tcx>(initial_partitioning: PreInliningPartit // reliably in that case. new_codegen_unit.items.insert(trans_item, llvm::InternalLinkage); } else { - assert!(trans_item.is_instantiated_only_on_demand()); // We can't be sure if this will also be instantiated // somewhere else, so we add an instance here with // InternalLinkage so we don't get any conflicts. @@ -550,68 +543,6 @@ fn compute_codegen_unit_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, return token::intern_and_get_ident(&mod_path[..]); } -fn single_codegen_unit<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - trans_items: I, - reachable: &NodeSet) - -> CodegenUnit<'tcx> - where I: Iterator> -{ - let mut items = FnvHashMap(); - - for trans_item in trans_items { - let linkage = trans_item.explicit_linkage(tcx).unwrap_or_else(|| { - match trans_item { - TransItem::Static(node_id) => { - if reachable.contains(&node_id) { - llvm::ExternalLinkage - } else { - llvm::PrivateLinkage - } - } - TransItem::DropGlue(_) => { - llvm::InternalLinkage - } - TransItem::Fn(instance) => { - if trans_item.is_generic_fn() { - // FIXME(mw): Assigning internal linkage to all - // monomorphizations is potentially a waste of space - // since monomorphizations could be shared between - // crates. The main reason for making them internal is - // a limitation in MingW's binutils that cannot deal - // with COFF object that have more than 2^15 sections, - // which is something that can happen for large programs - // when every function gets put into its own COMDAT - // section. - llvm::InternalLinkage - } else if trans_item.is_from_extern_crate() { - // FIXME(mw): It would be nice if we could mark these as - // `AvailableExternallyLinkage`, since they should have - // been instantiated in the extern crate. But this - // sometimes leads to crashes on Windows because LLVM - // does not handle exception handling table instantiation - // reliably in that case. - llvm::InternalLinkage - } else if reachable.contains(&tcx.map - .as_local_node_id(instance.def) - .unwrap()) { - llvm::ExternalLinkage - } else { - // Functions that are not visible outside this crate can - // be marked as internal. - llvm::InternalLinkage - } - } - } - }); - - items.insert(trans_item, linkage); - } - - CodegenUnit::new( - numbered_codegen_unit_name(&tcx.crate_name[..], 0), - items) -} - fn numbered_codegen_unit_name(crate_name: &str, index: usize) -> InternedString { token::intern_and_get_ident(&format!("{}{}{}", crate_name, diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs index 44e613c4c2b0..bde393b77e16 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -241,19 +241,6 @@ impl<'a, 'tcx> TransItem<'tcx> { } } - pub fn requests_inline(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> bool { - match *self { - TransItem::Fn(ref instance) => { - instance.substs.types().next().is_some() || { - let attributes = tcx.get_attrs(instance.def); - attr::requests_inline(&attributes[..]) - } - } - TransItem::DropGlue(..) => true, - TransItem::Static(..) => false, - } - } - pub fn is_from_extern_crate(&self) -> bool { match *self { TransItem::Fn(ref instance) => !instance.def.is_local(), @@ -262,10 +249,14 @@ impl<'a, 'tcx> TransItem<'tcx> { } } - pub fn is_instantiated_only_on_demand(&self) -> bool { + /// True if the translation item should only be translated to LLVM IR if + /// it is referenced somewhere (like inline functions, for example). + pub fn is_instantiated_only_on_demand(&self, tcx: TyCtxt) -> bool { match *self { TransItem::Fn(ref instance) => { - !instance.def.is_local() || instance.substs.types().next().is_some() + !instance.def.is_local() || + instance.substs.types().next().is_some() || + attr::requests_inline(&tcx.get_attrs(instance.def)[..]) } TransItem::DropGlue(..) => true, TransItem::Static(..) => false, @@ -282,6 +273,18 @@ impl<'a, 'tcx> TransItem<'tcx> { } } + /// Returns true if there has to be a local copy of this TransItem in every + /// codegen unit that references it (as with inlined functions, for example) + pub fn needs_local_copy(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> bool { + // Currently everything that is instantiated only on demand is done so + // with "internal" linkage, so we need a copy to be present in every + // codegen unit. + // This is coincidental: We could also instantiate something only if it + // is referenced (e.g. a regular, private function) but place it in its + // own codegen unit with "external" linkage. + self.is_instantiated_only_on_demand(tcx) + } + pub fn explicit_linkage(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Option { let def_id = match *self { TransItem::Fn(ref instance) => instance.def, From eba2270a9cc1c0785cf42fa87fe154f425a2eea0 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Thu, 25 Aug 2016 18:43:40 +0200 Subject: [PATCH 367/443] Add `pub fn ptr_eq(this: &Self, other: &Self) -> bool` to `Rc` and `Arc`. Servo and Kuchiki have had helper functions doing this for some time. --- src/liballoc/arc.rs | 37 +++++++++++++++++++++++++++++++++++++ src/liballoc/rc.rs | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+) diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index 3d579641b965..5f9ccd1820ca 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -331,6 +331,33 @@ impl Arc { deallocate(ptr as *mut u8, size_of_val(&*ptr), align_of_val(&*ptr)) } } + + #[inline] + #[unstable(feature = "ptr_eq", + reason = "newly added", + issue = "36497")] + /// Return whether two `Arc` references point to the same value + /// (not just values that compare equal). + /// + /// # Examples + /// + /// ``` + /// #![feature(ptr_eq)] + /// + /// use std::sync::Arc; + /// + /// let five = Arc::new(5); + /// let same_five = five.clone(); + /// let other_five = Arc::new(5); + /// + /// assert!(Arc::ptr_eq(&five, &same_five)); + /// assert!(!Arc::ptr_eq(&five, &other_five)); + /// ``` + pub fn ptr_eq(this: &Self, other: &Self) -> bool { + let this_ptr: *const ArcInner = *this.ptr; + let other_ptr: *const ArcInner = *other.ptr; + this_ptr == other_ptr + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -1200,6 +1227,16 @@ mod tests { let foo: Weak = Weak::new(); assert!(foo.upgrade().is_none()); } + + #[test] + fn test_ptr_eq() { + let five = Arc::new(5); + let same_five = five.clone(); + let other_five = Arc::new(5); + + assert!(Arc::ptr_eq(&five, &same_five)); + assert!(!Arc::ptr_eq(&five, &other_five)); + } } #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index dadddbc2cb3e..32e5587ff412 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -376,6 +376,33 @@ impl Rc { None } } + + #[inline] + #[unstable(feature = "ptr_eq", + reason = "newly added", + issue = "36497")] + /// Return whether two `Rc` references point to the same value + /// (not just values that compare equal). + /// + /// # Examples + /// + /// ``` + /// #![feature(ptr_eq)] + /// + /// use std::rc::Rc; + /// + /// let five = Rc::new(5); + /// let same_five = five.clone(); + /// let other_five = Rc::new(5); + /// + /// assert!(Rc::ptr_eq(&five, &same_five)); + /// assert!(!Rc::ptr_eq(&five, &other_five)); + /// ``` + pub fn ptr_eq(this: &Self, other: &Self) -> bool { + let this_ptr: *const RcBox = *this.ptr; + let other_ptr: *const RcBox = *other.ptr; + this_ptr == other_ptr + } } impl Rc { @@ -1174,6 +1201,16 @@ mod tests { let foo: Weak = Weak::new(); assert!(foo.upgrade().is_none()); } + + #[test] + fn test_ptr_eq() { + let five = Rc::new(5); + let same_five = five.clone(); + let other_five = Rc::new(5); + + assert!(Rc::ptr_eq(&five, &same_five)); + assert!(!Rc::ptr_eq(&five, &other_five)); + } } #[stable(feature = "rust1", since = "1.0.0")] From 5ce9feeb8cb48a89feffe579cfc1a9281b4dfbb0 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Thu, 15 Sep 2016 11:19:19 +0200 Subject: [PATCH 368/443] Add std::ptr::eq, for referential equality of &T references. Fixes https://github.com/rust-lang/rfcs/issues/1155 --- src/libcore/ptr.rs | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 8c8925251e5c..69682652a6a5 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -479,6 +479,40 @@ impl PartialEq for *mut T { #[stable(feature = "rust1", since = "1.0.0")] impl Eq for *mut T {} +/// Compare raw pointers for equality. +/// +/// This is the same as using the `==` operator, but less generic: +/// the arguments have to be `*const T` raw pointers, +/// not anything that implements `PartialEq`. +/// +/// This can be used to compare `&T` references (which coerce to `*const T` implicitly) +/// by their address rather than comparing the values they point to +/// (which is what the `PartialEq for &T` implementation does). +/// +/// # Examples +/// +/// ``` +/// #![feature(ptr_eq)] +/// use std::ptr; +/// +/// let five = 5; +/// let other_five = 5; +/// let five_ref = &five; +/// let same_five_ref = &five; +/// let other_five_ref = &other_five; +/// +/// assert!(five_ref == same_five_ref); +/// assert!(five_ref == other_five_ref); +/// +/// assert!(ptr::eq(five_ref, same_five_ref)); +/// assert!(!ptr::eq(five_ref, other_five_ref)); +/// ``` +#[unstable(feature = "ptr_eq", reason = "newly added", issue = "36497")] +#[inline] +pub fn eq(a: *const T, b: *const T) -> bool { + a == b +} + #[stable(feature = "rust1", since = "1.0.0")] impl Clone for *const T { #[inline] From 928c3981b63e63307a020e99ae67474a75652588 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Thu, 15 Sep 2016 14:46:35 -0400 Subject: [PATCH 369/443] Adapt run-make/sep-comp-inlining test case to new behaviour --- src/test/run-make/sepcomp-inlining/Makefile | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/test/run-make/sepcomp-inlining/Makefile b/src/test/run-make/sepcomp-inlining/Makefile index bc299de0c2d3..ef43b0d97e41 100644 --- a/src/test/run-make/sepcomp-inlining/Makefile +++ b/src/test/run-make/sepcomp-inlining/Makefile @@ -1,13 +1,14 @@ -include ../tools.mk -# Test that #[inline(always)] functions still get inlined across compilation -# unit boundaries. Compilation should produce three IR files, with each one -# containing a definition of the inlined function. Also, the non-#[inline] -# function should be defined in only one compilation unit. +# Test that #[inline] functions still get inlined across compilation unit +# boundaries. Compilation should produce three IR files, but only the two +# compilation units that have a usage of the #[inline] function should +# contain a definition. Also, the non-#[inline] function should be defined +# in only one compilation unit. all: $(RUSTC) foo.rs --emit=llvm-ir -C codegen-units=3 - [ "$$(cat "$(TMPDIR)"/foo.?.ll | grep -c define\ i32\ .*inlined)" -eq "1" ] - [ "$$(cat "$(TMPDIR)"/foo.?.ll | grep -c define\ available_externally\ i32\ .*inlined)" -eq "2" ] + [ "$$(cat "$(TMPDIR)"/foo.?.ll | grep -c define\ i32\ .*inlined)" -eq "0" ] + [ "$$(cat "$(TMPDIR)"/foo.?.ll | grep -c define\ internal\ i32\ .*inlined)" -eq "2" ] [ "$$(cat "$(TMPDIR)"/foo.?.ll | grep -c define\ i32\ .*normal)" -eq "1" ] [ "$$(cat "$(TMPDIR)"/foo.?.ll | grep -c declare\ i32\ .*normal)" -eq "2" ] From b735c1bc7891a5a0176e544aa50c47b4d67f52b4 Mon Sep 17 00:00:00 2001 From: Keegan McAllister Date: Sun, 11 Sep 2016 15:09:05 -0700 Subject: [PATCH 370/443] Tweak std::marker docs Fixes #29361. --- src/libcore/marker.rs | 419 +++++++++++++++++++++++++++--------------- 1 file changed, 266 insertions(+), 153 deletions(-) diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index c22c9f0d1c71..5a1a034a3635 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -8,11 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Primitive traits and marker types representing basic 'kinds' of types. +//! Primitive traits and types representing basic properties of types. //! //! Rust types can be classified in various useful ways according to -//! intrinsic properties of the type. These classifications, often called -//! 'kinds', are represented as traits. +//! their intrinsic properties. These classifications are represented +//! as traits. #![stable(feature = "rust1", since = "1.0.0")] @@ -22,7 +22,21 @@ use hash::Hasher; /// Types that can be transferred across thread boundaries. /// -/// This trait is automatically derived when the compiler determines it's appropriate. +/// This trait is automatically implemented when the compiler determines it's +/// appropriate. +/// +/// An example of a non-`Send` type is the reference-counting pointer +/// [`rc::Rc`][rc]. If two threads attempt to clone `Rc`s that point to the same +/// reference-counted value, they might try to update the reference count at the +/// same time, which is [undefined behavior][ub] because `Rc` doesn't use atomic +/// operations. Its cousin [`sync::Arc`][arc] does use atomic operations (incurring +/// some overhead) and thus is `Send`. +/// +/// See [the Nomicon](../../nomicon/send-and-sync.html) for more details. +/// +/// [rc]: ../../std/rc/struct.Rc.html +/// [arc]: ../../std/sync/struct.Arc.html +/// [ub]: ../../reference.html#behavior-considered-undefined #[stable(feature = "rust1", since = "1.0.0")] #[lang = "send"] #[rustc_on_unimplemented = "`{Self}` cannot be sent between threads safely"] @@ -38,10 +52,10 @@ impl !Send for *const T { } #[stable(feature = "rust1", since = "1.0.0")] impl !Send for *mut T { } -/// Types with a constant size known at compile-time. +/// Types with a constant size known at compile time. /// -/// All type parameters which can be bounded have an implicit bound of `Sized`. The special syntax -/// `?Sized` can be used to remove this bound if it is not appropriate. +/// All type parameters have an implicit bound of `Sized`. The special syntax +/// `?Sized` can be used to remove this bound if it's not appropriate. /// /// ``` /// # #![allow(dead_code)] @@ -51,6 +65,26 @@ impl !Send for *mut T { } /// // struct FooUse(Foo<[i32]>); // error: Sized is not implemented for [i32] /// struct BarUse(Bar<[i32]>); // OK /// ``` +/// +/// The one exception is the implicit `Self` type of a trait, which does not +/// get an implicit `Sized` bound. This is because a `Sized` bound prevents +/// the trait from being used to form a [trait object]: +/// +/// ``` +/// # #![allow(unused_variables)] +/// trait Foo { } +/// trait Bar: Sized { } +/// +/// struct Impl; +/// impl Foo for Impl { } +/// impl Bar for Impl { } +/// +/// let x: &Foo = &Impl; // OK +/// // let y: &Bar = &Impl; // error: the trait `Bar` cannot +/// // be made into an object +/// ``` +/// +/// [trait object]: ../../book/trait-objects.html #[stable(feature = "rust1", since = "1.0.0")] #[lang = "sized"] #[rustc_on_unimplemented = "`{Self}` does not have a constant size known at compile-time"] @@ -59,14 +93,27 @@ pub trait Sized { // Empty. } -/// Types that can be "unsized" to a dynamically sized type. +/// Types that can be "unsized" to a dynamically-sized type. +/// +/// For example, the sized array type `[i8; 2]` implements `Unsize<[i8]>` and +/// `Unsize`. +/// +/// All implementations of `Unsize` are provided automatically by the compiler. +/// +/// `Unsize` is used along with [`ops::CoerceUnsized`][coerceunsized] to allow +/// "user-defined" containers such as [`rc::Rc`][rc] to contain dynamically-sized +/// types. See the [DST coercion RFC][RFC982] for more details. +/// +/// [coerceunsized]: ../ops/trait.CoerceUnsized.html +/// [rc]: ../../std/rc/struct.Rc.html +/// [RFC982]: https://github.com/rust-lang/rfcs/blob/master/text/0982-dst-coercion.md #[unstable(feature = "unsize", issue = "27732")] #[lang="unsize"] pub trait Unsize { // Empty. } -/// Types that can be copied by simply copying bits (i.e. `memcpy`). +/// Types whose values can be duplicated simply by copying bits. /// /// By default, variable bindings have 'move semantics.' In other /// words: @@ -87,7 +134,8 @@ pub trait Unsize { /// However, if a type implements `Copy`, it instead has 'copy semantics': /// /// ``` -/// // we can just derive a `Copy` implementation +/// // We can derive a `Copy` implementation. `Clone` is also required, as it's +/// // a supertrait of `Copy`. /// #[derive(Debug, Copy, Clone)] /// struct Foo; /// @@ -100,13 +148,59 @@ pub trait Unsize { /// println!("{:?}", x); // A-OK! /// ``` /// -/// It's important to note that in these two examples, the only difference is if you are allowed to -/// access `x` after the assignment: a move is also a bitwise copy under the hood. +/// It's important to note that in these two examples, the only difference is whether you +/// are allowed to access `x` after the assignment. Under the hood, both a copy and a move +/// can result in bits being copied in memory, although this is sometimes optimized away. +/// +/// ## How can I implement `Copy`? +/// +/// There are two ways to implement `Copy` on your type. The simplest is to use `derive`: +/// +/// ``` +/// #[derive(Copy, Clone)] +/// struct MyStruct; +/// ``` +/// +/// You can also implement `Copy` and `Clone` manually: +/// +/// ``` +/// struct MyStruct; +/// +/// impl Copy for MyStruct { } +/// +/// impl Clone for MyStruct { +/// fn clone(&self) -> MyStruct { +/// *self +/// } +/// } +/// ``` +/// +/// There is a small difference between the two: the `derive` strategy will also place a `Copy` +/// bound on type parameters, which isn't always desired. +/// +/// ## What's the difference between `Copy` and `Clone`? +/// +/// Copies happen implicitly, for example as part of an assignment `y = x`. The behavior of +/// `Copy` is not overloadable; it is always a simple bit-wise copy. +/// +/// Cloning is an explicit action, `x.clone()`. The implementation of [`Clone`][clone] can +/// provide any type-specific behavior necessary to duplicate values safely. For example, +/// the implementation of `Clone` for [`String`][string] needs to copy the pointed-to string +/// buffer in the heap. A simple bitwise copy of `String` values would merely copy the +/// pointer, leading to a double free down the line. For this reason, `String` is `Clone` +/// but not `Copy`. +/// +/// `Clone` is a supertrait of `Copy`, so everything which is `Copy` must also implement +/// `Clone`. If a type is `Copy` then its `Clone` implementation need only return `*self` +/// (see the example above). +/// +/// [clone]: ../clone/trait.Clone.html +/// [string]: ../../std/string/struct.String.html /// /// ## When can my type be `Copy`? /// /// A type can implement `Copy` if all of its components implement `Copy`. For example, this -/// `struct` can be `Copy`: +/// struct can be `Copy`: /// /// ``` /// # #[allow(dead_code)] @@ -116,7 +210,8 @@ pub trait Unsize { /// } /// ``` /// -/// A `struct` can be `Copy`, and `i32` is `Copy`, so therefore, `Point` is eligible to be `Copy`. +/// A struct can be `Copy`, and `i32` is `Copy`, therefore `Point` is eligible to be `Copy`. +/// By contrast, consider /// /// ``` /// # #![allow(dead_code)] @@ -126,57 +221,35 @@ pub trait Unsize { /// } /// ``` /// -/// The `PointList` `struct` cannot implement `Copy`, because [`Vec`] is not `Copy`. If we +/// The struct `PointList` cannot implement `Copy`, because [`Vec`] is not `Copy`. If we /// attempt to derive a `Copy` implementation, we'll get an error: /// /// ```text /// the trait `Copy` may not be implemented for this type; field `points` does not implement `Copy` /// ``` /// -/// ## When can my type _not_ be `Copy`? +/// ## When *can't* my type be `Copy`? /// /// Some types can't be copied safely. For example, copying `&mut T` would create an aliased -/// mutable reference, and copying [`String`] would result in two attempts to free the same buffer. +/// mutable reference. Copying [`String`] would duplicate responsibility for managing the `String`'s +/// buffer, leading to a double free. /// /// Generalizing the latter case, any type implementing [`Drop`] can't be `Copy`, because it's /// managing some resource besides its own [`size_of::()`] bytes. /// -/// ## What if I derive `Copy` on a type that can't? +/// If you try to implement `Copy` on a struct or enum containing non-`Copy` data, you will get a +/// compile-time error. Specifically, with structs you'll get [E0204] and with enums you'll get +/// [E0205]. /// -/// If you try to derive `Copy` on a struct or enum, you will get a compile-time error. -/// Specifically, with structs you'll get [E0204](https://doc.rust-lang.org/error-index.html#E0204) -/// and with enums you'll get [E0205](https://doc.rust-lang.org/error-index.html#E0205). +/// [E0204]: https://doc.rust-lang.org/error-index.html#E0204 +/// [E0205]: https://doc.rust-lang.org/error-index.html#E0205 /// -/// ## When should my type be `Copy`? +/// ## When *should* my type be `Copy`? /// -/// Generally speaking, if your type _can_ implement `Copy`, it should. There's one important thing -/// to consider though: if you think your type may _not_ be able to implement `Copy` in the future, -/// then it might be prudent to not implement `Copy`. This is because removing `Copy` is a breaking -/// change: that second example would fail to compile if we made `Foo` non-`Copy`. -/// -/// ## Derivable -/// -/// This trait can be used with `#[derive]` if all of its components implement `Copy` and the type. -/// -/// ## How can I implement `Copy`? -/// -/// There are two ways to implement `Copy` on your type: -/// -/// ``` -/// #[derive(Copy, Clone)] -/// struct MyStruct; -/// ``` -/// -/// and -/// -/// ``` -/// struct MyStruct; -/// impl Copy for MyStruct {} -/// impl Clone for MyStruct { fn clone(&self) -> MyStruct { *self } } -/// ``` -/// -/// There is a small difference between the two: the `derive` strategy will also place a `Copy` -/// bound on type parameters, which isn't always desired. +/// Generally speaking, if your type _can_ implement `Copy`, it should. Keep in mind, though, +/// that implementing `Copy` is part of the public API of your type. If the type might become +/// non-`Copy` in the future, it could be prudent to omit the `Copy` implementation now, to +/// avoid a breaking API change. /// /// [`Vec`]: ../../std/vec/struct.Vec.html /// [`String`]: ../../std/string/struct.String.html @@ -188,64 +261,74 @@ pub trait Copy : Clone { // Empty. } -/// Types that can be safely shared between threads when aliased. +/// Types for which it is safe to share references between threads. +/// +/// This trait is automatically implemented when the compiler determines +/// it's appropriate. /// /// The precise definition is: a type `T` is `Sync` if `&T` is -/// thread-safe. In other words, there is no possibility of data races -/// when passing `&T` references between threads. +/// [`Send`][send]. In other words, if there is no possibility of +/// [undefined behavior][ub] (including data races) when passing +/// `&T` references between threads. /// -/// As one would expect, primitive types like [`u8`] and [`f64`] are all -/// `Sync`, and so are simple aggregate types containing them (like -/// tuples, structs and enums). More instances of basic `Sync` types -/// include "immutable" types like `&T` and those with simple -/// inherited mutability, such as [`Box`], [`Vec`] and most other -/// collection types. (Generic parameters need to be `Sync` for their -/// container to be `Sync`.) +/// As one would expect, primitive types like [`u8`][u8] and [`f64`][f64] +/// are all `Sync`, and so are simple aggregate types containing them, +/// like tuples, structs and enums. More examples of basic `Sync` +/// types include "immutable" types like `&T`, and those with simple +/// inherited mutability, such as [`Box`][box], [`Vec`][vec] and +/// most other collection types. (Generic parameters need to be `Sync` +/// for their container to be `Sync`.) /// -/// A somewhat surprising consequence of the definition is `&mut T` is -/// `Sync` (if `T` is `Sync`) even though it seems that it might -/// provide unsynchronized mutation. The trick is a mutable reference -/// stored in an aliasable reference (that is, `& &mut T`) becomes -/// read-only, as if it were a `& &T`, hence there is no risk of a data -/// race. +/// A somewhat surprising consequence of the definition is that `&mut T` +/// is `Sync` (if `T` is `Sync`) even though it seems like that might +/// provide unsynchronized mutation. The trick is that a mutable +/// reference behind a shared reference (that is, `& &mut T`) +/// becomes read-only, as if it were a `& &T`. Hence there is no risk +/// of a data race. /// /// Types that are not `Sync` are those that have "interior -/// mutability" in a non-thread-safe way, such as [`Cell`] and [`RefCell`] -/// in [`std::cell`]. These types allow for mutation of their contents -/// even when in an immutable, aliasable slot, e.g. the contents of -/// [`&Cell`][`Cell`] can be [`.set`], and do not ensure data races are -/// impossible, hence they cannot be `Sync`. A higher level example -/// of a non-`Sync` type is the reference counted pointer -/// [`std::rc::Rc`][`Rc`], because any reference [`&Rc`][`Rc`] can clone a new -/// reference, which modifies the reference counts in a non-atomic -/// way. +/// mutability" in a non-thread-safe form, such as [`cell::Cell`][cell] +/// and [`cell::RefCell`][refcell]. These types allow for mutation of +/// their contents even through an immutable, shared reference. For +/// example the `set` method on `Cell` takes `&self`, so it requires +/// only a shared reference `&Cell`. The method performs no +/// synchronization, thus `Cell` cannot be `Sync`. +/// +/// Another example of a non-`Sync` type is the reference-counting +/// pointer [`rc::Rc`][rc]. Given any reference `&Rc`, you can clone +/// a new `Rc`, modifying the reference counts in a non-atomic way. /// /// For cases when one does need thread-safe interior mutability, -/// types like the atomics in [`std::sync`][`sync`] and [`Mutex`] / [`RwLock`] in -/// the [`sync`] crate do ensure that any mutation cannot cause data -/// races. Hence these types are `Sync`. +/// Rust provides [atomic data types], as well as explicit locking via +/// [`sync::Mutex`][mutex] and [`sync::RWLock`][rwlock]. These types +/// ensure that any mutation cannot cause data races, hence the types +/// are `Sync`. Likewise, [`sync::Arc`][arc] provides a thread-safe +/// analogue of `Rc`. /// -/// Any types with interior mutability must also use the [`std::cell::UnsafeCell`] -/// wrapper around the value(s) which can be mutated when behind a `&` -/// reference; not doing this is undefined behavior (for example, -/// [`transmute`]-ing from `&T` to `&mut T` is invalid). +/// Any types with interior mutability must also use the +/// [`cell::UnsafeCell`][unsafecell] wrapper around the value(s) which +/// can be mutated through a shared reference. Failing to doing this is +/// [undefined behavior][ub]. For example, [`transmute`][transmute]-ing +/// from `&T` to `&mut T` is invalid. /// -/// This trait is automatically derived when the compiler determines it's appropriate. +/// See [the Nomicon](../../nomicon/send-and-sync.html) for more +/// details about `Sync`. /// -/// [`u8`]: ../../std/primitive.u8.html -/// [`f64`]: ../../std/primitive.f64.html -/// [`Vec`]: ../../std/vec/struct.Vec.html -/// [`Box`]: ../../std/boxed/struct.Box.html -/// [`Cell`]: ../../std/cell/struct.Cell.html -/// [`RefCell`]: ../../std/cell/struct.RefCell.html -/// [`std::cell`]: ../../std/cell/index.html -/// [`.set`]: ../../std/cell/struct.Cell.html#method.set -/// [`Rc`]: ../../std/rc/struct.Rc.html -/// [`sync`]: ../../std/sync/index.html -/// [`Mutex`]: ../../std/sync/struct.Mutex.html -/// [`RwLock`]: ../../std/sync/struct.RwLock.html -/// [`std::cell::UnsafeCell`]: ../../std/cell/struct.UnsafeCell.html -/// [`transmute`]: ../../std/mem/fn.transmute.html +/// [send]: trait.Send.html +/// [u8]: ../../std/primitive.u8.html +/// [f64]: ../../std/primitive.f64.html +/// [box]: ../../std/boxed/struct.Box.html +/// [vec]: ../../std/vec/struct.Vec.html +/// [cell]: ../cell/struct.Cell.html +/// [refcell]: ../cell/struct.RefCell.html +/// [rc]: ../../std/rc/struct.Rc.html +/// [arc]: ../../std/sync/struct.Arc.html +/// [atomic data types]: ../sync/atomic/index.html +/// [mutex]: ../../std/sync/struct.Mutex.html +/// [rwlock]: ../../std/sync/struct.RwLock.html +/// [unsafecell]: ../cell/struct.UnsafeCell.html +/// [ub]: ../../reference.html#behavior-considered-undefined +/// [transmute]: ../../std/mem/fn.transmute.html #[stable(feature = "rust1", since = "1.0.0")] #[lang = "sync"] #[rustc_on_unimplemented = "`{Self}` cannot be shared between threads safely"] @@ -314,29 +397,30 @@ macro_rules! impls{ ) } -/// `PhantomData` allows you to describe that a type acts as if it stores a value of type `T`, -/// even though it does not. This allows you to inform the compiler about certain safety properties -/// of your code. +/// Zero-sized type used to mark things that "act like" they own a `T`. /// -/// For a more in-depth explanation of how to use `PhantomData`, please see [the Nomicon]. +/// Adding a `PhantomData` field to your type tells the compiler that your +/// type acts as though it stores a value of type `T`, even though it doesn't +/// really. This information is used when computing certain safety properties. /// -/// [the Nomicon]: ../../nomicon/phantom-data.html +/// For a more in-depth explanation of how to use `PhantomData`, please see +/// [the Nomicon](../../nomicon/phantom-data.html). /// /// # A ghastly note 👻👻👻 /// -/// Though they both have scary names, `PhantomData` and 'phantom types' are related, but not -/// identical. Phantom types are a more general concept that don't require `PhantomData` to -/// implement, but `PhantomData` is the most common way to implement them in a correct manner. +/// Though they both have scary names, `PhantomData` and 'phantom types' are +/// related, but not identical. A phantom type parameter is simply a type +/// parameter which is never used. In Rust, this often causes the compiler to +/// complain, and the solution is to add a "dummy" use by way of `PhantomData`. /// /// # Examples /// -/// ## Unused lifetime parameter +/// ## Unused lifetime parameters /// -/// Perhaps the most common time that `PhantomData` is required is -/// with a struct that has an unused lifetime parameter, typically as -/// part of some unsafe code. For example, here is a struct `Slice` -/// that has two pointers of type `*const T`, presumably pointing into -/// an array somewhere: +/// Perhaps the most common use case for `PhantomData` is a struct that has an +/// unused lifetime parameter, typically as part of some unsafe code. For +/// example, here is a struct `Slice` that has two pointers of type `*const T`, +/// presumably pointing into an array somewhere: /// /// ```ignore /// struct Slice<'a, T> { @@ -350,7 +434,7 @@ macro_rules! impls{ /// intent is not expressed in the code, since there are no uses of /// the lifetime `'a` and hence it is not clear what data it applies /// to. We can correct this by telling the compiler to act *as if* the -/// `Slice` struct contained a borrowed reference `&'a T`: +/// `Slice` struct contained a reference `&'a T`: /// /// ``` /// use std::marker::PhantomData; @@ -359,29 +443,53 @@ macro_rules! impls{ /// struct Slice<'a, T: 'a> { /// start: *const T, /// end: *const T, -/// phantom: PhantomData<&'a T> +/// phantom: PhantomData<&'a T>, /// } /// ``` /// -/// This also in turn requires that we annotate `T:'a`, indicating -/// that `T` is a type that can be borrowed for the lifetime `'a`. +/// This also in turn requires the annotation `T: 'a`, indicating +/// that any references in `T` are valid over the lifetime `'a`. /// -/// ## Unused type parameters -/// -/// It sometimes happens that there are unused type parameters that -/// indicate what type of data a struct is "tied" to, even though that -/// data is not actually found in the struct itself. Here is an -/// example where this arises when handling external resources over a -/// foreign function interface. `PhantomData` can prevent -/// mismatches by enforcing types in the method implementations: +/// When initializing a `Slice` you simply provide the value +/// `PhantomData` for the field `phantom`: /// /// ``` /// # #![allow(dead_code)] -/// # trait ResType { fn foo(&self); } +/// # use std::marker::PhantomData; +/// # struct Slice<'a, T: 'a> { +/// # start: *const T, +/// # end: *const T, +/// # phantom: PhantomData<&'a T>, +/// # } +/// fn borrow_vec<'a, T>(vec: &'a Vec) -> Slice<'a, T> { +/// let ptr = vec.as_ptr(); +/// Slice { +/// start: ptr, +/// end: unsafe { ptr.offset(vec.len() as isize) }, +/// phantom: PhantomData, +/// } +/// } +/// ``` +/// +/// ## Unused type parameters +/// +/// It sometimes happens that you have unused type parameters which +/// indicate what type of data a struct is "tied" to, even though that +/// data is not actually found in the struct itself. Here is an +/// example where this arises with [FFI]. The foreign interface uses +/// handles of type `*mut ()` to refer to Rust values of different +/// types. We track the Rust type using a phantom type parameter on +/// the struct `ExternalResource` which wraps a handle. +/// +/// [FFI]: ../../book/ffi.html +/// +/// ``` +/// # #![allow(dead_code)] +/// # trait ResType { } /// # struct ParamType; /// # mod foreign_lib { -/// # pub fn new(_: usize) -> *mut () { 42 as *mut () } -/// # pub fn do_stuff(_: *mut (), _: usize) {} +/// # pub fn new(_: usize) -> *mut () { 42 as *mut () } +/// # pub fn do_stuff(_: *mut (), _: usize) {} /// # } /// # fn convert_params(_: ParamType) -> usize { 42 } /// use std::marker::PhantomData; @@ -408,21 +516,20 @@ macro_rules! impls{ /// } /// ``` /// -/// ## Indicating ownership +/// ## Ownership and the drop check /// -/// Adding a field of type `PhantomData` also indicates that your -/// struct owns data of type `T`. This in turn implies that when your -/// struct is dropped, it may in turn drop one or more instances of -/// the type `T`, though that may not be apparent from the other -/// structure of the type itself. This is commonly necessary if the -/// structure is using a raw pointer like `*mut T` whose referent -/// may be dropped when the type is dropped, as a `*mut T` is -/// otherwise not treated as owned. +/// Adding a field of type `PhantomData` indicates that your +/// type owns data of type `T`. This in turn implies that when your +/// type is dropped, it may drop one or more instances of the type +/// `T`. This has bearing on the Rust compiler's [drop check] +/// analysis. /// /// If your struct does not in fact *own* the data of type `T`, it is /// better to use a reference type, like `PhantomData<&'a T>` /// (ideally) or `PhantomData<*const T>` (if no lifetime applies), so /// as not to indicate ownership. +/// +/// [drop check]: ../../nomicon/dropck.html #[lang = "phantom_data"] #[stable(feature = "rust1", since = "1.0.0")] pub struct PhantomData; @@ -438,10 +545,13 @@ mod impls { /// Types that can be reflected over. /// -/// This trait is implemented for all types. Its purpose is to ensure -/// that when you write a generic function that will employ -/// reflection, that must be reflected (no pun intended) in the -/// generic bounds of that function. Here is an example: +/// By "reflection" we mean use of the [`Any`][any] trait, or related +/// machinery such as [`TypeId`][typeid]. +/// +/// `Reflect` is implemented for all types. Its purpose is to ensure +/// that when you write a generic function that will employ reflection, +/// that must be reflected (no pun intended) in the generic bounds of +/// that function. /// /// ``` /// #![feature(reflect_marker)] @@ -455,21 +565,24 @@ mod impls { /// } /// ``` /// -/// Without the declaration `T: Reflect`, `foo` would not type check -/// (note: as a matter of style, it would be preferable to write -/// `T: Any`, because `T: Any` implies `T: Reflect` and `T: 'static`, but -/// we use `Reflect` here to show how it works). The `Reflect` bound -/// thus serves to alert `foo`'s caller to the fact that `foo` may -/// behave differently depending on whether `T = u32` or not. In -/// particular, thanks to the `Reflect` bound, callers know that a -/// function declared like `fn bar(...)` will always act in -/// precisely the same way no matter what type `T` is supplied, -/// because there are no bounds declared on `T`. (The ability for a -/// caller to reason about what a function may do based solely on what -/// generic bounds are declared is often called the ["parametricity -/// property"][1].) +/// Without the bound `T: Reflect`, `foo` would not typecheck. (As +/// a matter of style, it would be preferable to write `T: Any`, +/// because `T: Any` implies `T: Reflect` and `T: 'static`, but we +/// use `Reflect` here for illustrative purposes.) /// -/// [1]: http://en.wikipedia.org/wiki/Parametricity +/// The `Reflect` bound serves to alert `foo`'s caller to the +/// fact that `foo` may behave differently depending on whether +/// `T` is `u32` or not. The ability for a caller to reason about what +/// a function may do based solely on what generic bounds are declared +/// is often called the "[parametricity property][param]". Despite the +/// use of `Reflect`, Rust lacks true parametricity because a generic +/// function can, at the very least, call [`mem::size_of`][size_of] +/// without employing any trait bounds whatsoever. +/// +/// [any]: ../any/trait.Any.html +/// [typeid]: ../any/struct.TypeId.html +/// [param]: http://en.wikipedia.org/wiki/Parametricity +/// [size_of]: ../mem/fn.size_of.html #[rustc_reflect_like] #[unstable(feature = "reflect_marker", reason = "requires RFC and more experience", From 9f4e9083604f68c6ee55461687802dfecd753836 Mon Sep 17 00:00:00 2001 From: Tim Neumann Date: Thu, 15 Sep 2016 21:34:21 +0200 Subject: [PATCH 371/443] correctly cancel some errors --- src/libsyntax/parse/parser.rs | 16 +++++++++++----- .../compile-fail/associated-types/issue-36499.rs | 15 +++++++++++++++ 2 files changed, 26 insertions(+), 5 deletions(-) create mode 100644 src/test/compile-fail/associated-types/issue-36499.rs diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 6a0e40edded5..fb8bf0f6181f 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -808,10 +808,12 @@ impl<'a> Parser<'a> { /// Eat and discard tokens until one of `kets` is encountered. Respects token trees, /// passes through any errors encountered. Used for error recovery. pub fn eat_to_tokens(&mut self, kets: &[&token::Token]) { + let handler = self.diagnostic(); + self.parse_seq_to_before_tokens(kets, SeqSep::none(), |p| p.parse_token_tree(), - |mut e| e.cancel()); + |mut e| handler.cancel(&mut e)); } /// Parse a sequence, including the closing delimiter. The function @@ -1040,6 +1042,10 @@ impl<'a> Parser<'a> { self.sess.span_diagnostic.abort_if_errors(); } + fn cancel(&self, err: &mut DiagnosticBuilder) { + self.sess.span_diagnostic.cancel(err) + } + pub fn diagnostic(&self) -> &'a errors::Handler { &self.sess.span_diagnostic } @@ -2416,7 +2422,7 @@ impl<'a> Parser<'a> { ex = ExprKind::Lit(P(lit)); } Err(mut err) => { - err.cancel(); + self.cancel(&mut err); let msg = format!("expected expression, found {}", self.this_token_descr()); return Err(self.fatal(&msg)); @@ -3732,7 +3738,7 @@ impl<'a> Parser<'a> { } } Err(mut err) => { - err.cancel(); + self.cancel(&mut err); let msg = format!("expected pattern, found {}", self.this_token_descr()); return Err(self.fatal(&msg)); } @@ -4106,7 +4112,7 @@ impl<'a> Parser<'a> { } Err(mut e) => { self.recover_stmt_(SemiColonMode::Break); - e.cancel(); + self.cancel(&mut e); } _ => () } @@ -4347,7 +4353,7 @@ impl<'a> Parser<'a> { let span_hi = match self.parse_ty() { Ok(..) => self.span.hi, Err(ref mut err) => { - err.cancel(); + self.cancel(err); span_hi } }; diff --git a/src/test/compile-fail/associated-types/issue-36499.rs b/src/test/compile-fail/associated-types/issue-36499.rs new file mode 100644 index 000000000000..b5b3ecbb580a --- /dev/null +++ b/src/test/compile-fail/associated-types/issue-36499.rs @@ -0,0 +1,15 @@ +// 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. + +// error-pattern: aborting due to previous error + +fn main() { + 2 + +2; +} From ffaebadc990579c8813b3c21b5cd05c6bfdc595a Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Thu, 15 Sep 2016 23:40:48 +0300 Subject: [PATCH 372/443] Default RUST_MIN_STACK to 16MiB for now --- src/librustc_driver/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index fbd48fc42c92..a18a754b184b 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -1054,7 +1054,8 @@ fn parse_crate_attrs<'a>(sess: &'a Session, input: &Input) -> PResult<'a, Vec(f: F) { - const STACK_SIZE: usize = 8 * 1024 * 1024; // 8MB + // Temporarily have stack size set to 16MB to deal with nom-using crates failing + const STACK_SIZE: usize = 16 * 1024 * 1024; // 16MB struct Sink(Arc>>); impl Write for Sink { From 21ba8160f2aed7a2195015c5889c8a991181fe2f Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Mon, 12 Sep 2016 09:47:54 +0000 Subject: [PATCH 373/443] Move fields `single_step` and `keep_macs` from `MacroExpander` to `ExpansionConfig`. --- src/librustc_driver/driver.rs | 2 +- src/libsyntax/ext/expand.rs | 17 +++++++---------- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 36e9fccdf5fd..f07025910f07 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -674,11 +674,11 @@ pub fn phase_2_configure_and_expand<'a, F>(sess: &Session, } let features = sess.features.borrow(); let cfg = syntax::ext::expand::ExpansionConfig { - crate_name: crate_name.to_string(), features: Some(&features), recursion_limit: sess.recursion_limit.get(), trace_mac: sess.opts.debugging_opts.trace_macros, should_test: sess.opts.test, + ..syntax::ext::expand::ExpansionConfig::default(crate_name.to_string()) }; let mut ecx = ExtCtxt::new(&sess.parse_sess, krate.config.clone(), cfg, &mut resolver); let ret = syntax::ext::expand::expand_crate(&mut ecx, syntax_exts, krate); diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 62e299684b76..eab59d3c9309 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -173,19 +173,12 @@ impl Invocation { pub struct MacroExpander<'a, 'b:'a> { pub cx: &'a mut ExtCtxt<'b>, - pub single_step: bool, - pub keep_macs: bool, monotonic: bool, // c.f. `cx.monotonic_expander()` } impl<'a, 'b> MacroExpander<'a, 'b> { pub fn new(cx: &'a mut ExtCtxt<'b>, monotonic: bool) -> Self { - MacroExpander { - cx: cx, - monotonic: monotonic, - single_step: false, - keep_macs: false, - } + MacroExpander { cx: cx, monotonic: monotonic } } fn expand_crate(&mut self, mut krate: ast::Crate) -> ast::Crate { @@ -238,7 +231,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { expansions.push(Vec::new()); } expansions[depth].push((mark.as_u32(), expansion)); - if !self.single_step { + if !self.cx.ecfg.single_step { invocations.extend(new_invocations.into_iter().rev()); } } @@ -417,7 +410,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { self.cx.insert_macro(def.clone()); // If keep_macs is true, expands to a MacEager::items instead. - if self.keep_macs { + if self.cx.ecfg.keep_macs { Some(placeholders::reconstructed_macro_rules(&def, &path)) } else { Some(placeholders::macro_scope_placeholder()) @@ -726,6 +719,8 @@ pub struct ExpansionConfig<'feat> { pub recursion_limit: usize, pub trace_mac: bool, pub should_test: bool, // If false, strip `#[test]` nodes + pub single_step: bool, + pub keep_macs: bool, } macro_rules! feature_tests { @@ -749,6 +744,8 @@ impl<'feat> ExpansionConfig<'feat> { recursion_limit: 64, trace_mac: false, should_test: false, + single_step: false, + keep_macs: false, } } From 0ddb66c4c7216f43cccac8fa08b17abc98bd6c0b Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Tue, 13 Sep 2016 05:21:54 +0000 Subject: [PATCH 374/443] Allow `IdentMacroExpander::expand` to access the ident macro invocation's attributes. --- src/libsyntax/ext/base.rs | 6 ++++-- src/libsyntax/ext/expand.rs | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index fb4816d3847e..ede17f8b0056 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -177,7 +177,8 @@ pub trait IdentMacroExpander { cx: &'cx mut ExtCtxt, sp: Span, ident: ast::Ident, - token_tree: Vec ) + token_tree: Vec, + attrs: Vec) -> Box; } @@ -193,7 +194,8 @@ impl IdentMacroExpander for F cx: &'cx mut ExtCtxt, sp: Span, ident: ast::Ident, - token_tree: Vec ) + token_tree: Vec, + _attrs: Vec) -> Box { (*self)(cx, sp, ident, token_tree) diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index eab59d3c9309..9ea3ec3cccf7 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -374,7 +374,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } }); - kind.make_from(expander.expand(self.cx, span, ident, marked_tts)) + kind.make_from(expander.expand(self.cx, span, ident, marked_tts, attrs)) } MacroRulesTT => { From 2abdc8805cf803ea53e96ca7ad44de3697fb7183 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Tue, 13 Sep 2016 06:25:02 +0000 Subject: [PATCH 375/443] Remove `MacroRulesTT`. --- src/librustc_plugin/registry.rs | 6 +---- src/libsyntax/ext/base.rs | 3 --- src/libsyntax/ext/expand.rs | 42 +---------------------------- src/libsyntax/ext/placeholders.rs | 13 ++++++--- src/libsyntax/ext/tt/macro_rules.rs | 39 ++++++++++++++++++++++++--- src/libsyntax_ext/lib.rs | 5 ++-- 6 files changed, 51 insertions(+), 57 deletions(-) diff --git a/src/librustc_plugin/registry.rs b/src/librustc_plugin/registry.rs index 435196d95618..8f0cc2c3d750 100644 --- a/src/librustc_plugin/registry.rs +++ b/src/librustc_plugin/registry.rs @@ -17,7 +17,7 @@ use rustc::mir::transform::MirMapPass; use syntax::ext::base::{SyntaxExtension, NamedSyntaxExtension, NormalTT}; use syntax::ext::base::{IdentTT, MultiModifier, MultiDecorator}; -use syntax::ext::base::{MacroExpanderFn, MacroRulesTT}; +use syntax::ext::base::MacroExpanderFn; use syntax::parse::token; use syntax::ast; use syntax::feature_gate::AttributeType; @@ -111,10 +111,6 @@ impl<'a> Registry<'a> { } MultiDecorator(ext) => MultiDecorator(ext), MultiModifier(ext) => MultiModifier(ext), - MacroRulesTT => { - self.sess.err("plugin tried to register a new MacroRulesTT"); - return; - } })); } diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index ede17f8b0056..9d0d74138cd4 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -457,9 +457,6 @@ pub enum SyntaxExtension { /// the block. /// IdentTT(Box, Option, bool), - - /// Represents `macro_rules!` itself. - MacroRulesTT, } pub type NamedSyntaxExtension = (Name, SyntaxExtension); diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 9ea3ec3cccf7..4e87d8ee9dda 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -12,7 +12,7 @@ use ast::{Block, Crate, Ident, Mac_, PatKind}; use ast::{MacStmtStyle, StmtKind, ItemKind}; use ast; use ext::hygiene::Mark; -use ext::placeholders::{self, placeholder, PlaceholderExpander}; +use ext::placeholders::{placeholder, PlaceholderExpander}; use attr::{self, HasAttrs}; use codemap::{ExpnInfo, NameAndSpan, MacroBang, MacroAttribute}; use syntax_pos::{self, Span, ExpnId}; @@ -377,46 +377,6 @@ impl<'a, 'b> MacroExpander<'a, 'b> { kind.make_from(expander.expand(self.cx, span, ident, marked_tts, attrs)) } - MacroRulesTT => { - if ident.name == keywords::Invalid.name() { - self.cx.span_err(path.span, - &format!("macro {}! expects an ident argument", extname)); - return kind.dummy(span); - }; - - self.cx.bt_push(ExpnInfo { - call_site: span, - callee: NameAndSpan { - format: MacroBang(extname), - span: None, - // `macro_rules!` doesn't directly allow unstable - // (this is orthogonal to whether the macro it creates allows it) - allow_internal_unstable: false, - } - }); - - let def = ast::MacroDef { - ident: ident, - id: ast::DUMMY_NODE_ID, - span: span, - imported_from: None, - use_locally: true, - body: marked_tts, - export: attr::contains_name(&attrs, "macro_export"), - allow_internal_unstable: attr::contains_name(&attrs, "allow_internal_unstable"), - attrs: attrs, - }; - - self.cx.insert_macro(def.clone()); - - // If keep_macs is true, expands to a MacEager::items instead. - if self.cx.ecfg.keep_macs { - Some(placeholders::reconstructed_macro_rules(&def, &path)) - } else { - Some(placeholders::macro_scope_placeholder()) - } - } - MultiDecorator(..) | MultiModifier(..) => { self.cx.span_err(path.span, &format!("`{}` can only be used in attributes", extname)); diff --git a/src/libsyntax/ext/placeholders.rs b/src/libsyntax/ext/placeholders.rs index 47f366a88768..0ede6dd98e5b 100644 --- a/src/libsyntax/ext/placeholders.rs +++ b/src/libsyntax/ext/placeholders.rs @@ -13,7 +13,7 @@ use codemap::{DUMMY_SP, dummy_spanned}; use ext::base::ExtCtxt; use ext::expand::{Expansion, ExpansionKind}; use fold::*; -use parse::token::keywords; +use parse::token::{intern, keywords}; use ptr::P; use util::move_map::MoveMap; use util::small_vector::SmallVector; @@ -214,7 +214,7 @@ impl<'a, 'b> Folder for PlaceholderExpander<'a, 'b> { } } -pub fn reconstructed_macro_rules(def: &ast::MacroDef, path: &ast::Path) -> Expansion { +pub fn reconstructed_macro_rules(def: &ast::MacroDef) -> Expansion { Expansion::Items(SmallVector::one(P(ast::Item { ident: def.ident, attrs: def.attrs.clone(), @@ -222,7 +222,14 @@ pub fn reconstructed_macro_rules(def: &ast::MacroDef, path: &ast::Path) -> Expan node: ast::ItemKind::Mac(ast::Mac { span: def.span, node: ast::Mac_ { - path: path.clone(), + path: ast::Path { + span: DUMMY_SP, + global: false, + segments: vec![ast::PathSegment { + identifier: ast::Ident::with_empty_ctxt(intern("macro_rules")), + parameters: ast::PathParameters::none(), + }], + }, tts: def.body.clone(), } }), diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index 51ef45b97be6..da82c9ffab1c 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -8,10 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use ast; +use {ast, attr}; use syntax_pos::{Span, DUMMY_SP}; -use ext::base::{DummyResult, ExtCtxt, MacResult, SyntaxExtension}; -use ext::base::{NormalTT, TTMacroExpander}; +use ext::base::{DummyResult, ExtCtxt, MacEager, MacResult, SyntaxExtension}; +use ext::base::{IdentMacroExpander, NormalTT, TTMacroExpander}; +use ext::placeholders; use ext::tt::macro_parser::{Success, Error, Failure}; use ext::tt::macro_parser::{MatchedSeq, MatchedNonterminal}; use ext::tt::macro_parser::parse; @@ -242,6 +243,38 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt, cx.span_fatal(best_fail_spot.substitute_dummy(sp), &best_fail_msg[..]); } +pub struct MacroRulesExpander; +impl IdentMacroExpander for MacroRulesExpander { + fn expand(&self, + cx: &mut ExtCtxt, + span: Span, + ident: ast::Ident, + tts: Vec, + attrs: Vec) + -> Box { + let def = ast::MacroDef { + ident: ident, + id: ast::DUMMY_NODE_ID, + span: span, + imported_from: None, + use_locally: true, + body: tts, + export: attr::contains_name(&attrs, "macro_export"), + allow_internal_unstable: attr::contains_name(&attrs, "allow_internal_unstable"), + attrs: attrs, + }; + + cx.insert_macro(def.clone()); + + // If keep_macs is true, expands to a MacEager::items instead. + if cx.ecfg.keep_macs { + MacEager::items(placeholders::reconstructed_macro_rules(&def).make_items()) + } else { + MacEager::items(placeholders::macro_scope_placeholder().make_items()) + } + } +} + // Note that macro-by-example's input is also matched against a token tree: // $( $lhs:tt => $rhs:tt );+ // diff --git a/src/libsyntax_ext/lib.rs b/src/libsyntax_ext/lib.rs index 3a6212e5445c..e0c028195bab 100644 --- a/src/libsyntax_ext/lib.rs +++ b/src/libsyntax_ext/lib.rs @@ -50,8 +50,9 @@ pub mod deriving; use std::rc::Rc; use syntax::ast; -use syntax::ext::base::{MacroExpanderFn, MacroRulesTT, NormalTT, MultiModifier}; +use syntax::ext::base::{MacroExpanderFn, NormalTT, IdentTT, MultiModifier}; use syntax::ext::hygiene::Mark; +use syntax::ext::tt::macro_rules::MacroRulesExpander; use syntax::parse::token::intern; pub fn register_builtins(resolver: &mut syntax::ext::base::Resolver, enable_quotes: bool) { @@ -59,7 +60,7 @@ pub fn register_builtins(resolver: &mut syntax::ext::base::Resolver, enable_quot resolver.add_macro(Mark::root(), ast::Ident::with_empty_ctxt(intern(name)), Rc::new(ext)); }; - register("macro_rules", MacroRulesTT); + register("macro_rules", IdentTT(Box::new(MacroRulesExpander), None, false)); macro_rules! register { ($( $name:ident: $f:expr, )*) => { $( From f9a08cc9821a442380d15096e3d245c32617eea7 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Tue, 13 Sep 2016 08:39:11 +0000 Subject: [PATCH 376/443] Remove irrelevant test. --- .../auxiliary/macro_crate_MacroRulesTT.rs | 26 ------------------- .../plugin-MacroRulesTT.rs | 18 ------------- 2 files changed, 44 deletions(-) delete mode 100644 src/test/compile-fail-fulldeps/auxiliary/macro_crate_MacroRulesTT.rs delete mode 100644 src/test/compile-fail-fulldeps/plugin-MacroRulesTT.rs diff --git a/src/test/compile-fail-fulldeps/auxiliary/macro_crate_MacroRulesTT.rs b/src/test/compile-fail-fulldeps/auxiliary/macro_crate_MacroRulesTT.rs deleted file mode 100644 index 9e693fcc5644..000000000000 --- a/src/test/compile-fail-fulldeps/auxiliary/macro_crate_MacroRulesTT.rs +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 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)] - -extern crate syntax; -extern crate rustc; -extern crate rustc_plugin; - -use syntax::parse::token; -use syntax::ext::base::MacroRulesTT; -use rustc_plugin::Registry; - -#[plugin_registrar] -pub fn plugin_registrar(reg: &mut Registry) { - reg.register_syntax_extension(token::intern("bogus"), MacroRulesTT); -} diff --git a/src/test/compile-fail-fulldeps/plugin-MacroRulesTT.rs b/src/test/compile-fail-fulldeps/plugin-MacroRulesTT.rs deleted file mode 100644 index e13ddd13f5d9..000000000000 --- a/src/test/compile-fail-fulldeps/plugin-MacroRulesTT.rs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// aux-build:macro_crate_MacroRulesTT.rs -// ignore-stage1 -// error-pattern: plugin tried to register a new MacroRulesTT - -#![feature(plugin)] -#![plugin(macro_crate_MacroRulesTT)] - -fn main() { } From 3f7931017463459768e4281f6f4cea1d75e2e1fe Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Fri, 16 Sep 2016 01:48:27 +0300 Subject: [PATCH 377/443] Try to support py3 with rustbuild better --- src/bootstrap/bootstrap.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 17a7c9ca66a2..14a985e93ce0 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -269,6 +269,7 @@ class RustBuild: sys.exit(ret) def build_triple(self): + default_encoding = sys.getdefaultencoding() config = self.get_toml('build') if config: return config @@ -276,8 +277,8 @@ class RustBuild: if config: return config try: - ostype = subprocess.check_output(['uname', '-s']).strip() - cputype = subprocess.check_output(['uname', '-m']).strip() + ostype = subprocess.check_output(['uname', '-s']).strip().decode(default_encoding) + cputype = subprocess.check_output(['uname', '-m']).strip().decode(default_encoding) except (subprocess.CalledProcessError, WindowsError): if sys.platform == 'win32': return 'x86_64-pc-windows-msvc' @@ -289,7 +290,8 @@ class RustBuild: # Darwin's `uname -s` lies and always returns i386. We have to use # sysctl instead. if ostype == 'Darwin' and cputype == 'i686': - sysctl = subprocess.check_output(['sysctl', 'hw.optional.x86_64']) + args = ['sysctl', 'hw.optional.x86_64'] + sysctl = subprocess.check_output(args).decode(default_encoding) if ': 1' in sysctl: cputype = 'x86_64' From 63ded0518a35ac9bd259bb961225eae7b4fa737c Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 15 Sep 2016 10:59:11 +1000 Subject: [PATCH 378/443] Overhaul char_lit(). This commit does the following. - Removes parsing support for '\X12', '\u123456' and '\U12345678' char literals. These are no longer valid Rust and rejected by the lexer. (This strange-sounding situation occurs because the parser rescans char literals to compute their value.) - Rearranges the function so that all the escaped values are handled in a single `match`, and changes the error-handling to use vanilla assert!() and unwrap(). --- src/libsyntax/parse/mod.rs | 71 +++++++++++++++----------------------- 1 file changed, 28 insertions(+), 43 deletions(-) diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index a1eceb6921c6..5aa0efdec11a 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -286,52 +286,37 @@ pub fn tts_to_parser<'a>(sess: &'a ParseSess, pub fn char_lit(lit: &str) -> (char, isize) { use std::char; - let mut chars = lit.chars(); - match (chars.next(), chars.next()) { - (Some(c), None) if c != '\\' => return (c, 1), - (Some('\\'), Some(c)) => match c { - '"' => return ('"', 2), - 'n' => return ('\n', 2), - 'r' => return ('\r', 2), - 't' => return ('\t', 2), - '\\' => return ('\\', 2), - '\'' => return ('\'', 2), - '0' => return ('\0', 2), - _ => {} - }, - _ => panic!("lexer accepted invalid char escape `{}`", lit) - }; - - fn esc(len: usize, lit: &str) -> Option<(char, isize)> { - u32::from_str_radix(&lit[2..len], 16).ok() - .and_then(char::from_u32) - .map(|x| (x, len as isize)) + // Handle non-escaped chars first. + if lit.as_bytes()[0] != b'\\' { + // If the first byte isn't '\\' it might part of a multi-byte char, so + // get the char with chars(). + let c = lit.chars().next().unwrap(); + return (c, 1); } - let unicode_escape = || -> Option<(char, isize)> { - if lit.as_bytes()[2] == b'{' { - let idx = lit.find('}').unwrap_or_else(|| { - panic!("lexer should have rejected a bad character escape {}", lit) - }); - - let subslice = &lit[3..idx]; - u32::from_str_radix(subslice, 16).ok() - .and_then(char::from_u32) - .map(|x| (x, subslice.chars().count() as isize + 4)) - } else { - esc(6, lit) + // Handle escaped chars. + match lit.as_bytes()[1] as char { + '"' => ('"', 2), + 'n' => ('\n', 2), + 'r' => ('\r', 2), + 't' => ('\t', 2), + '\\' => ('\\', 2), + '\'' => ('\'', 2), + '0' => ('\0', 2), + 'x' => { + let v = u32::from_str_radix(&lit[2..4], 16).unwrap(); + let c = char::from_u32(v).unwrap(); + (c, 4) } - }; - - // Unicode escapes - return match lit.as_bytes()[1] as char { - 'x' | 'X' => esc(4, lit), - 'u' => unicode_escape(), - 'U' => esc(10, lit), - _ => None, - }.unwrap_or_else(|| { - panic!("lexer should have rejected a bad character escape {}", lit) - }) + 'u' => { + assert!(lit.as_bytes()[2] == b'{'); + let idx = lit.find('}').unwrap(); + let v = u32::from_str_radix(&lit[3..idx], 16).unwrap(); + let c = char::from_u32(v).unwrap(); + (c, (idx + 1) as isize) + } + _ => panic!("lexer should have rejected a bad character escape {}", lit) + } } /// Parse a string representing a string literal into its final form. Does From bfa6fdc72c5d650e68e09eac6025bd7d577bb11e Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Thu, 15 Sep 2016 20:39:58 -0400 Subject: [PATCH 379/443] trans: Allow base::internalize_symbols() to internalize #[no_mangle] symbols --- src/librustc_trans/base.rs | 19 ++----------------- src/librustc_trans/partitioning.rs | 15 ++++++++------- src/librustc_trans/trans_item.rs | 6 +++++- 3 files changed, 15 insertions(+), 25 deletions(-) diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index fcfe53d0c851..2c3880d21ad1 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -1421,21 +1421,7 @@ fn internalize_symbols<'a, 'tcx>(sess: &Session, .iter() .cloned() .filter(|trans_item|{ - let def_id = match *trans_item { - TransItem::DropGlue(..) => { - return false - }, - TransItem::Fn(ref instance) => { - instance.def - } - TransItem::Static(node_id) => { - tcx.map.local_def_id(node_id) - } - }; - - trans_item.explicit_linkage(tcx).is_some() || - attr::contains_extern_indicator(tcx.sess.diagnostic(), - &tcx.get_attrs(def_id)) + trans_item.explicit_linkage(tcx).is_some() }) .map(|trans_item| symbol_map.get_or_compute(scx, trans_item)) .collect(); @@ -1900,8 +1886,7 @@ fn collect_and_partition_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a partitioning::partition(scx, items.iter().cloned(), strategy, - &inlining_map, - scx.reachable()) + &inlining_map) }); assert!(scx.tcx().sess.opts.cg.codegen_units == codegen_units.len() || diff --git a/src/librustc_trans/partitioning.rs b/src/librustc_trans/partitioning.rs index 798e883c9557..65615e6b6440 100644 --- a/src/librustc_trans/partitioning.rs +++ b/src/librustc_trans/partitioning.rs @@ -133,7 +133,7 @@ use symbol_map::SymbolMap; use syntax::ast::NodeId; use syntax::parse::token::{self, InternedString}; use trans_item::TransItem; -use util::nodemap::{FnvHashMap, FnvHashSet, NodeSet}; +use util::nodemap::{FnvHashMap, FnvHashSet}; pub enum PartitioningStrategy { /// Generate one codegen unit per source-level module. @@ -254,8 +254,7 @@ const FALLBACK_CODEGEN_UNIT: &'static str = "__rustc_fallback_codegen_unit"; pub fn partition<'a, 'tcx, I>(scx: &SharedCrateContext<'a, 'tcx>, trans_items: I, strategy: PartitioningStrategy, - inlining_map: &InliningMap<'tcx>, - reachable: &NodeSet) + inlining_map: &InliningMap<'tcx>) -> Vec> where I: Iterator> { @@ -265,8 +264,7 @@ pub fn partition<'a, 'tcx, I>(scx: &SharedCrateContext<'a, 'tcx>, // respective 'home' codegen unit. Regular translation items are all // functions and statics defined in the local crate. let mut initial_partitioning = place_root_translation_items(scx, - trans_items, - reachable); + trans_items); debug_dump(tcx, "INITIAL PARTITONING:", initial_partitioning.codegen_units.iter()); @@ -304,8 +302,7 @@ struct PreInliningPartitioning<'tcx> { struct PostInliningPartitioning<'tcx>(Vec>); fn place_root_translation_items<'a, 'tcx, I>(scx: &SharedCrateContext<'a, 'tcx>, - trans_items: I, - _reachable: &NodeSet) + trans_items: I) -> PreInliningPartitioning<'tcx> where I: Iterator> { @@ -344,6 +341,10 @@ fn place_root_translation_items<'a, 'tcx, I>(scx: &SharedCrateContext<'a, 'tcx>, // This is a non-generic functions, we always // make it visible externally on the chance that // it might be used in another codegen unit. + // Later on base::internalize_symbols() will + // assign "internal" linkage to those symbols + // that are not referenced from other codegen + // units (and are not publicly visible). llvm::ExternalLinkage } else { // In the current setup, generic functions cannot diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs index bde393b77e16..5c7cbbbd88d4 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -251,7 +251,11 @@ impl<'a, 'tcx> TransItem<'tcx> { /// True if the translation item should only be translated to LLVM IR if /// it is referenced somewhere (like inline functions, for example). - pub fn is_instantiated_only_on_demand(&self, tcx: TyCtxt) -> bool { + pub fn is_instantiated_only_on_demand(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> bool { + if self.explicit_linkage(tcx).is_some() { + return false; + } + match *self { TransItem::Fn(ref instance) => { !instance.def.is_local() || From 102ee5e70a3da9fa654c1515b492d0f2387e1f97 Mon Sep 17 00:00:00 2001 From: Mark-Simulacrum Date: Thu, 15 Sep 2016 19:47:04 -0600 Subject: [PATCH 380/443] Add example in AsMut trait documentation --- src/libcore/convert.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/libcore/convert.rs b/src/libcore/convert.rs index 5191cd760106..5f16a4f2435f 100644 --- a/src/libcore/convert.rs +++ b/src/libcore/convert.rs @@ -92,6 +92,22 @@ pub trait AsRef { /// [`Option`]: ../../std/option/enum.Option.html /// [`Result`]: ../../std/result/enum.Result.html /// +/// # Examples +/// +/// [`Box`] implements `AsMut`: +/// +/// [`Box`]: ../../std/boxed/struct.Box.html +/// +/// ``` +/// fn add_one>(num: &mut T) { +/// *num.as_mut() += 1; +/// } +/// +/// let mut boxed_num = Box::new(0); +/// add_one(&mut boxed_num); +/// assert_eq!(*boxed_num, 1); +/// ``` +/// /// # Generic Impls /// /// - `AsMut` auto-dereferences if the inner type is a reference or a mutable From cf976fe2cd92a7a4923e6a0934c8f15333b6589d Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Thu, 15 Sep 2016 22:09:49 -0400 Subject: [PATCH 381/443] Adapt codegen-unit test cases to new behaviour --- src/test/codegen-units/partitioning/local-inlining.rs | 2 +- .../codegen-units/partitioning/local-transitive-inlining.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/codegen-units/partitioning/local-inlining.rs b/src/test/codegen-units/partitioning/local-inlining.rs index 5eb1cbc2199f..84ca8b1b0f64 100644 --- a/src/test/codegen-units/partitioning/local-inlining.rs +++ b/src/test/codegen-units/partitioning/local-inlining.rs @@ -19,7 +19,7 @@ mod inline { // Important: This function should show up in all codegen units where it is inlined - //~ TRANS_ITEM fn local_inlining::inline[0]::inlined_function[0] @@ local_inlining-inline[External] local_inlining-user1[Available] local_inlining-user2[Available] + //~ TRANS_ITEM fn local_inlining::inline[0]::inlined_function[0] @@ local_inlining-user1[Internal] local_inlining-user2[Internal] #[inline(always)] pub fn inlined_function() { diff --git a/src/test/codegen-units/partitioning/local-transitive-inlining.rs b/src/test/codegen-units/partitioning/local-transitive-inlining.rs index 28c4698eabd1..7e37f9ccaa5a 100644 --- a/src/test/codegen-units/partitioning/local-transitive-inlining.rs +++ b/src/test/codegen-units/partitioning/local-transitive-inlining.rs @@ -18,7 +18,7 @@ mod inline { - //~ TRANS_ITEM fn local_transitive_inlining::inline[0]::inlined_function[0] @@ local_transitive_inlining-inline[External] local_transitive_inlining-direct_user[Available] local_transitive_inlining-indirect_user[Available] + //~ TRANS_ITEM fn local_transitive_inlining::inline[0]::inlined_function[0] @@ local_transitive_inlining-indirect_user[Internal] #[inline(always)] pub fn inlined_function() { @@ -29,7 +29,7 @@ mod inline { mod direct_user { use super::inline; - //~ TRANS_ITEM fn local_transitive_inlining::direct_user[0]::foo[0] @@ local_transitive_inlining-direct_user[External] local_transitive_inlining-indirect_user[Available] + //~ TRANS_ITEM fn local_transitive_inlining::direct_user[0]::foo[0] @@ local_transitive_inlining-indirect_user[Internal] #[inline(always)] pub fn foo() { inline::inlined_function(); From 68e8624d05bc9b291fc3d945aaf5c1cb24bf015f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 7 Sep 2016 18:40:31 -0700 Subject: [PATCH 382/443] Specify when type parameter shadows primitive type When a type parameter shadows a primitive type, the error message was non obvious. For example, given the file `file.rs`: ```rust trait Parser { fn parse(text: &str) -> Option; } impl Parser for bool { fn parse(text: &str) -> Option { Some(true) } } fn main() { println!("{}", bool::parse("ok").unwrap_or(false)); } ``` The output was: ```bash % rustc file.rs error[E0308]: mismatched types --> file.rs:7:14 | 7 | Some(true) | ^^^^ expected type parameter, found bool | = note: expected type `bool` = note: found type `bool` error: aborting due to previous error ``` We now show extra information about the type: ```bash % rustc file.rs error[E0308]: mismatched types --> file.rs:7:14 | 7 | Some(true) | ^^^^ expected type parameter, found bool | = note: expected type `bool` (type parameter) = note: found type `bool` (bool) error: aborting due to previous error ``` Fixes #35030 --- src/librustc/infer/error_reporting.rs | 13 +++++++++- src/librustc/ty/error.rs | 2 +- src/librustc_errors/lib.rs | 17 ++++++++++--- src/test/ui/mismatched_types/issue-35030.rs | 25 +++++++++++++++++++ .../ui/mismatched_types/issue-35030.stderr | 11 ++++++++ 5 files changed, 63 insertions(+), 5 deletions(-) create mode 100644 src/test/ui/mismatched_types/issue-35030.rs create mode 100644 src/test/ui/mismatched_types/issue-35030.stderr diff --git a/src/librustc/infer/error_reporting.rs b/src/librustc/infer/error_reporting.rs index b8a3bdfcf257..2792968d427a 100644 --- a/src/librustc/infer/error_reporting.rs +++ b/src/librustc/infer/error_reporting.rs @@ -547,7 +547,18 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { }; if !is_simple_error { - diag.note_expected_found(&"type", &expected, &found); + if expected == found { + if let &TypeError::Sorts(ref values) = terr { + diag.note_expected_found_extra( + &"type", &expected, &found, + &format!(" ({})", values.expected.sort_string(self.tcx)), + &format!(" ({})", values.found.sort_string(self.tcx))); + } else { + diag.note_expected_found(&"type", &expected, &found); + } + } else { + diag.note_expected_found(&"type", &expected, &found); + } } } diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs index d820fddea390..001f47af68c3 100644 --- a/src/librustc/ty/error.rs +++ b/src/librustc/ty/error.rs @@ -210,7 +210,7 @@ impl<'tcx> fmt::Display for TypeError<'tcx> { } impl<'a, 'gcx, 'lcx, 'tcx> ty::TyS<'tcx> { - fn sort_string(&self, tcx: TyCtxt<'a, 'gcx, 'lcx>) -> String { + pub fn sort_string(&self, tcx: TyCtxt<'a, 'gcx, 'lcx>) -> String { match self.sty { ty::TyBool | ty::TyChar | ty::TyInt(_) | ty::TyUint(_) | ty::TyFloat(_) | ty::TyStr | ty::TyNever => self.to_string(), diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index d82d7dbe70f9..d2f3eea85f22 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -273,10 +273,21 @@ impl<'a> DiagnosticBuilder<'a> { expected: &fmt::Display, found: &fmt::Display) -> &mut DiagnosticBuilder<'a> + { + self.note_expected_found_extra(label, expected, found, &"", &"") + } + + pub fn note_expected_found_extra(&mut self, + label: &fmt::Display, + expected: &fmt::Display, + found: &fmt::Display, + expected_extra: &fmt::Display, + found_extra: &fmt::Display) + -> &mut DiagnosticBuilder<'a> { // For now, just attach these as notes - self.note(&format!("expected {} `{}`", label, expected)); - self.note(&format!(" found {} `{}`", label, found)); + self.note(&format!("expected {} `{}`{}", label, expected, expected_extra)); + self.note(&format!(" found {} `{}`{}", label, found, found_extra)); self } @@ -764,4 +775,4 @@ pub fn expect(diag: &Handler, opt: Option, msg: M) -> T where Some(t) => t, None => diag.bug(&msg()), } -} \ No newline at end of file +} diff --git a/src/test/ui/mismatched_types/issue-35030.rs b/src/test/ui/mismatched_types/issue-35030.rs new file mode 100644 index 000000000000..006074ead13b --- /dev/null +++ b/src/test/ui/mismatched_types/issue-35030.rs @@ -0,0 +1,25 @@ +// 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. + +// rustc-env:RUST_NEW_ERROR_FORMAT + +trait Parser { + fn parse(text: &str) -> Option; +} + +impl Parser for bool { + fn parse(text: &str) -> Option { + Some(true) + } +} + +fn main() { + println!("{}", bool::parse("ok").unwrap_or(false)); +} diff --git a/src/test/ui/mismatched_types/issue-35030.stderr b/src/test/ui/mismatched_types/issue-35030.stderr new file mode 100644 index 000000000000..aa017297a4e1 --- /dev/null +++ b/src/test/ui/mismatched_types/issue-35030.stderr @@ -0,0 +1,11 @@ +error[E0308]: mismatched types + --> $DIR/issue-35030.rs:19:14 + | +19 | Some(true) + | ^^^^ expected type parameter, found bool + | + = note: expected type `bool` (type parameter) + = note: found type `bool` (bool) + +error: aborting due to previous error + From 8075d546069e9fc850beb846747c43e9ee55e175 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 16 Sep 2016 15:46:40 +1000 Subject: [PATCH 383/443] Optimize the parser's last token handling. The parser currently makes a heap copy of the last token in four cases: identifiers, paths, doc comments, and commas. The identifier and interpolation cases are unused, and for doc comments and commas we only need to record their presence, not their value. This commit consolidates the last token handling and avoids the unnecessary copies by replacing `last_token`, `last_token_eof`, and `last_token_interpolated` with a new field `last_token_kind`. This simplifies the parser slightly and speeds up parsing on some files by 3--4%. --- src/libsyntax/parse/parser.rs | 82 +++++++++++++++++------------------ 1 file changed, 39 insertions(+), 43 deletions(-) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 6a0e40edded5..0696576c93e3 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -237,6 +237,15 @@ fn maybe_append(mut lhs: Vec, rhs: Option>) lhs } +#[derive(PartialEq)] +enum LastTokenKind { + DocComment, + Comma, + Interpolated, + Eof, + Other, +} + /* ident is handled by common.rs */ pub struct Parser<'a> { @@ -248,10 +257,8 @@ pub struct Parser<'a> { /// the span of the prior token: pub last_span: Span, pub cfg: CrateConfig, - /// the previous token or None (only stashed sometimes). - pub last_token: Option>, - last_token_interpolated: bool, - last_token_eof: bool, + /// the previous token kind + last_token_kind: LastTokenKind, pub buffer: [TokenAndSpan; 4], pub buffer_start: isize, pub buffer_end: isize, @@ -362,9 +369,7 @@ impl<'a> Parser<'a> { token: tok0.tok, span: span, last_span: span, - last_token: None, - last_token_interpolated: false, - last_token_eof: false, + last_token_kind: LastTokenKind::Other, buffer: [ placeholder.clone(), placeholder.clone(), @@ -500,7 +505,7 @@ impl<'a> Parser<'a> { expr: PResult<'a, P>) -> PResult<'a, (Span, P)> { expr.map(|e| { - if self.last_token_interpolated { + if self.last_token_kind == LastTokenKind::Interpolated { (self.last_span, e) } else { (e.span, e) @@ -520,21 +525,19 @@ impl<'a> Parser<'a> { self.bug("ident interpolation not converted to real token"); } _ => { - let last_token = self.last_token.clone().map(|t| *t); - Err(match last_token { - Some(token::DocComment(_)) => self.span_fatal_help(self.last_span, + Err(if self.last_token_kind == LastTokenKind::DocComment { + self.span_fatal_help(self.last_span, "found a documentation comment that doesn't document anything", "doc comments must come before what they document, maybe a comment was \ - intended with `//`?"), - _ => { + intended with `//`?") + } else { let mut err = self.fatal(&format!("expected identifier, found `{}`", self.this_token_to_string())); if self.token == token::Underscore { err.note("`_` is a wildcard pattern, not an identifier"); } err - } - }) + }) } } } @@ -923,26 +926,22 @@ impl<'a> Parser<'a> { /// Advance the parser by one token pub fn bump(&mut self) { - if self.last_token_eof { + if self.last_token_kind == LastTokenKind::Eof { // Bumping after EOF is a bad sign, usually an infinite loop. self.bug("attempted to bump the parser past EOF (may be stuck in a loop)"); } - if self.token == token::Eof { - self.last_token_eof = true; - } - self.last_span = self.span; - // Stash token for error recovery (sometimes; clone is not necessarily cheap). - self.last_token = if self.token.is_ident() || - self.token.is_path() || - self.token.is_doc_comment() || - self.token == token::Comma { - Some(Box::new(self.token.clone())) - } else { - None + + // Record last token kind for possible error recovery. + self.last_token_kind = match self.token { + token::DocComment(..) => LastTokenKind::DocComment, + token::Comma => LastTokenKind::Comma, + token::Interpolated(..) => LastTokenKind::Interpolated, + token::Eof => LastTokenKind::Eof, + _ => LastTokenKind::Other, }; - self.last_token_interpolated = self.token.is_interpolated(); + let next = if self.buffer_start == self.buffer_end { self.reader.real_token() } else { @@ -979,11 +978,10 @@ impl<'a> Parser<'a> { lo: BytePos, hi: BytePos) { self.last_span = mk_sp(self.span.lo, lo); - // It would be incorrect to just stash current token, but fortunately - // for tokens currently using `bump_with`, last_token will be of no - // use anyway. - self.last_token = None; - self.last_token_interpolated = false; + // It would be incorrect to record the kind of the current token, but + // fortunately for tokens currently using `bump_with`, the + // last_token_kind will be of no use anyway. + self.last_token_kind = LastTokenKind::Other; self.span = mk_sp(lo, hi); self.token = next; self.expected_tokens.clear(); @@ -2974,7 +2972,7 @@ impl<'a> Parser<'a> { self.expected_tokens.push(TokenType::Operator); while let Some(op) = AssocOp::from_token(&self.token) { - let lhs_span = if self.last_token_interpolated { + let lhs_span = if self.last_token_kind == LastTokenKind::Interpolated { self.last_span } else { lhs.span @@ -4036,13 +4034,13 @@ impl<'a> Parser<'a> { None => { let unused_attrs = |attrs: &[_], s: &mut Self| { if attrs.len() > 0 { - let last_token = s.last_token.clone().map(|t| *t); - match last_token { - Some(token::DocComment(_)) => s.span_err_help(s.last_span, + if s.last_token_kind == LastTokenKind::DocComment { + s.span_err_help(s.last_span, "found a documentation comment that doesn't document anything", "doc comments must come before what they document, maybe a \ - comment was intended with `//`?"), - _ => s.span_err(s.span, "expected statement after outer attribute"), + comment was intended with `//`?"); + } else { + s.span_err(s.span, "expected statement after outer attribute"); } } }; @@ -4332,9 +4330,7 @@ impl<'a> Parser<'a> { let missing_comma = !lifetimes.is_empty() && !self.token.is_like_gt() && - self.last_token - .as_ref().map_or(true, - |x| &**x != &token::Comma); + self.last_token_kind != LastTokenKind::Comma; if missing_comma { From eb19cd65756cd285c81410e627752a75a41e3f0e Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Sat, 11 Jun 2016 23:47:28 +0300 Subject: [PATCH 384/443] groundwork refactoring of `gather_moves` --- src/librustc/mir/repr.rs | 7 +- src/librustc/mir/visit.rs | 3 - .../borrowck/mir/dataflow/impls.rs | 47 +- .../borrowck/mir/dataflow/sanity_check.rs | 24 +- .../borrowck/mir/elaborate_drops.rs | 159 ++- .../borrowck/mir/gather_moves.rs | 905 +++++++----------- src/librustc_borrowck/borrowck/mir/mod.rs | 70 +- src/librustc_trans/mir/analyze.rs | 1 - 8 files changed, 494 insertions(+), 722 deletions(-) diff --git a/src/librustc/mir/repr.rs b/src/librustc/mir/repr.rs index a2abaa5e12f5..53b6ccdbd530 100644 --- a/src/librustc/mir/repr.rs +++ b/src/librustc/mir/repr.rs @@ -1243,7 +1243,7 @@ impl<'a, 'b> GraphSuccessors<'b> for Mir<'a> { type Iter = IntoIter; } -#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, Ord, PartialOrd)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)] pub struct Location { /// the location is within this block pub block: BasicBlock, @@ -1253,3 +1253,8 @@ pub struct Location { pub statement_index: usize, } +impl fmt::Debug for Location { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, "{:?}[{}]", self.block, self.statement_index) + } +} diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index c2d0b2c686e7..16e0b376f4b5 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -774,9 +774,6 @@ pub enum LvalueContext<'tcx> { // Being borrowed Borrow { region: &'tcx Region, kind: BorrowKind }, - // Being sliced -- this should be same as being borrowed, probably - Slice { from_start: usize, from_end: usize }, - // Used as base for another lvalue, e.g. `x` in `x.y` Projection, diff --git a/src/librustc_borrowck/borrowck/mir/dataflow/impls.rs b/src/librustc_borrowck/borrowck/mir/dataflow/impls.rs index c46daf9c2253..8ac59c60396f 100644 --- a/src/librustc_borrowck/borrowck/mir/dataflow/impls.rs +++ b/src/librustc_borrowck/borrowck/mir/dataflow/impls.rs @@ -17,7 +17,7 @@ use super::super::MoveDataParamEnv; use super::super::DropFlagState; use super::super::drop_flag_effects_for_function_entry; use super::super::drop_flag_effects_for_location; -use super::super::on_all_children_bits; +use super::super::on_lookup_result_bits; use super::{BitDenotation, BlockSets, DataflowOperator}; @@ -277,10 +277,9 @@ impl<'a, 'tcx> BitDenotation for MaybeInitializedLvals<'a, 'tcx> { dest_lval: &repr::Lvalue) { // when a call returns successfully, that means we need to set // the bits for that dest_lval to 1 (initialized). - let move_path_index = ctxt.move_data.rev_lookup.find(dest_lval); - on_all_children_bits(self.tcx, self.mir, &ctxt.move_data, - move_path_index, - |mpi| { in_out.add(&mpi); }); + on_lookup_result_bits(self.tcx, self.mir, &ctxt.move_data, + ctxt.move_data.rev_lookup.find(dest_lval), + |mpi| { in_out.add(&mpi); }); } } @@ -338,11 +337,10 @@ impl<'a, 'tcx> BitDenotation for MaybeUninitializedLvals<'a, 'tcx> { _dest_bb: repr::BasicBlock, dest_lval: &repr::Lvalue) { // when a call returns successfully, that means we need to set - // the bits for that dest_lval to 1 (initialized). - let move_path_index = ctxt.move_data.rev_lookup.find(dest_lval); - on_all_children_bits(self.tcx, self.mir, &ctxt.move_data, - move_path_index, - |mpi| { in_out.remove(&mpi); }); + // the bits for that dest_lval to 0 (initialized). + on_lookup_result_bits(self.tcx, self.mir, &ctxt.move_data, + ctxt.move_data.rev_lookup.find(dest_lval), + |mpi| { in_out.remove(&mpi); }); } } @@ -400,10 +398,9 @@ impl<'a, 'tcx> BitDenotation for DefinitelyInitializedLvals<'a, 'tcx> { dest_lval: &repr::Lvalue) { // when a call returns successfully, that means we need to set // the bits for that dest_lval to 1 (initialized). - let move_path_index = ctxt.move_data.rev_lookup.find(dest_lval); - on_all_children_bits(self.tcx, self.mir, &ctxt.move_data, - move_path_index, - |mpi| { in_out.add(&mpi); }); + on_lookup_result_bits(self.tcx, self.mir, &ctxt.move_data, + ctxt.move_data.rev_lookup.find(dest_lval), + |mpi| { in_out.add(&mpi); }); } } @@ -448,11 +445,10 @@ impl<'a, 'tcx> BitDenotation for MovingOutStatements<'a, 'tcx> { // assigning into this `lvalue` kills all // MoveOuts from it, and *also* all MoveOuts // for children and associated fragment sets. - let move_path_index = rev_lookup.find(lvalue); - on_all_children_bits(tcx, + on_lookup_result_bits(tcx, mir, move_data, - move_path_index, + rev_lookup.find(lvalue), |mpi| for moi in &path_map[mpi] { assert!(moi.index() < bits_per_block); sets.kill_set.add(&moi); @@ -489,18 +485,17 @@ impl<'a, 'tcx> BitDenotation for MovingOutStatements<'a, 'tcx> { _dest_bb: repr::BasicBlock, dest_lval: &repr::Lvalue) { let move_data = &ctxt.move_data; - let move_path_index = move_data.rev_lookup.find(dest_lval); let bits_per_block = self.bits_per_block(ctxt); let path_map = &move_data.path_map; - on_all_children_bits(self.tcx, - self.mir, - move_data, - move_path_index, - |mpi| for moi in &path_map[mpi] { - assert!(moi.index() < bits_per_block); - in_out.remove(&moi); - }); + on_lookup_result_bits(self.tcx, + self.mir, + move_data, + move_data.rev_lookup.find(dest_lval), + |mpi| for moi in &path_map[mpi] { + assert!(moi.index() < bits_per_block); + in_out.remove(&moi); + }); } } diff --git a/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs b/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs index 9a4865755e79..88f6d5fef562 100644 --- a/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs +++ b/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs @@ -16,7 +16,7 @@ use rustc::ty::{self, TyCtxt}; use rustc::mir::repr::{self, Mir}; use rustc_data_structures::indexed_vec::Idx; -use super::super::gather_moves::{MovePathIndex}; +use super::super::gather_moves::{MovePathIndex, LookupResult}; use super::super::MoveDataParamEnv; use super::BitDenotation; use super::DataflowResults; @@ -116,20 +116,26 @@ fn each_block<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>, repr::BorrowKind::Shared, ref peeking_at_lval) = *rvalue { // Okay, our search is over. - let peek_mpi = move_data.rev_lookup.find(peeking_at_lval); - let bit_state = sets.on_entry.contains(&peek_mpi); - debug!("rustc_peek({:?} = &{:?}) bit_state: {}", - lvalue, peeking_at_lval, bit_state); - if !bit_state { - tcx.sess.span_err(span, &format!("rustc_peek: bit not set")); + match move_data.rev_lookup.find(peeking_at_lval) { + LookupResult::Exact(peek_mpi) => { + let bit_state = sets.on_entry.contains(&peek_mpi); + debug!("rustc_peek({:?} = &{:?}) bit_state: {}", + lvalue, peeking_at_lval, bit_state); + if !bit_state { + tcx.sess.span_err(span, "rustc_peek: bit not set"); + } + } + LookupResult::Parent(..) => { + tcx.sess.span_err(span, "rustc_peek: argument untracked"); + } } return; } else { // Our search should have been over, but the input // does not match expectations of `rustc_peek` for // this sanity_check. - let msg = &format!("rustc_peek: argument expression \ - must be immediate borrow of form `&expr`"); + let msg = "rustc_peek: argument expression \ + must be immediate borrow of form `&expr`"; tcx.sess.span_err(span, msg); } } diff --git a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs index 71274b7e0218..96702b209a1f 100644 --- a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs +++ b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs @@ -9,10 +9,11 @@ // except according to those terms. use indexed_set::IdxSetBuf; -use super::gather_moves::{MoveData, MovePathIndex, MovePathContent}; +use super::gather_moves::{MoveData, MovePathIndex, LookupResult}; use super::dataflow::{MaybeInitializedLvals, MaybeUninitializedLvals}; use super::dataflow::{DataflowResults}; use super::{drop_flag_effects_for_location, on_all_children_bits}; +use super::on_lookup_result_bits; use super::{DropFlagState, MoveDataParamEnv}; use super::patch::MirPatch; use rustc::ty::{self, Ty, TyCtxt}; @@ -42,7 +43,7 @@ impl<'tcx> MirPass<'tcx> for ElaborateDrops { } let id = src.item_id(); let param_env = ty::ParameterEnvironment::for_item(tcx, id); - let move_data = MoveData::gather_moves(mir, tcx); + let move_data = MoveData::gather_moves(mir, tcx, ¶m_env); let elaborate_patch = { let mir = &*mir; let env = MoveDataParamEnv { @@ -184,31 +185,11 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { fn path_needs_drop(&self, path: MovePathIndex) -> bool { - match self.move_data().move_paths[path].content { - MovePathContent::Lvalue(ref lvalue) => { - let ty = lvalue.ty(self.mir, self.tcx).to_ty(self.tcx); - debug!("path_needs_drop({:?}, {:?} : {:?})", path, lvalue, ty); + let lvalue = &self.move_data().move_paths[path].lvalue; + let ty = lvalue.ty(self.mir, self.tcx).to_ty(self.tcx); + debug!("path_needs_drop({:?}, {:?} : {:?})", path, lvalue, ty); - self.tcx.type_needs_drop_given_env(ty, self.param_env()) - } - _ => false - } - } - - /// Returns whether this lvalue is tracked by drop elaboration. This - /// includes all lvalues, except these (1.) behind references or arrays, - /// or (2.) behind ADT's with a Drop impl. - fn lvalue_is_tracked(&self, lv: &Lvalue<'tcx>) -> bool - { - // `lvalue_contents_drop_state_cannot_differ` only compares - // the `lv` to its immediate contents, while this recursively - // follows parent chain formed by `base` of each projection. - if let &Lvalue::Projection(ref data) = lv { - !super::lvalue_contents_drop_state_cannot_differ(self.tcx, self.mir, &data.base) && - self.lvalue_is_tracked(&data.base) - } else { - true - } + self.tcx.type_needs_drop_given_env(ty, self.param_env()) } fn collect_drop_flags(&mut self) @@ -221,19 +202,29 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { _ => continue }; - if !self.lvalue_is_tracked(location) { - continue - } - let init_data = self.initialization_data_at(Location { block: bb, statement_index: data.statements.len() }); let path = self.move_data().rev_lookup.find(location); - debug!("collect_drop_flags: {:?}, lv {:?} (index {:?})", + debug!("collect_drop_flags: {:?}, lv {:?} ({:?})", bb, location, path); + let path = match path { + LookupResult::Exact(e) => e, + LookupResult::Parent(None) => continue, + LookupResult::Parent(Some(parent)) => { + let (_maybe_live, maybe_dead) = init_data.state(parent); + if maybe_dead { + span_bug!(terminator.source_info.span, + "drop of untracked, uninitialized value {:?}, lv {:?} ({:?})", + bb, location, path); + } + continue + } + }; + on_all_children_bits(self.tcx, self.mir, self.move_data(), path, |child| { if self.path_needs_drop(child) { let (maybe_live, maybe_dead) = init_data.state(child); @@ -257,20 +248,27 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { match terminator.kind { TerminatorKind::Drop { ref location, target, unwind } => { let init_data = self.initialization_data_at(loc); - let path = self.move_data().rev_lookup.find(location); - self.elaborate_drop(&DropCtxt { - source_info: terminator.source_info, - is_cleanup: data.is_cleanup, - init_data: &init_data, - lvalue: location, - path: path, - succ: target, - unwind: if data.is_cleanup { - None - } else { - Some(Option::unwrap_or(unwind, resume_block)) + match self.move_data().rev_lookup.find(location) { + LookupResult::Exact(path) => { + self.elaborate_drop(&DropCtxt { + source_info: terminator.source_info, + is_cleanup: data.is_cleanup, + init_data: &init_data, + lvalue: location, + path: path, + succ: target, + unwind: if data.is_cleanup { + None + } else { + Some(Option::unwrap_or(unwind, resume_block)) + } + }, bb); } - }, bb); + LookupResult::Parent(..) => { + span_bug!(terminator.source_info.span, + "drop of untracked value {:?}", bb); + } + } } TerminatorKind::DropAndReplace { ref location, ref value, target, unwind } => @@ -336,35 +334,37 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { is_cleanup: data.is_cleanup, }); - if !self.lvalue_is_tracked(location) { - // drop and replace behind a pointer/array/whatever. The location - // must be initialized. - debug!("elaborate_drop_and_replace({:?}) - untracked", terminator); - self.patch.patch_terminator(bb, TerminatorKind::Drop { - location: location.clone(), - target: target, - unwind: Some(unwind) - }); - } else { - debug!("elaborate_drop_and_replace({:?}) - tracked", terminator); - let init_data = self.initialization_data_at(loc); - let path = self.move_data().rev_lookup.find(location); + match self.move_data().rev_lookup.find(location) { + LookupResult::Exact(path) => { + debug!("elaborate_drop_and_replace({:?}) - tracked {:?}", terminator, path); + let init_data = self.initialization_data_at(loc); - self.elaborate_drop(&DropCtxt { - source_info: terminator.source_info, - is_cleanup: data.is_cleanup, - init_data: &init_data, - lvalue: location, - path: path, - succ: target, - unwind: Some(unwind) - }, bb); - on_all_children_bits(self.tcx, self.mir, self.move_data(), path, |child| { - self.set_drop_flag(Location { block: target, statement_index: 0 }, - child, DropFlagState::Present); - self.set_drop_flag(Location { block: unwind, statement_index: 0 }, - child, DropFlagState::Present); - }); + self.elaborate_drop(&DropCtxt { + source_info: terminator.source_info, + is_cleanup: data.is_cleanup, + init_data: &init_data, + lvalue: location, + path: path, + succ: target, + unwind: Some(unwind) + }, bb); + on_all_children_bits(self.tcx, self.mir, self.move_data(), path, |child| { + self.set_drop_flag(Location { block: target, statement_index: 0 }, + child, DropFlagState::Present); + self.set_drop_flag(Location { block: unwind, statement_index: 0 }, + child, DropFlagState::Present); + }); + } + LookupResult::Parent(parent) => { + // drop and replace behind a pointer/array/whatever. The location + // must be initialized. + debug!("elaborate_drop_and_replace({:?}) - untracked {:?}", terminator, parent); + self.patch.patch_terminator(bb, TerminatorKind::Drop { + location: location.clone(), + target: target, + unwind: Some(unwind) + }); + } } } @@ -446,10 +446,9 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { substs: &'tcx Substs<'tcx>) -> Vec<(Lvalue<'tcx>, Option)> { - let move_paths = &self.move_data().move_paths; variant.fields.iter().enumerate().map(|(i, f)| { let subpath = - super::move_path_children_matching(move_paths, variant_path, |p| { + super::move_path_children_matching(self.move_data(), variant_path, |p| { match p { &Projection { elem: ProjectionElem::Field(idx, _), .. @@ -580,7 +579,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { let fields = tys.iter().enumerate().map(|(i, &ty)| { (c.lvalue.clone().field(Field::new(i), ty), super::move_path_children_matching( - &self.move_data().move_paths, c.path, |proj| match proj { + self.move_data(), c.path, |proj| match proj { &Projection { elem: ProjectionElem::Field(f, _), .. } => f.index() == i, @@ -598,7 +597,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { debug!("open_drop_for_box({:?}, {:?})", c, ty); let interior_path = super::move_path_children_matching( - &self.move_data().move_paths, c.path, |proj| match proj { + self.move_data(), c.path, |proj| match proj { &Projection { elem: ProjectionElem::Deref, .. } => true, _ => false }).unwrap(); @@ -625,10 +624,8 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { variant_index: usize) -> BasicBlock { - let move_paths = &self.move_data().move_paths; - let subpath = super::move_path_children_matching( - move_paths, c.path, |proj| match proj { + self.move_data(), c.path, |proj| match proj { &Projection { elem: ProjectionElem::Downcast(_, idx), .. } => idx == variant_index, @@ -942,7 +939,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { let loc = Location { block: tgt, statement_index: 0 }; let path = self.move_data().rev_lookup.find(lv); - on_all_children_bits( + on_lookup_result_bits( self.tcx, self.mir, self.move_data(), path, |child| self.set_drop_flag(loc, child, DropFlagState::Present) ); @@ -1011,7 +1008,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { let loc = Location { block: bb, statement_index: data.statements.len() }; let path = self.move_data().rev_lookup.find(lv); - on_all_children_bits( + on_lookup_result_bits( self.tcx, self.mir, self.move_data(), path, |child| self.set_drop_flag(loc, child, DropFlagState::Present) ); diff --git a/src/librustc_borrowck/borrowck/mir/gather_moves.rs b/src/librustc_borrowck/borrowck/mir/gather_moves.rs index 01bf8ed0e4b5..2713a3c371db 100644 --- a/src/librustc_borrowck/borrowck/mir/gather_moves.rs +++ b/src/librustc_borrowck/borrowck/mir/gather_moves.rs @@ -9,16 +9,18 @@ // except according to those terms. -use rustc::ty::TyCtxt; +use rustc::ty::{self, TyCtxt, ParameterEnvironment}; use rustc::mir::repr::*; use rustc::util::nodemap::FnvHashMap; -use rustc_data_structures::indexed_vec::{Idx, IndexVec}; +use rustc::util::common::ErrorReported; +use rustc_data_structures::indexed_vec::{IndexVec}; + +use syntax::codemap::DUMMY_SP; -use std::cell::{Cell}; use std::collections::hash_map::Entry; use std::fmt; -use std::iter; -use std::ops::Index; +use std::mem; +use std::ops::{Index, IndexMut}; use super::abs_domain::{AbstractElem, Lift}; @@ -28,17 +30,15 @@ use super::abs_domain::{AbstractElem, Lift}; // ensure that other code does not accidentally access `index.0` // (which is likely to yield a subtle off-by-one error). mod indexes { + use std::fmt; use core::nonzero::NonZero; use rustc_data_structures::indexed_vec::Idx; macro_rules! new_index { - ($Index:ident) => { - #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] + ($Index:ident, $debug_name:expr) => { + #[derive(Copy, Clone, PartialEq, Eq, Hash)] pub struct $Index(NonZero); - impl $Index { - } - impl Idx for $Index { fn new(idx: usize) -> Self { unsafe { $Index(NonZero::new(idx + 1)) } @@ -47,14 +47,20 @@ mod indexes { *self.0 - 1 } } + + impl fmt::Debug for $Index { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, "{}{}", $debug_name, self.index()) + } + } } } /// Index into MovePathData.move_paths - new_index!(MovePathIndex); + new_index!(MovePathIndex, "mp"); /// Index into MoveData.moves. - new_index!(MoveOutIndex); + new_index!(MoveOutIndex, "mo"); } pub use self::indexes::MovePathIndex; @@ -62,7 +68,7 @@ pub use self::indexes::MoveOutIndex; impl self::indexes::MoveOutIndex { pub fn move_path_index(&self, move_data: &MoveData) -> MovePathIndex { - move_data.moves[self.index()].path + move_data.moves[*self].path } } @@ -83,40 +89,7 @@ pub struct MovePath<'tcx> { pub next_sibling: Option, pub first_child: Option, pub parent: Option, - pub content: MovePathContent<'tcx>, -} - -/// MovePaths usually represent a single l-value. The exceptions are -/// forms that arise due to erroneous input code: static data holds -/// l-values that we cannot actually move out of. Therefore we map -/// statics to a special marker value (`MovePathContent::Static`) -/// representing an invalid origin. -#[derive(Clone, Debug)] -pub enum MovePathContent<'tcx> { - Lvalue(Lvalue<'tcx>), - Static, -} - -/// During construction of the MovePath's, we use PreMovePath to -/// represent accumulated state while we are gathering up all the -/// children of each path. -#[derive(Clone)] -struct PreMovePath<'tcx> { - pub next_sibling: Option, - pub first_child: Cell>, - pub parent: Option, - pub content: MovePathContent<'tcx>, -} - -impl<'tcx> PreMovePath<'tcx> { - fn into_move_path(self) -> MovePath<'tcx> { - MovePath { - next_sibling: self.next_sibling, - parent: self.parent, - content: self.content, - first_child: self.first_child.get(), - } - } + pub lvalue: Lvalue<'tcx>, } impl<'tcx> fmt::Debug for MovePath<'tcx> { @@ -131,52 +104,50 @@ impl<'tcx> fmt::Debug for MovePath<'tcx> { if let Some(next_sibling) = self.next_sibling { write!(w, " next_sibling: {:?}", next_sibling)?; } - write!(w, " content: {:?} }}", self.content) + write!(w, " lvalue: {:?} }}", self.lvalue) } } #[derive(Debug)] pub struct MoveData<'tcx> { - pub move_paths: MovePathData<'tcx>, - pub moves: Vec, - pub loc_map: LocMap, - pub path_map: PathMap, - pub rev_lookup: MovePathLookup<'tcx>, -} - -#[derive(Debug)] -pub struct LocMap { - /// Location-indexed (BasicBlock for outer index, index within BB - /// for inner index) map to list of MoveOutIndex's. - /// + pub move_paths: IndexVec>, + pub moves: IndexVec, /// Each Location `l` is mapped to the MoveOut's that are effects /// of executing the code at `l`. (There can be multiple MoveOut's /// for a given `l` because each MoveOut is associated with one /// particular path being moved.) - map: Vec>>, -} - -impl Index for LocMap { - type Output = [MoveOutIndex]; - fn index(&self, index: Location) -> &Self::Output { - assert!(index.block.index() < self.map.len()); - assert!(index.statement_index < self.map[index.block.index()].len()); - &self.map[index.block.index()][index.statement_index] - } + pub loc_map: LocationMap>, + pub path_map: IndexVec>, + pub rev_lookup: MovePathLookup<'tcx>, } #[derive(Debug)] -pub struct PathMap { - /// Path-indexed map to list of MoveOutIndex's. - /// - /// Each Path `p` is mapped to the MoveOut's that move out of `p`. - map: Vec>, +pub struct LocationMap { + /// Location-indexed (BasicBlock for outer index, index within BB + /// for inner index) map. + map: IndexVec>, } -impl Index for PathMap { - type Output = [MoveOutIndex]; - fn index(&self, index: MovePathIndex) -> &Self::Output { - &self.map[index.index()] +impl Index for LocationMap { + type Output = T; + fn index(&self, index: Location) -> &Self::Output { + &self.map[index.block][index.statement_index] + } +} + +impl IndexMut for LocationMap { + fn index_mut(&mut self, index: Location) -> &mut Self::Output { + &mut self.map[index.block][index.statement_index] + } +} + +impl LocationMap where T: Default + Clone { + fn new(mir: &Mir) -> Self { + LocationMap { + map: mir.basic_blocks().iter().map(|block| { + vec![T::default(); block.statements.len()+1] + }).collect() + } } } @@ -196,583 +167,373 @@ pub struct MoveOut { impl fmt::Debug for MoveOut { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - write!(fmt, "p{}@{:?}", self.path.index(), self.source) + write!(fmt, "{:?}@{:?}", self.path, self.source) } } -#[derive(Debug)] -pub struct MovePathData<'tcx> { - move_paths: Vec>, -} - -impl<'tcx> MovePathData<'tcx> { - pub fn len(&self) -> usize { self.move_paths.len() } -} - -impl<'tcx> Index for MovePathData<'tcx> { - type Output = MovePath<'tcx>; - fn index(&self, i: MovePathIndex) -> &MovePath<'tcx> { - &self.move_paths[i.index()] - } -} - -struct MovePathDataBuilder<'tcx> { - pre_move_paths: Vec>, - rev_lookup: MovePathLookup<'tcx>, -} - /// Tables mapping from an l-value to its MovePathIndex. #[derive(Debug)] pub struct MovePathLookup<'tcx> { - vars: IndexVec>, - temps: IndexVec>, - args: IndexVec>, + vars: IndexVec, + temps: IndexVec, + args: IndexVec, /// The move path representing the return value is constructed /// lazily when we first encounter it in the input MIR. return_ptr: Option, - /// A single move path (representing any static data referenced) - /// is constructed lazily when we first encounter statics in the - /// input MIR. - statics: Option, - /// projections are made from a base-lvalue and a projection /// elem. The base-lvalue will have a unique MovePathIndex; we use /// the latter as the index into the outer vector (narrowing /// subsequent search so that it is solely relative to that /// base-lvalue). For the remaining lookup, we map the projection /// elem to the associated MovePathIndex. - projections: Vec, MovePathIndex>>, - - /// Tracks the next index to allocate during construction of the - /// MovePathData. Unused after MovePathData is fully constructed. - next_index: MovePathIndex, + projections: FnvHashMap<(MovePathIndex, AbstractElem<'tcx>), MovePathIndex> } -trait FillTo { - type T; - fn fill_to_with(&mut self, idx: usize, x: Self::T); - fn fill_to(&mut self, idx: usize) where Self::T: Default { - self.fill_to_with(idx, Default::default()) - } -} -impl FillTo for Vec { - type T = T; - fn fill_to_with(&mut self, idx: usize, x: T) { - if idx >= self.len() { - let delta = idx + 1 - self.len(); - assert_eq!(idx + 1, self.len() + delta); - self.extend(iter::repeat(x).take(delta)) - } - debug_assert!(idx < self.len()); - } +struct MoveDataBuilder<'a, 'tcx: 'a> { + mir: &'a Mir<'tcx>, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + param_env: &'a ParameterEnvironment<'tcx>, + data: MoveData<'tcx>, } -#[derive(Clone, Debug)] -enum LookupKind { Generate, Reuse } -#[derive(Clone, Debug)] -struct Lookup(LookupKind, T); +impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> { + fn new(mir: &'a Mir<'tcx>, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + param_env: &'a ParameterEnvironment<'tcx>) + -> Self { + let mut move_paths = IndexVec::new(); + let mut path_map = IndexVec::new(); -impl Lookup { - fn index(&self) -> usize { (self.1).index() } -} - -impl<'tcx> MovePathLookup<'tcx> { - fn new(mir: &Mir) -> Self { - MovePathLookup { - vars: IndexVec::from_elem(None, &mir.var_decls), - temps: IndexVec::from_elem(None, &mir.temp_decls), - args: IndexVec::from_elem(None, &mir.arg_decls), - statics: None, - return_ptr: None, - projections: vec![], - next_index: MovePathIndex::new(0), - } - } - - fn next_index(next: &mut MovePathIndex) -> MovePathIndex { - let i = *next; - *next = MovePathIndex::new(i.index() + 1); - i - } - - fn lookup_or_generate(vec: &mut IndexVec>, - idx: I, - next_index: &mut MovePathIndex) - -> Lookup { - let entry = &mut vec[idx]; - match *entry { - None => { - let i = Self::next_index(next_index); - *entry = Some(i); - Lookup(LookupKind::Generate, i) - } - Some(entry_idx) => { - Lookup(LookupKind::Reuse, entry_idx) + MoveDataBuilder { + mir: mir, + tcx: tcx, + param_env: param_env, + data: MoveData { + moves: IndexVec::new(), + loc_map: LocationMap::new(mir), + rev_lookup: MovePathLookup { + vars: mir.var_decls.indices().map(Lvalue::Var).map(|v| { + Self::new_move_path(&mut move_paths, &mut path_map, None, v) + }).collect(), + temps: mir.temp_decls.indices().map(Lvalue::Temp).map(|t| { + Self::new_move_path(&mut move_paths, &mut path_map, None, t) + }).collect(), + args: mir.arg_decls.indices().map(Lvalue::Arg).map(|a| { + Self::new_move_path(&mut move_paths, &mut path_map, None, a) + }).collect(), + return_ptr: None, + projections: FnvHashMap(), + }, + move_paths: move_paths, + path_map: path_map, } } } - fn lookup_var(&mut self, var_idx: Var) -> Lookup { - Self::lookup_or_generate(&mut self.vars, - var_idx, - &mut self.next_index) + fn new_move_path(move_paths: &mut IndexVec>, + path_map: &mut IndexVec>, + parent: Option, + lvalue: Lvalue<'tcx>) + -> MovePathIndex + { + let move_path = move_paths.push(MovePath { + next_sibling: None, + first_child: None, + parent: parent, + lvalue: lvalue + }); + + if let Some(parent) = parent { + let next_sibling = + mem::replace(&mut move_paths[parent].first_child, Some(move_path)); + move_paths[move_path].next_sibling = next_sibling; + } + + let path_map_ent = path_map.push(vec![]); + assert_eq!(path_map_ent, move_path); + move_path } - fn lookup_temp(&mut self, temp_idx: Temp) -> Lookup { - Self::lookup_or_generate(&mut self.temps, - temp_idx, - &mut self.next_index) - } - - fn lookup_arg(&mut self, arg_idx: Arg) -> Lookup { - Self::lookup_or_generate(&mut self.args, - arg_idx, - &mut self.next_index) - } - - fn lookup_static(&mut self) -> Lookup { - match self.statics { - Some(mpi) => { - Lookup(LookupKind::Reuse, mpi) - } - ref mut ret @ None => { - let mpi = Self::next_index(&mut self.next_index); - *ret = Some(mpi); - Lookup(LookupKind::Generate, mpi) + /// This creates a MovePath for a given lvalue, returning an `ErrorReported` + /// if that lvalue can't be moved from. + /// + /// NOTE: lvalues behind references *do not* get a move path, which is + /// problematic for borrowck. + /// + /// Maybe we should have seperate "borrowck" and "moveck" modes. + fn move_path_for(&mut self, lval: &Lvalue<'tcx>) + -> Result + { + debug!("lookup({:?})", lval); + match *lval { + Lvalue::Var(var) => Ok(self.data.rev_lookup.vars[var]), + Lvalue::Arg(arg) => Ok(self.data.rev_lookup.args[arg]), + Lvalue::Temp(temp) => Ok(self.data.rev_lookup.temps[temp]), + // error: can't move out of a static + Lvalue::Static(..) => Err(ErrorReported), + Lvalue::ReturnPointer => match self.data.rev_lookup.return_ptr { + Some(ptr) => Ok(ptr), + ref mut ptr @ None => { + let path = Self::new_move_path( + &mut self.data.move_paths, + &mut self.data.path_map, + None, + lval.clone()); + *ptr = Some(path); + Ok(path) + } + }, + Lvalue::Projection(ref proj) => { + self.move_path_for_projection(lval, proj) } } } - fn lookup_return_pointer(&mut self) -> Lookup { - match self.return_ptr { - Some(mpi) => { - Lookup(LookupKind::Reuse, mpi) - } - ref mut ret @ None => { - let mpi = Self::next_index(&mut self.next_index); - *ret = Some(mpi); - Lookup(LookupKind::Generate, mpi) - } - } + fn create_move_path(&mut self, lval: &Lvalue<'tcx>) { + // This is an assignment, not a move, so this not being a valid + // move path is OK. + let _ = self.move_path_for(lval); } - fn lookup_proj(&mut self, - proj: &LvalueProjection<'tcx>, - base: MovePathIndex) -> Lookup { - let MovePathLookup { ref mut projections, - ref mut next_index, .. } = *self; - projections.fill_to(base.index()); - match projections[base.index()].entry(proj.elem.lift()) { - Entry::Occupied(ent) => { - Lookup(LookupKind::Reuse, *ent.get()) - } + fn move_path_for_projection(&mut self, + lval: &Lvalue<'tcx>, + proj: &LvalueProjection<'tcx>) + -> Result + { + let base = try!(self.move_path_for(&proj.base)); + let lv_ty = proj.base.ty(self.mir, self.tcx).to_ty(self.tcx); + match lv_ty.sty { + // error: can't move out of borrowed content + ty::TyRef(..) | ty::TyRawPtr(..) => return Err(ErrorReported), + // error: can't move out of struct with destructor + ty::TyStruct(adt, _) | ty::TyEnum(adt, _) if adt.has_dtor() => + return Err(ErrorReported), + + ty::TyArray(..) | ty::TySlice(..) => match proj.elem { + // error: can't move out of an array + ProjectionElem::Index(..) => return Err(ErrorReported), + _ => {} + }, + _ => {} + }; + match self.data.rev_lookup.projections.entry((base, proj.elem.lift())) { + Entry::Occupied(ent) => Ok(*ent.get()), Entry::Vacant(ent) => { - let mpi = Self::next_index(next_index); - ent.insert(mpi); - Lookup(LookupKind::Generate, mpi) + let path = Self::new_move_path( + &mut self.data.move_paths, + &mut self.data.path_map, + Some(base), + lval.clone() + ); + ent.insert(path); + Ok(path) } } } + + fn finalize(self) -> MoveData<'tcx> { + debug!("{}", { + debug!("moves for {:?}:", self.mir.span); + for (j, mo) in self.data.moves.iter_enumerated() { + debug!(" {:?} = {:?}", j, mo); + } + debug!("move paths for {:?}:", self.mir.span); + for (j, path) in self.data.move_paths.iter_enumerated() { + debug!(" {:?} = {:?}", j, path); + } + "done dumping moves" + }); + self.data + } +} + +#[derive(Copy, Clone, Debug)] +pub enum LookupResult { + Exact(MovePathIndex), + Parent(Option) } impl<'tcx> MovePathLookup<'tcx> { // Unlike the builder `fn move_path_for` below, this lookup // alternative will *not* create a MovePath on the fly for an - // unknown l-value; it will simply panic. - pub fn find(&self, lval: &Lvalue<'tcx>) -> MovePathIndex { + // unknown l-value, but will rather return the nearest available + // parent. + pub fn find(&self, lval: &Lvalue<'tcx>) -> LookupResult { match *lval { - Lvalue::Var(var) => self.vars[var].unwrap(), - Lvalue::Temp(temp) => self.temps[temp].unwrap(), - Lvalue::Arg(arg) => self.args[arg].unwrap(), - Lvalue::Static(ref _def_id) => self.statics.unwrap(), - Lvalue::ReturnPointer => self.return_ptr.unwrap(), + Lvalue::Var(var) => LookupResult::Exact(self.vars[var]), + Lvalue::Temp(temp) => LookupResult::Exact(self.temps[temp]), + Lvalue::Arg(arg) => LookupResult::Exact(self.args[arg]), + Lvalue::Static(..) => LookupResult::Parent(None), + Lvalue::ReturnPointer => LookupResult::Exact(self.return_ptr.unwrap()), Lvalue::Projection(ref proj) => { - let base_index = self.find(&proj.base); - self.projections[base_index.index()][&proj.elem.lift()] + match self.find(&proj.base) { + LookupResult::Exact(base_path) => { + match self.projections.get(&(base_path, proj.elem.lift())) { + Some(&subpath) => LookupResult::Exact(subpath), + None => LookupResult::Parent(Some(base_path)) + } + } + inexact => inexact + } } } } } -impl<'tcx> MovePathDataBuilder<'tcx> { - fn lookup(&mut self, lval: &Lvalue<'tcx>) -> Lookup { - let proj = match *lval { - Lvalue::Var(var_idx) => - return self.rev_lookup.lookup_var(var_idx), - Lvalue::Temp(temp_idx) => - return self.rev_lookup.lookup_temp(temp_idx), - Lvalue::Arg(arg_idx) => - return self.rev_lookup.lookup_arg(arg_idx), - Lvalue::Static(_def_id) => - return self.rev_lookup.lookup_static(), - Lvalue::ReturnPointer => - return self.rev_lookup.lookup_return_pointer(), - Lvalue::Projection(ref proj) => { - proj - } - }; - - let base_index = self.move_path_for(&proj.base); - self.rev_lookup.lookup_proj(proj, base_index) - } - - fn create_move_path(&mut self, lval: &Lvalue<'tcx>) { - // Create MovePath for `lval`, discarding returned index. - self.move_path_for(lval); - } - - fn move_path_for(&mut self, lval: &Lvalue<'tcx>) -> MovePathIndex { - debug!("move_path_for({:?})", lval); - - let lookup: Lookup = self.lookup(lval); - - // `lookup` is either the previously assigned index or a - // newly-allocated one. - debug_assert!(lookup.index() <= self.pre_move_paths.len()); - - if let Lookup(LookupKind::Generate, mpi) = lookup { - let parent; - let sibling; - // tracks whether content is Some non-static; statics map to None. - let content: Option<&Lvalue<'tcx>>; - - match *lval { - Lvalue::Static(_) => { - content = None; - sibling = None; - parent = None; - } - - Lvalue::Var(_) | Lvalue::Temp(_) | Lvalue::Arg(_) | - Lvalue::ReturnPointer => { - content = Some(lval); - sibling = None; - parent = None; - } - Lvalue::Projection(ref proj) => { - content = Some(lval); - - // Here, install new MovePath as new first_child. - - // Note: `parent` previously allocated (Projection - // case of match above established this). - let idx = self.move_path_for(&proj.base); - parent = Some(idx); - - let parent_move_path = &mut self.pre_move_paths[idx.index()]; - - // At last: Swap in the new first_child. - sibling = parent_move_path.first_child.get(); - parent_move_path.first_child.set(Some(mpi)); - } - }; - - let content = match content { - Some(lval) => MovePathContent::Lvalue(lval.clone()), - None => MovePathContent::Static, - }; - - let move_path = PreMovePath { - next_sibling: sibling, - parent: parent, - content: content, - first_child: Cell::new(None), - }; - - self.pre_move_paths.push(move_path); - } - - return lookup.1; - } -} - impl<'a, 'tcx> MoveData<'tcx> { - pub fn gather_moves(mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Self { - gather_moves(mir, tcx) + pub fn gather_moves(mir: &Mir<'tcx>, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + param_env: &ParameterEnvironment<'tcx>) + -> Self { + gather_moves(mir, tcx, param_env) } } -#[derive(Debug)] -enum StmtKind { - Use, Repeat, Cast, BinaryOp, UnaryOp, Box, - Aggregate, Drop, CallFn, CallArg, Return, If, -} +fn gather_moves<'a, 'tcx>(mir: &Mir<'tcx>, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + param_env: &ParameterEnvironment<'tcx>) + -> MoveData<'tcx> { + let mut builder = MoveDataBuilder::new(mir, tcx, param_env); -fn gather_moves<'a, 'tcx>(mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> MoveData<'tcx> { - use self::StmtKind as SK; - - let bb_count = mir.basic_blocks().len(); - let mut moves = vec![]; - let mut loc_map: Vec<_> = iter::repeat(Vec::new()).take(bb_count).collect(); - let mut path_map = Vec::new(); - - // this is mutable only because we will move it to and fro' the - // BlockContexts constructed on each iteration. (Moving is more - // straight-forward than mutable borrows in this instance.) - let mut builder = MovePathDataBuilder { - pre_move_paths: Vec::new(), - rev_lookup: MovePathLookup::new(mir), - }; - - // Before we analyze the program text, we create the MovePath's - // for all of the vars, args, and temps. (This enforces a basic - // property that even if the MIR body doesn't contain any - // references to a var/arg/temp, it will still be a valid - // operation to lookup the MovePath associated with it.) - assert!(mir.var_decls.len() <= ::std::u32::MAX as usize); - assert!(mir.arg_decls.len() <= ::std::u32::MAX as usize); - assert!(mir.temp_decls.len() <= ::std::u32::MAX as usize); - for var in mir.var_decls.indices() { - let path_idx = builder.move_path_for(&Lvalue::Var(var)); - path_map.fill_to(path_idx.index()); - } - for arg in mir.arg_decls.indices() { - let path_idx = builder.move_path_for(&Lvalue::Arg(arg)); - path_map.fill_to(path_idx.index()); - } - for temp in mir.temp_decls.indices() { - let path_idx = builder.move_path_for(&Lvalue::Temp(temp)); - path_map.fill_to(path_idx.index()); - } - - for (bb, bb_data) in mir.basic_blocks().iter_enumerated() { - let loc_map_bb = &mut loc_map[bb.index()]; - - debug_assert!(loc_map_bb.len() == 0); - let len = bb_data.statements.len(); - loc_map_bb.fill_to(len); - debug_assert!(loc_map_bb.len() == len + 1); - - let mut bb_ctxt = BlockContext { - _tcx: tcx, - moves: &mut moves, - builder: builder, - path_map: &mut path_map, - loc_map_bb: loc_map_bb, - }; - - for (i, stmt) in bb_data.statements.iter().enumerate() { + for (bb, block) in mir.basic_blocks().iter_enumerated() { + for (i, stmt) in block.statements.iter().enumerate() { let source = Location { block: bb, statement_index: i }; - match stmt.kind { - StatementKind::Assign(ref lval, ref rval) => { - bb_ctxt.builder.create_move_path(lval); - - // Ensure that the path_map contains entries even - // if the lvalue is assigned and never read. - let assigned_path = bb_ctxt.builder.move_path_for(lval); - bb_ctxt.path_map.fill_to(assigned_path.index()); - - match *rval { - Rvalue::Use(ref operand) => { - bb_ctxt.on_operand(SK::Use, operand, source) - } - Rvalue::Repeat(ref operand, ref _const) => - bb_ctxt.on_operand(SK::Repeat, operand, source), - Rvalue::Cast(ref _kind, ref operand, ref _ty) => - bb_ctxt.on_operand(SK::Cast, operand, source), - Rvalue::BinaryOp(ref _binop, ref operand1, ref operand2) | - Rvalue::CheckedBinaryOp(ref _binop, ref operand1, ref operand2) => { - bb_ctxt.on_operand(SK::BinaryOp, operand1, source); - bb_ctxt.on_operand(SK::BinaryOp, operand2, source); - } - Rvalue::UnaryOp(ref _unop, ref operand) => { - bb_ctxt.on_operand(SK::UnaryOp, operand, source); - } - Rvalue::Box(ref _ty) => { - // this is creating uninitialized - // memory that needs to be initialized. - let deref_lval = Lvalue::Projection(Box::new(Projection { - base: lval.clone(), - elem: ProjectionElem::Deref, - })); - bb_ctxt.on_move_out_lval(SK::Box, &deref_lval, source); - } - Rvalue::Aggregate(ref _kind, ref operands) => { - for operand in operands { - bb_ctxt.on_operand(SK::Aggregate, operand, source); - } - } - Rvalue::Ref(..) | - Rvalue::Len(..) | - Rvalue::InlineAsm { .. } => {} - } - } - StatementKind::StorageLive(_) | - StatementKind::StorageDead(_) => {} - StatementKind::SetDiscriminant{ .. } => { - span_bug!(stmt.source_info.span, - "SetDiscriminant should not exist during borrowck"); - } - } + builder.gather_statement(source, stmt); } - debug!("gather_moves({:?})", bb_data.terminator()); - match bb_data.terminator().kind { + let terminator_loc = Location { + block: bb, + statement_index: block.statements.len() + }; + builder.gather_terminator(terminator_loc, block.terminator()); + } + + builder.finalize() +} + +impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> { + fn gather_statement(&mut self, loc: Location, stmt: &Statement<'tcx>) { + debug!("gather_statement({:?}, {:?})", loc, stmt); + match stmt.kind { + StatementKind::Assign(ref lval, ref rval) => { + self.create_move_path(lval); + self.gather_rvalue(loc, rval); + } + StatementKind::StorageLive(_) | + StatementKind::StorageDead(_) => {} + StatementKind::SetDiscriminant{ .. } => { + span_bug!(stmt.source_info.span, + "SetDiscriminant should not exist during borrowck"); + } + } + } + + fn gather_rvalue(&mut self, loc: Location, rvalue: &Rvalue<'tcx>) { + match *rvalue { + Rvalue::Use(ref operand) | + Rvalue::Repeat(ref operand, _) | + Rvalue::Cast(_, ref operand, _) | + Rvalue::UnaryOp(_, ref operand) => { + self.gather_operand(loc, operand) + } + Rvalue::BinaryOp(ref _binop, ref lhs, ref rhs) | + Rvalue::CheckedBinaryOp(ref _binop, ref lhs, ref rhs) => { + self.gather_operand(loc, lhs); + self.gather_operand(loc, rhs); + } + Rvalue::Aggregate(ref _kind, ref operands) => { + for operand in operands { + self.gather_operand(loc, operand); + } + } + Rvalue::Ref(..) | + Rvalue::Len(..) | + Rvalue::InlineAsm { .. } => {} + Rvalue::Box(..) => { + // This returns an rvalue with uninitialized contents. We can't + // move out of it here because it is an rvalue - assignments always + // completely initialize their lvalue. + // + // However, this does not matter - MIR building is careful to + // only emit a shallow free for the partially-initialized + // temporary. + // + // In any case, if we want to fix this, we have to register a + // special move and change the `statement_effect` functions. + } + } + } + + fn gather_terminator(&mut self, loc: Location, term: &Terminator<'tcx>) { + debug!("gather_terminator({:?}, {:?})", loc, term); + match term.kind { TerminatorKind::Goto { target: _ } | TerminatorKind::Resume | TerminatorKind::Unreachable => { } TerminatorKind::Return => { - let source = Location { block: bb, - statement_index: bb_data.statements.len() }; - debug!("gather_moves Return on_move_out_lval return {:?}", source); - bb_ctxt.on_move_out_lval(SK::Return, &Lvalue::ReturnPointer, source); + self.gather_move(loc, &Lvalue::ReturnPointer); } - TerminatorKind::If { ref cond, targets: _ } => { - let source = Location { block: bb, - statement_index: bb_data.statements.len() }; - bb_ctxt.on_operand(SK::If, cond, source); - } - - TerminatorKind::Assert { - ref cond, expected: _, - ref msg, target: _, cleanup: _ - } => { - // The `cond` is always of (copyable) type `bool`, - // so there will never be anything to move. - let _ = cond; - match *msg { - AssertMessage:: BoundsCheck { ref len, ref index } => { - // Same for the usize length and index in bounds-checking. - let _ = (len, index); - } - AssertMessage::Math(_) => {} - } - } - - TerminatorKind::SwitchInt { switch_ty: _, values: _, targets: _, ref discr } | - TerminatorKind::Switch { adt_def: _, targets: _, ref discr } => { - // The `discr` is not consumed; that is instead - // encoded on specific match arms (and for - // SwitchInt`, it is always a copyable integer - // type anyway). - let _ = discr; + TerminatorKind::If { .. } | + TerminatorKind::Assert { .. } | + TerminatorKind::SwitchInt { .. } | + TerminatorKind::Switch { .. } => { + // branching terminators - these don't move anything } TerminatorKind::Drop { ref location, target: _, unwind: _ } => { - let source = Location { block: bb, - statement_index: bb_data.statements.len() }; - bb_ctxt.on_move_out_lval(SK::Drop, location, source); + self.gather_move(loc, location); } TerminatorKind::DropAndReplace { ref location, ref value, .. } => { - let assigned_path = bb_ctxt.builder.move_path_for(location); - bb_ctxt.path_map.fill_to(assigned_path.index()); - - let source = Location { block: bb, - statement_index: bb_data.statements.len() }; - bb_ctxt.on_operand(SK::Use, value, source); + self.create_move_path(location); + self.gather_operand(loc, value); } TerminatorKind::Call { ref func, ref args, ref destination, cleanup: _ } => { - let source = Location { block: bb, - statement_index: bb_data.statements.len() }; - bb_ctxt.on_operand(SK::CallFn, func, source); + self.gather_operand(loc, func); for arg in args { - debug!("gather_moves Call on_operand {:?} {:?}", arg, source); - bb_ctxt.on_operand(SK::CallArg, arg, source); + self.gather_operand(loc, arg); } if let Some((ref destination, _bb)) = *destination { - debug!("gather_moves Call create_move_path {:?} {:?}", destination, source); - - // Ensure that the path_map contains entries even - // if the lvalue is assigned and never read. - let assigned_path = bb_ctxt.builder.move_path_for(destination); - bb_ctxt.path_map.fill_to(assigned_path.index()); - - bb_ctxt.builder.create_move_path(destination); + self.create_move_path(destination); } } } - - builder = bb_ctxt.builder; } - // At this point, we may have created some MovePaths that do not - // have corresponding entries in the path map. - // - // (For example, creating the path `a.b.c` may, as a side-effect, - // create a path for the parent path `a.b`.) - // - // All such paths were not referenced ... - // - // well you know, lets actually try just asserting that the path map *is* complete. - assert_eq!(path_map.len(), builder.pre_move_paths.len()); - - let pre_move_paths = builder.pre_move_paths; - let move_paths: Vec<_> = pre_move_paths.into_iter() - .map(|p| p.into_move_path()) - .collect(); - - debug!("{}", { - let mut seen: Vec<_> = move_paths.iter().map(|_| false).collect(); - for (j, &MoveOut { ref path, ref source }) in moves.iter().enumerate() { - debug!("MovePathData moves[{}]: MoveOut {{ path: {:?} = {:?}, source: {:?} }}", - j, path, move_paths[path.index()], source); - seen[path.index()] = true; - } - for (j, path) in move_paths.iter().enumerate() { - if !seen[j] { - debug!("MovePathData move_paths[{}]: {:?}", j, path); - } - } - "done dumping MovePathData" - }); - - MoveData { - move_paths: MovePathData { move_paths: move_paths, }, - moves: moves, - loc_map: LocMap { map: loc_map }, - path_map: PathMap { map: path_map }, - rev_lookup: builder.rev_lookup, - } -} - -struct BlockContext<'b, 'tcx: 'b> { - _tcx: TyCtxt<'b, 'tcx, 'tcx>, - moves: &'b mut Vec, - builder: MovePathDataBuilder<'tcx>, - path_map: &'b mut Vec>, - loc_map_bb: &'b mut Vec>, -} - -impl<'b, 'tcx: 'b> BlockContext<'b, 'tcx> { - fn on_move_out_lval(&mut self, - stmt_kind: StmtKind, - lval: &Lvalue<'tcx>, - source: Location) { - let i = source.statement_index; - let index = MoveOutIndex::new(self.moves.len()); - - let path = self.builder.move_path_for(lval); - self.moves.push(MoveOut { path: path, source: source.clone() }); - self.path_map.fill_to(path.index()); - - debug!("ctxt: {:?} add consume of lval: {:?} \ - at index: {:?} \ - to path_map for path: {:?} and \ - to loc_map for loc: {:?}", - stmt_kind, lval, index, path, source); - - debug_assert!(path.index() < self.path_map.len()); - // this is actually a questionable assert; at the very - // least, incorrect input code can probably cause it to - // fire. - assert!(self.path_map[path.index()].iter().find(|idx| **idx == index).is_none()); - self.path_map[path.index()].push(index); - - debug_assert!(i < self.loc_map_bb.len()); - debug_assert!(self.loc_map_bb[i].iter().find(|idx| **idx == index).is_none()); - self.loc_map_bb[i].push(index); - } - - fn on_operand(&mut self, stmt_kind: StmtKind, operand: &Operand<'tcx>, source: Location) { + fn gather_operand(&mut self, loc: Location, operand: &Operand<'tcx>) { match *operand { Operand::Constant(..) => {} // not-a-move Operand::Consume(ref lval) => { // a move - self.on_move_out_lval(stmt_kind, lval, source); + self.gather_move(loc, lval); } } } + + fn gather_move(&mut self, loc: Location, lval: &Lvalue<'tcx>) { + debug!("gather_move({:?}, {:?})", loc, lval); + + let lv_ty = lval.ty(self.mir, self.tcx).to_ty(self.tcx); + if !lv_ty.moves_by_default(self.tcx, self.param_env, DUMMY_SP) { + debug!("gather_move({:?}, {:?}) - {:?} is Copy. skipping", loc, lval, lv_ty); + return + } + + let path = self.move_path_for(lval).unwrap_or_else(|_| { + // Moving out of a bad path. Eventually, this should be a MIR + // borrowck error instead of a bug. + span_bug!(self.mir.span, + "Broken MIR: moving out of lvalue {:?}: {:?} at {:?}", + lval, lv_ty, loc); + }); + let move_out = self.data.moves.push(MoveOut { path: path, source: loc }); + + debug!("gather_move({:?}, {:?}): adding move {:?} of {:?}", + loc, lval, move_out, path); + + self.data.path_map[path].push(move_out); + self.data.loc_map[loc].push(move_out); + } } diff --git a/src/librustc_borrowck/borrowck/mir/mod.rs b/src/librustc_borrowck/borrowck/mir/mod.rs index e035e268b1c4..7c2410a2c145 100644 --- a/src/librustc_borrowck/borrowck/mir/mod.rs +++ b/src/librustc_borrowck/borrowck/mir/mod.rs @@ -34,8 +34,7 @@ use self::dataflow::{DataflowOperator}; use self::dataflow::{Dataflow, DataflowAnalysis, DataflowResults}; use self::dataflow::{MaybeInitializedLvals, MaybeUninitializedLvals}; use self::dataflow::{DefinitelyInitializedLvals}; -use self::gather_moves::{MoveData, MovePathIndex}; -use self::gather_moves::{MovePathContent, MovePathData}; +use self::gather_moves::{MoveData, MovePathIndex, LookupResult}; fn has_rustc_mir_with(attrs: &[ast::Attribute], name: &str) -> Option> { for attr in attrs { @@ -78,8 +77,8 @@ pub fn borrowck_mir<'a, 'tcx: 'a>( let tcx = bcx.tcx; - let move_data = MoveData::gather_moves(mir, tcx); let param_env = ty::ParameterEnvironment::for_item(tcx, id); + let move_data = MoveData::gather_moves(mir, tcx, ¶m_env); let mdpe = MoveDataParamEnv { move_data: move_data, param_env: param_env }; let flow_inits = do_dataflow(tcx, mir, id, attributes, &mdpe, MaybeInitializedLvals::new(tcx, mir)); @@ -211,23 +210,23 @@ impl DropFlagState { } } -fn move_path_children_matching<'tcx, F>(move_paths: &MovePathData<'tcx>, +fn move_path_children_matching<'tcx, F>(move_data: &MoveData<'tcx>, path: MovePathIndex, mut cond: F) -> Option where F: FnMut(&repr::LvalueProjection<'tcx>) -> bool { - let mut next_child = move_paths[path].first_child; + let mut next_child = move_data.move_paths[path].first_child; while let Some(child_index) = next_child { - match move_paths[child_index].content { - MovePathContent::Lvalue(repr::Lvalue::Projection(ref proj)) => { + match move_data.move_paths[child_index].lvalue { + repr::Lvalue::Projection(ref proj) => { if cond(proj) { return Some(child_index) } } _ => {} } - next_child = move_paths[child_index].next_sibling; + next_child = move_data.move_paths[child_index].next_sibling; } None @@ -272,6 +271,24 @@ fn lvalue_contents_drop_state_cannot_differ<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx } } +fn on_lookup_result_bits<'a, 'tcx, F>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + mir: &Mir<'tcx>, + move_data: &MoveData<'tcx>, + lookup_result: LookupResult, + each_child: F) + where F: FnMut(MovePathIndex) +{ + match lookup_result { + LookupResult::Parent(..) => { + // access to untracked value - do not touch children + } + LookupResult::Exact(e) => { + on_all_children_bits(tcx, mir, move_data, e, each_child) + } + } +} + fn on_all_children_bits<'a, 'tcx, F>( tcx: TyCtxt<'a, 'tcx, 'tcx>, mir: &Mir<'tcx>, @@ -286,12 +303,8 @@ fn on_all_children_bits<'a, 'tcx, F>( move_data: &MoveData<'tcx>, path: MovePathIndex) -> bool { - match move_data.move_paths[path].content { - MovePathContent::Lvalue(ref lvalue) => { - lvalue_contents_drop_state_cannot_differ(tcx, mir, lvalue) - } - _ => true - } + lvalue_contents_drop_state_cannot_differ( + tcx, mir, &move_data.move_paths[path].lvalue) } fn on_all_children_bits<'a, 'tcx, F>( @@ -327,10 +340,10 @@ fn drop_flag_effects_for_function_entry<'a, 'tcx, F>( let move_data = &ctxt.move_data; for (arg, _) in mir.arg_decls.iter_enumerated() { let lvalue = repr::Lvalue::Arg(arg); - let move_path_index = move_data.rev_lookup.find(&lvalue); - on_all_children_bits(tcx, mir, move_data, - move_path_index, - |moi| callback(moi, DropFlagState::Present)); + let lookup_result = move_data.rev_lookup.find(&lvalue); + on_lookup_result_bits(tcx, mir, move_data, + lookup_result, + |moi| callback(moi, DropFlagState::Present)); } } @@ -352,11 +365,10 @@ fn drop_flag_effects_for_location<'a, 'tcx, F>( debug!("moving out of path {:?}", move_data.move_paths[path]); // don't move out of non-Copy things - if let MovePathContent::Lvalue(ref lvalue) = move_data.move_paths[path].content { - let ty = lvalue.ty(mir, tcx).to_ty(tcx); - if !ty.moves_by_default(tcx, param_env, DUMMY_SP) { - continue; - } + let lvalue = &move_data.move_paths[path].lvalue; + let ty = lvalue.ty(mir, tcx).to_ty(tcx); + if !ty.moves_by_default(tcx, param_env, DUMMY_SP) { + continue; } on_all_children_bits(tcx, mir, move_data, @@ -372,9 +384,9 @@ fn drop_flag_effects_for_location<'a, 'tcx, F>( } repr::StatementKind::Assign(ref lvalue, _) => { debug!("drop_flag_effects: assignment {:?}", stmt); - on_all_children_bits(tcx, mir, move_data, - move_data.rev_lookup.find(lvalue), - |moi| callback(moi, DropFlagState::Present)) + on_lookup_result_bits(tcx, mir, move_data, + move_data.rev_lookup.find(lvalue), + |moi| callback(moi, DropFlagState::Present)) } repr::StatementKind::StorageLive(_) | repr::StatementKind::StorageDead(_) => {} @@ -383,9 +395,9 @@ fn drop_flag_effects_for_location<'a, 'tcx, F>( debug!("drop_flag_effects: replace {:?}", block.terminator()); match block.terminator().kind { repr::TerminatorKind::DropAndReplace { ref location, .. } => { - on_all_children_bits(tcx, mir, move_data, - move_data.rev_lookup.find(location), - |moi| callback(moi, DropFlagState::Present)) + on_lookup_result_bits(tcx, mir, move_data, + move_data.rev_lookup.find(location), + |moi| callback(moi, DropFlagState::Present)) } _ => { // other terminators do not contain move-ins diff --git a/src/librustc_trans/mir/analyze.rs b/src/librustc_trans/mir/analyze.rs index cfd1ec099686..e13da2531024 100644 --- a/src/librustc_trans/mir/analyze.rs +++ b/src/librustc_trans/mir/analyze.rs @@ -180,7 +180,6 @@ impl<'mir, 'bcx, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'bcx, 'tcx> { LvalueContext::Store | LvalueContext::Inspect | LvalueContext::Borrow { .. } | - LvalueContext::Slice { .. } | LvalueContext::Projection => { self.mark_as_lvalue(index); } From 7b25e886028195a4f90c0baa5cc9101ebeceb5a3 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Sun, 24 Jul 2016 13:56:27 +0300 Subject: [PATCH 385/443] forbid moves out of slices The wording of RFC #495 enables moves out of slices. Unfortuantely, non-zeroing moves out of slices introduce a very annoying complication: as slices can vary in their length, indexes from the start and end may or may not overlap depending on the slice's exact length, which prevents assigning a particular drop flag for each individual element. For example, in the code ```Rust fn foo(a: Box<[Box<[T]>]>, c: bool) -> T { match (a, c) { (box [box [t, ..], ..], true) => t, (box [.., box [.., t]], false) => t, _ => panic!() } } ``` If the condition is false, we have to drop the first element of `a`, unless `a` has size 1 in which case we drop all the elements of it but the last. If someone comes with a nice way of handling it, we can always re-allow moves out of slices. This is a [breaking-change], but it is behind the `slice_patterns` feature gate and was not allowed until recently. --- .../borrowck/gather_loans/gather_moves.rs | 1 + .../borrowck/gather_loans/move_error.rs | 26 ++++++++++--------- src/test/compile-fail/move-out-of-slice-1.rs | 21 +++++++++++++++ 3 files changed, 36 insertions(+), 12 deletions(-) create mode 100644 src/test/compile-fail/move-out-of-slice-1.rs diff --git a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs index 3e335dacc8ed..9bdc6887f6d0 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs @@ -185,6 +185,7 @@ fn check_and_get_illegal_move_origin<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, check_and_get_illegal_move_origin(bccx, b) } } + ty::TySlice(..) => Some(cmt.clone()), _ => { check_and_get_illegal_move_origin(bccx, b) } diff --git a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs index 3fa7c252b842..9fbf1492f5d2 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs @@ -16,7 +16,6 @@ use rustc::ty; use syntax::ast; use syntax_pos; use errors::DiagnosticBuilder; -use rustc::hir; pub struct MoveErrorCollector<'tcx> { errors: Vec> @@ -131,17 +130,20 @@ fn report_cannot_move_out_of<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, err } - Categorization::Interior(ref b, mc::InteriorElement(Kind::Index, _)) => { - let expr = bccx.tcx.map.expect_expr(move_from.id); - if let hir::ExprIndex(..) = expr.node { - let mut err = struct_span_err!(bccx, move_from.span, E0508, - "cannot move out of type `{}`, \ - a non-copy fixed-size array", - b.ty); - err.span_label(move_from.span, &format!("cannot move out of here")); - err - } else { - span_bug!(move_from.span, "this path should not cause illegal move"); + Categorization::Interior(ref b, mc::InteriorElement(ik, _)) => { + match (&b.ty.sty, ik) { + (&ty::TySlice(..), _) | + (_, Kind::Index) => { + let mut err = struct_span_err!(bccx, move_from.span, E0508, + "cannot move out of type `{}`, \ + a non-copy array", + b.ty); + err.span_label(move_from.span, &format!("cannot move out of here")); + err + } + (_, Kind::Pattern) => { + span_bug!(move_from.span, "this path should not cause illegal move"); + } } } diff --git a/src/test/compile-fail/move-out-of-slice-1.rs b/src/test/compile-fail/move-out-of-slice-1.rs new file mode 100644 index 000000000000..f3efc68701e9 --- /dev/null +++ b/src/test/compile-fail/move-out-of-slice-1.rs @@ -0,0 +1,21 @@ +// 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. + +#![feature(slice_patterns, box_patterns)] + +struct A; + +fn main() { + let a: Box<[A]> = Box::new([A]); + match a { + box [a] => {}, //~ ERROR cannot move out of type `[A]` + _ => {} + } +} From eeedc144be1f57cda196638d7bf38cf4cd2b9700 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Thu, 8 Sep 2016 20:12:53 +0300 Subject: [PATCH 386/443] fix dynamic drop for unions Moving out of a union is now treated like moving out of its parent type. Fixes #36246 --- .../borrowck/mir/gather_moves.rs | 52 ++++++++++++------- src/librustc_borrowck/borrowck/mir/mod.rs | 6 +-- src/test/run-pass/dynamic-drop.rs | 25 ++++++++- 3 files changed, 60 insertions(+), 23 deletions(-) diff --git a/src/librustc_borrowck/borrowck/mir/gather_moves.rs b/src/librustc_borrowck/borrowck/mir/gather_moves.rs index 2713a3c371db..bd38f554dc9b 100644 --- a/src/librustc_borrowck/borrowck/mir/gather_moves.rs +++ b/src/librustc_borrowck/borrowck/mir/gather_moves.rs @@ -12,7 +12,6 @@ use rustc::ty::{self, TyCtxt, ParameterEnvironment}; use rustc::mir::repr::*; use rustc::util::nodemap::FnvHashMap; -use rustc::util::common::ErrorReported; use rustc_data_structures::indexed_vec::{IndexVec}; use syntax::codemap::DUMMY_SP; @@ -198,6 +197,11 @@ struct MoveDataBuilder<'a, 'tcx: 'a> { data: MoveData<'tcx>, } +pub enum MovePathError { + IllegalMove, + UnionMove { path: MovePathIndex }, +} + impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> { fn new(mir: &'a Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -256,7 +260,7 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> { move_path } - /// This creates a MovePath for a given lvalue, returning an `ErrorReported` + /// This creates a MovePath for a given lvalue, returning an `MovePathError` /// if that lvalue can't be moved from. /// /// NOTE: lvalues behind references *do not* get a move path, which is @@ -264,7 +268,7 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> { /// /// Maybe we should have seperate "borrowck" and "moveck" modes. fn move_path_for(&mut self, lval: &Lvalue<'tcx>) - -> Result + -> Result { debug!("lookup({:?})", lval); match *lval { @@ -272,7 +276,7 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> { Lvalue::Arg(arg) => Ok(self.data.rev_lookup.args[arg]), Lvalue::Temp(temp) => Ok(self.data.rev_lookup.temps[temp]), // error: can't move out of a static - Lvalue::Static(..) => Err(ErrorReported), + Lvalue::Static(..) => Err(MovePathError::IllegalMove), Lvalue::ReturnPointer => match self.data.rev_lookup.return_ptr { Some(ptr) => Ok(ptr), ref mut ptr @ None => { @@ -300,21 +304,28 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> { fn move_path_for_projection(&mut self, lval: &Lvalue<'tcx>, proj: &LvalueProjection<'tcx>) - -> Result + -> Result { let base = try!(self.move_path_for(&proj.base)); let lv_ty = proj.base.ty(self.mir, self.tcx).to_ty(self.tcx); match lv_ty.sty { // error: can't move out of borrowed content - ty::TyRef(..) | ty::TyRawPtr(..) => return Err(ErrorReported), + ty::TyRef(..) | ty::TyRawPtr(..) => return Err(MovePathError::IllegalMove), // error: can't move out of struct with destructor - ty::TyStruct(adt, _) | ty::TyEnum(adt, _) if adt.has_dtor() => - return Err(ErrorReported), - - ty::TyArray(..) | ty::TySlice(..) => match proj.elem { + ty::TyAdt(adt, _) if adt.has_dtor() => + return Err(MovePathError::IllegalMove), + // move out of union - always move the entire union + ty::TyAdt(adt, _) if adt.is_union() => + return Err(MovePathError::UnionMove { path: base }), + // error: can't move out of a slice + ty::TySlice(..) => + return Err(MovePathError::IllegalMove), + ty::TyArray(..) => match proj.elem { // error: can't move out of an array - ProjectionElem::Index(..) => return Err(ErrorReported), - _ => {} + ProjectionElem::Index(..) => return Err(MovePathError::IllegalMove), + _ => { + // FIXME: still badly broken + } }, _ => {} }; @@ -521,13 +532,16 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> { return } - let path = self.move_path_for(lval).unwrap_or_else(|_| { - // Moving out of a bad path. Eventually, this should be a MIR - // borrowck error instead of a bug. - span_bug!(self.mir.span, - "Broken MIR: moving out of lvalue {:?}: {:?} at {:?}", - lval, lv_ty, loc); - }); + let path = match self.move_path_for(lval) { + Ok(path) | Err(MovePathError::UnionMove { path }) => path, + Err(MovePathError::IllegalMove) => { + // Moving out of a bad path. Eventually, this should be a MIR + // borrowck error instead of a bug. + span_bug!(self.mir.span, + "Broken MIR: moving out of lvalue {:?}: {:?} at {:?}", + lval, lv_ty, loc); + } + }; let move_out = self.data.moves.push(MoveOut { path: path, source: loc }); debug!("gather_move({:?}, {:?}): adding move {:?} of {:?}", diff --git a/src/librustc_borrowck/borrowck/mir/mod.rs b/src/librustc_borrowck/borrowck/mir/mod.rs index 7c2410a2c145..5b5d782bc83a 100644 --- a/src/librustc_borrowck/borrowck/mir/mod.rs +++ b/src/librustc_borrowck/borrowck/mir/mod.rs @@ -256,12 +256,12 @@ fn lvalue_contents_drop_state_cannot_differ<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx let ty = lv.ty(mir, tcx).to_ty(tcx); match ty.sty { ty::TyArray(..) | ty::TySlice(..) | ty::TyRef(..) | ty::TyRawPtr(..) => { - debug!("lvalue_contents_drop_state_cannot_differ lv: {:?} ty: {:?} refd => false", + debug!("lvalue_contents_drop_state_cannot_differ lv: {:?} ty: {:?} refd => true", lv, ty); true } - ty::TyAdt(def, _) if def.has_dtor() => { - debug!("lvalue_contents_drop_state_cannot_differ lv: {:?} ty: {:?} Drop => false", + ty::TyAdt(def, _) if def.has_dtor() || def.is_union() => { + debug!("lvalue_contents_drop_state_cannot_differ lv: {:?} ty: {:?} Drop => true", lv, ty); true } diff --git a/src/test/run-pass/dynamic-drop.rs b/src/test/run-pass/dynamic-drop.rs index 2b016dfb33ec..a2cca2064092 100644 --- a/src/test/run-pass/dynamic-drop.rs +++ b/src/test/run-pass/dynamic-drop.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(rustc_attrs)] +#![feature(untagged_unions)] use std::cell::{Cell, RefCell}; use std::panic; @@ -111,6 +111,20 @@ fn assignment1(a: &Allocator, c0: bool) { _v = _w; } +#[allow(unions_with_drop_fields)] +union Boxy { + a: T, + b: T, +} + +fn union1(a: &Allocator) { + unsafe { + let mut u = Boxy { a: a.alloc() }; + u.b = a.alloc(); + drop(u.a); + } +} + fn run_test(mut f: F) where F: FnMut(&Allocator) { @@ -136,6 +150,13 @@ fn run_test(mut f: F) } } +fn run_test_nopanic(mut f: F) + where F: FnMut(&Allocator) +{ + let first_alloc = Allocator::new(usize::MAX); + f(&first_alloc); +} + fn main() { run_test(|a| dynamic_init(a, false)); run_test(|a| dynamic_init(a, true)); @@ -149,4 +170,6 @@ fn main() { run_test(|a| assignment1(a, false)); run_test(|a| assignment1(a, true)); + + run_test_nopanic(|a| union1(a)); } From 5c5f75223c1f707e70bf3fdd98449338433c41f8 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Fri, 16 Sep 2016 16:02:43 +0300 Subject: [PATCH 387/443] fix test fallout --- .../borrowck/borrowck-move-out-of-vec-tail.rs | 2 +- .../compile-fail/borrowck/borrowck-vec-pattern-nesting.rs | 2 +- src/test/compile-fail/issue-12567.rs | 8 ++++---- src/test/compile-fail/mir-dataflow/uninits-2.rs | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/test/compile-fail/borrowck/borrowck-move-out-of-vec-tail.rs b/src/test/compile-fail/borrowck/borrowck-move-out-of-vec-tail.rs index f595d9d81cc6..51e00a0ad2c3 100644 --- a/src/test/compile-fail/borrowck/borrowck-move-out-of-vec-tail.rs +++ b/src/test/compile-fail/borrowck/borrowck-move-out-of-vec-tail.rs @@ -28,7 +28,7 @@ pub fn main() { [_, ref tail..] => { match tail { &[Foo { string: a }, - //~^ ERROR cannot move out of borrowed content + //~^ ERROR cannot move out of type `[Foo]` //~| cannot move out //~| to prevent move Foo { string: b }] => { diff --git a/src/test/compile-fail/borrowck/borrowck-vec-pattern-nesting.rs b/src/test/compile-fail/borrowck/borrowck-vec-pattern-nesting.rs index d89b4100789f..ae001e4e34d1 100644 --- a/src/test/compile-fail/borrowck/borrowck-vec-pattern-nesting.rs +++ b/src/test/compile-fail/borrowck/borrowck-vec-pattern-nesting.rs @@ -40,7 +40,7 @@ fn c() { let mut vec = vec!(box 1, box 2, box 3); let vec: &mut [Box] = &mut vec; match vec { - &mut [_a, //~ ERROR cannot move out of borrowed content + &mut [_a, //~ ERROR cannot move out //~| cannot move out //~| to prevent move .. diff --git a/src/test/compile-fail/issue-12567.rs b/src/test/compile-fail/issue-12567.rs index 32a6ea4f062c..15d9a318d29c 100644 --- a/src/test/compile-fail/issue-12567.rs +++ b/src/test/compile-fail/issue-12567.rs @@ -15,12 +15,12 @@ fn match_vecs<'a, T>(l1: &'a [T], l2: &'a [T]) { (&[], &[]) => println!("both empty"), (&[], &[hd, ..]) | (&[hd, ..], &[]) => println!("one empty"), - //~^^ ERROR: cannot move out of borrowed content - //~^^^ ERROR: cannot move out of borrowed content + //~^^ ERROR: cannot move out of type `[T]`, a non-copy array + //~^^^ ERROR: cannot move out of type `[T]`, a non-copy array (&[hd1, ..], &[hd2, ..]) => println!("both nonempty"), - //~^^ ERROR: cannot move out of borrowed content - //~^^^ ERROR: cannot move out of borrowed content + //~^^ ERROR: cannot move out of type `[T]`, a non-copy array + //~^^^ ERROR: cannot move out of type `[T]`, a non-copy array } } diff --git a/src/test/compile-fail/mir-dataflow/uninits-2.rs b/src/test/compile-fail/mir-dataflow/uninits-2.rs index e0bf42534499..94f812a40a9b 100644 --- a/src/test/compile-fail/mir-dataflow/uninits-2.rs +++ b/src/test/compile-fail/mir-dataflow/uninits-2.rs @@ -23,7 +23,7 @@ struct S(i32); fn foo(x: &mut S) { // `x` is initialized here, so maybe-uninit bit is 0. - unsafe { *rustc_peek(&x) }; //~ ERROR rustc_peek: bit not set + unsafe { rustc_peek(&x) }; //~ ERROR rustc_peek: bit not set ::std::mem::drop(x); From e8a44d29b633412b4173be8f1bfb6dae7ac3c45e Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Sat, 10 Sep 2016 14:33:29 -0700 Subject: [PATCH 388/443] librustc_mir: Remove `&*x` when `x` has a reference type. This introduces a new `InstCombine` pass for us to place such peephole optimizations. --- src/librustc_driver/driver.rs | 3 + src/librustc_mir/transform/instcombine.rs | 110 ++++++++++++++++++++++ src/librustc_mir/transform/mod.rs | 2 + 3 files changed, 115 insertions(+) create mode 100644 src/librustc_mir/transform/instcombine.rs diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 36e9fccdf5fd..14cd05279b1c 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -1017,6 +1017,7 @@ pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, passes.push_pass(box mir::transform::no_landing_pads::NoLandingPads); passes.push_pass(box mir::transform::simplify_cfg::SimplifyCfg::new("no-landing-pads")); + // From here on out, regions are gone. passes.push_pass(box mir::transform::erase_regions::EraseRegions); passes.push_pass(box mir::transform::add_call_guards::AddCallGuards); @@ -1024,6 +1025,8 @@ pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, passes.push_pass(box mir::transform::no_landing_pads::NoLandingPads); passes.push_pass(box mir::transform::simplify_cfg::SimplifyCfg::new("elaborate-drops")); + // No lifetime analysis based on borrowing can be done from here on out. + passes.push_pass(box mir::transform::instcombine::InstCombine::new()); passes.push_pass(box mir::transform::deaggregator::Deaggregator); passes.push_pass(box mir::transform::add_call_guards::AddCallGuards); diff --git a/src/librustc_mir/transform/instcombine.rs b/src/librustc_mir/transform/instcombine.rs new file mode 100644 index 000000000000..a0331f03b019 --- /dev/null +++ b/src/librustc_mir/transform/instcombine.rs @@ -0,0 +1,110 @@ +// 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. + +//! Performs various peephole optimizations. + +use rustc::mir::repr::{Location, Lvalue, Mir, Operand, ProjectionElem, Rvalue}; +use rustc::mir::transform::{MirPass, MirSource, Pass}; +use rustc::mir::visit::{MutVisitor, Visitor}; +use rustc::ty::TyCtxt; +use rustc::util::nodemap::FnvHashSet; +use std::mem; + +pub struct InstCombine { + optimizations: OptimizationList, +} + +impl InstCombine { + pub fn new() -> InstCombine { + InstCombine { + optimizations: OptimizationList::default(), + } + } +} + +impl Pass for InstCombine {} + +impl<'tcx> MirPass<'tcx> for InstCombine { + fn run_pass<'a>(&mut self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + _: MirSource, + mir: &mut Mir<'tcx>) { + // We only run when optimizing MIR (at any level). + if tcx.sess.opts.debugging_opts.mir_opt_level == Some(0) { + return + } + + // First, find optimization opportunities. This is done in a pre-pass to keep the MIR + // read-only so that we can do global analyses on the MIR in the process (e.g. + // `Lvalue::ty()`). + { + let mut optimization_finder = OptimizationFinder::new(mir, tcx); + optimization_finder.visit_mir(mir); + self.optimizations = optimization_finder.optimizations + } + + // Then carry out those optimizations. + MutVisitor::visit_mir(&mut *self, mir); + } +} + +impl<'tcx> MutVisitor<'tcx> for InstCombine { + fn visit_rvalue(&mut self, rvalue: &mut Rvalue<'tcx>, location: Location) { + if self.optimizations.and_stars.remove(&location) { + debug!("Replacing `&*`: {:?}", rvalue); + let new_lvalue = match *rvalue { + Rvalue::Ref(_, _, Lvalue::Projection(ref mut projection)) => { + mem::replace(&mut projection.base, Lvalue::ReturnPointer) + } + _ => bug!("Detected `&*` but didn't find `&*`!"), + }; + *rvalue = Rvalue::Use(Operand::Consume(new_lvalue)) + } + + self.super_rvalue(rvalue, location) + } +} + +/// Finds optimization opportunities on the MIR. +struct OptimizationFinder<'b, 'a, 'tcx:'a+'b> { + mir: &'b Mir<'tcx>, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + optimizations: OptimizationList, +} + +impl<'b, 'a, 'tcx:'b> OptimizationFinder<'b, 'a, 'tcx> { + fn new(mir: &'b Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> OptimizationFinder<'b, 'a, 'tcx> { + OptimizationFinder { + mir: mir, + tcx: tcx, + optimizations: OptimizationList::default(), + } + } +} + +impl<'b, 'a, 'tcx> Visitor<'tcx> for OptimizationFinder<'b, 'a, 'tcx> { + fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { + if let Rvalue::Ref(_, _, Lvalue::Projection(ref projection)) = *rvalue { + if let ProjectionElem::Deref = projection.elem { + if projection.base.ty(self.mir, self.tcx).to_ty(self.tcx).is_region_ptr() { + self.optimizations.and_stars.insert(location); + } + } + } + + self.super_rvalue(rvalue, location) + } +} + +#[derive(Default)] +struct OptimizationList { + and_stars: FnvHashSet, +} + diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs index c3485b8256da..e99b7a976e3e 100644 --- a/src/librustc_mir/transform/mod.rs +++ b/src/librustc_mir/transform/mod.rs @@ -18,3 +18,5 @@ pub mod promote_consts; pub mod qualify_consts; pub mod dump_mir; pub mod deaggregator; +pub mod instcombine; + From ad6321573259f5877c9186fb084b7273d89dde71 Mon Sep 17 00:00:00 2001 From: Mark-Simulacrum Date: Thu, 15 Sep 2016 19:59:29 -0600 Subject: [PATCH 389/443] Add links between format_args! macro and std::fmt::Arguments struct --- src/libcore/fmt/mod.rs | 10 +++++++--- src/libstd/macros.rs | 14 ++++++++++---- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index 66ef92928eb0..8342d663cdc7 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -272,10 +272,14 @@ impl<'a> Arguments<'a> { /// safely be done so, so no constructors are given and the fields are private /// to prevent modification. /// -/// The `format_args!` macro will safely create an instance of this structure +/// The [`format_args!`] macro will safely create an instance of this structure /// and pass it to a function or closure, passed as the first argument. The -/// macro validates the format string at compile-time so usage of the `write` -/// and `format` functions can be safely performed. +/// macro validates the format string at compile-time so usage of the [`write`] +/// and [`format`] functions can be safely performed. +/// +/// [`format_args!`]: ../../std/macro.format_args.html +/// [`format`]: ../../std/fmt/fn.format.html +/// [`write`]: ../../std/fmt/fn.write.html #[stable(feature = "rust1", since = "1.0.0")] #[derive(Copy, Clone)] pub struct Arguments<'a> { diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index 6f0f6ecab5ba..c78840bd42b0 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -193,12 +193,18 @@ macro_rules! assert_approx_eq { pub mod builtin { /// The core macro for formatted string creation & output. /// - /// This macro produces a value of type `fmt::Arguments`. This value can be - /// passed to the functions in `std::fmt` for performing useful functions. - /// All other formatting macros (`format!`, `write!`, `println!`, etc) are + /// This macro produces a value of type [`fmt::Arguments`]. This value can be + /// passed to the functions in [`std::fmt`] for performing useful functions. + /// All other formatting macros ([`format!`], [`write!`], [`println!`], etc) are /// proxied through this one. /// - /// For more information, see the documentation in `std::fmt`. + /// For more information, see the documentation in [`std::fmt`]. + /// + /// [`fmt::Arguments`]: ../std/fmt/struct.Arguments.html + /// [`std::fmt`]: ../std/fmt/index.html + /// [`format!`]: ../std/macro.format.html + /// [`write!`]: ../std/macro.write.html + /// [`println!`]: ../std/macro.println.html /// /// # Examples /// From d8b2cfeae6fbc1a9d7e86c9809f27ad1200903cb Mon Sep 17 00:00:00 2001 From: Cobrand Date: Fri, 16 Sep 2016 23:52:03 +0200 Subject: [PATCH 390/443] Remove stray println! when invoking error E0316 --- src/librustc/middle/resolve_lifetime.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 95706b5677a6..2d93c33afb40 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -337,7 +337,6 @@ impl<'a, 'tcx, 'v> Visitor<'v> for LifetimeContext<'a, 'tcx> { if !self.trait_ref_hack || !trait_ref.bound_lifetimes.is_empty() { if self.trait_ref_hack { - println!("{:?}", trait_ref.span); span_err!(self.sess, trait_ref.span, E0316, "nested quantification of lifetimes"); } From d104e5bfb70f7ee3fc3e7d30e6021ae804ce87e5 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Fri, 16 Sep 2016 01:08:12 +0300 Subject: [PATCH 391/443] Up the LLVM Fixes #36474 --- src/llvm | 2 +- src/rustllvm/llvm-auto-clean-trigger | 2 +- src/test/run-pass/issue-36474.rs | 40 ++++++++++++++++++++++++++++ 3 files changed, 42 insertions(+), 2 deletions(-) create mode 100644 src/test/run-pass/issue-36474.rs diff --git a/src/llvm b/src/llvm index 16b79d01fd6d..7801978ec1f3 160000 --- a/src/llvm +++ b/src/llvm @@ -1 +1 @@ -Subproject commit 16b79d01fd6d942cf3c9120b92df56b13ec92665 +Subproject commit 7801978ec1f3637fcda1b564048ebc732bf586af diff --git a/src/rustllvm/llvm-auto-clean-trigger b/src/rustllvm/llvm-auto-clean-trigger index 1080070d21a3..ea8d59290df2 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. -2016-08-30 +2016-09-17 diff --git a/src/test/run-pass/issue-36474.rs b/src/test/run-pass/issue-36474.rs new file mode 100644 index 000000000000..025244ca6648 --- /dev/null +++ b/src/test/run-pass/issue-36474.rs @@ -0,0 +1,40 @@ +// 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. + +fn main() { + remove_axis(&3, 0); +} + +trait Dimension { + fn slice(&self) -> &[usize]; +} + +impl Dimension for () { + fn slice(&self) -> &[usize] { &[] } +} + +impl Dimension for usize { + fn slice(&self) -> &[usize] { + unsafe { + ::std::slice::from_raw_parts(self, 1) + } + } +} + +fn remove_axis(value: &usize, axis: usize) -> () { + let tup = (); + let mut it = tup.slice().iter(); + for (i, _) in value.slice().iter().enumerate() { + if i == axis { + continue; + } + it.next(); + } +} From 2cee9ec3b36933e143f2b2cc36a351da0a9114eb Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Sat, 17 Sep 2016 23:14:09 +0000 Subject: [PATCH 392/443] Ensure that macro invocations are folded and visited the same order. --- src/libsyntax/fold.rs | 84 ++++++++++++++++-------------------------- src/libsyntax/visit.rs | 10 ++--- 2 files changed, 36 insertions(+), 58 deletions(-) diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 9fb4d0203f41..36f273e1dbc2 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -478,8 +478,8 @@ pub fn noop_fold_parenthesized_parameter_data(data: ParenthesizedPara pub fn noop_fold_local(l: P, fld: &mut T) -> P { l.map(|Local {id, pat, ty, init, span, attrs}| Local { id: fld.new_id(id), - ty: ty.map(|t| fld.fold_ty(t)), pat: fld.fold_pat(pat), + ty: ty.map(|t| fld.fold_ty(t)), init: init.map(|e| fld.fold_expr(e)), span: fld.new_span(span), attrs: fold_attrs(attrs.into(), fld).into(), @@ -860,14 +860,10 @@ pub fn noop_fold_item_kind(i: ItemKind, folder: &mut T) -> ItemKind { ItemKind::Const(folder.fold_ty(t), folder.fold_expr(e)) } ItemKind::Fn(decl, unsafety, constness, abi, generics, body) => { - ItemKind::Fn( - folder.fold_fn_decl(decl), - unsafety, - constness, - abi, - folder.fold_generics(generics), - folder.fold_block(body) - ) + let generics = folder.fold_generics(generics); + let decl = folder.fold_fn_decl(decl); + let body = folder.fold_block(body); + ItemKind::Fn(decl, unsafety, constness, abi, generics, body) } ItemKind::Mod(m) => ItemKind::Mod(folder.fold_mod(m)), ItemKind::ForeignMod(nm) => ItemKind::ForeignMod(folder.fold_foreign_mod(nm)), @@ -875,50 +871,35 @@ pub fn noop_fold_item_kind(i: ItemKind, folder: &mut T) -> ItemKind { ItemKind::Ty(folder.fold_ty(t), folder.fold_generics(generics)) } ItemKind::Enum(enum_definition, generics) => { - ItemKind::Enum( - ast::EnumDef { - variants: enum_definition.variants.move_map(|x| folder.fold_variant(x)), - }, - folder.fold_generics(generics)) + let generics = folder.fold_generics(generics); + let variants = enum_definition.variants.move_map(|x| folder.fold_variant(x)); + ItemKind::Enum(ast::EnumDef { variants: variants }, generics) } ItemKind::Struct(struct_def, generics) => { - let struct_def = folder.fold_variant_data(struct_def); - ItemKind::Struct(struct_def, folder.fold_generics(generics)) + let generics = folder.fold_generics(generics); + ItemKind::Struct(folder.fold_variant_data(struct_def), generics) } ItemKind::Union(struct_def, generics) => { - let struct_def = folder.fold_variant_data(struct_def); - ItemKind::Union(struct_def, folder.fold_generics(generics)) + let generics = folder.fold_generics(generics); + ItemKind::Union(folder.fold_variant_data(struct_def), generics) } ItemKind::DefaultImpl(unsafety, ref trait_ref) => { ItemKind::DefaultImpl(unsafety, folder.fold_trait_ref((*trait_ref).clone())) } - ItemKind::Impl(unsafety, polarity, generics, ifce, ty, impl_items) => { - let new_impl_items = impl_items.move_flat_map(|item| { - folder.fold_impl_item(item) - }); - let ifce = match ifce { - None => None, - Some(ref trait_ref) => { - Some(folder.fold_trait_ref((*trait_ref).clone())) - } - }; - ItemKind::Impl(unsafety, - polarity, - folder.fold_generics(generics), - ifce, - folder.fold_ty(ty), - new_impl_items) - } - ItemKind::Trait(unsafety, generics, bounds, items) => { - let bounds = folder.fold_bounds(bounds); - let items = items.move_flat_map(|item| { - folder.fold_trait_item(item) - }); - ItemKind::Trait(unsafety, - folder.fold_generics(generics), - bounds, - items) - } + ItemKind::Impl(unsafety, polarity, generics, ifce, ty, impl_items) => ItemKind::Impl( + unsafety, + polarity, + folder.fold_generics(generics), + ifce.map(|trait_ref| folder.fold_trait_ref(trait_ref.clone())), + folder.fold_ty(ty), + impl_items.move_flat_map(|item| folder.fold_impl_item(item)), + ), + ItemKind::Trait(unsafety, generics, bounds, items) => ItemKind::Trait( + unsafety, + folder.fold_generics(generics), + folder.fold_bounds(bounds), + items.move_flat_map(|item| folder.fold_trait_item(item)), + ), ItemKind::Mac(m) => ItemKind::Mac(folder.fold_mac(m)), } } @@ -954,9 +935,9 @@ pub fn noop_fold_impl_item(i: ImplItem, folder: &mut T) -> SmallVector { SmallVector::one(ImplItem { id: folder.new_id(i.id), + vis: folder.fold_vis(i.vis), ident: folder.fold_ident(i.ident), attrs: fold_attrs(i.attrs, folder), - vis: folder.fold_vis(i.vis), defaultness: i.defaultness, node: match i.node { ast::ImplItemKind::Const(ty, expr) => { @@ -1031,15 +1012,12 @@ pub fn noop_fold_item(i: P, folder: &mut T) -> SmallVector(Item {id, ident, attrs, node, vis, span}: Item, folder: &mut T) -> Item { - let id = folder.new_id(id); - let node = folder.fold_item_kind(node); - Item { - id: id, + id: folder.new_id(id), + vis: folder.fold_vis(vis), ident: folder.fold_ident(ident), attrs: fold_attrs(attrs, folder), - node: node, - vis: folder.fold_vis(vis), + node: folder.fold_item_kind(node), span: folder.new_span(span) } } @@ -1047,6 +1025,7 @@ pub fn noop_fold_item_simple(Item {id, ident, attrs, node, vis, span} pub fn noop_fold_foreign_item(ni: ForeignItem, folder: &mut T) -> ForeignItem { ForeignItem { id: folder.new_id(ni.id), + vis: folder.fold_vis(ni.vis), ident: folder.fold_ident(ni.ident), attrs: fold_attrs(ni.attrs, folder), node: match ni.node { @@ -1057,7 +1036,6 @@ pub fn noop_fold_foreign_item(ni: ForeignItem, folder: &mut T) -> For ForeignItemKind::Static(folder.fold_ty(t), m) } }, - vis: folder.fold_vis(ni.vis), span: folder.new_span(ni.span) } } diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index efd9b027504f..57b06c40878f 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -532,8 +532,8 @@ pub fn walk_fn_kind(visitor: &mut V, function_kind: FnKind) { pub fn walk_fn(visitor: &mut V, kind: FnKind, declaration: &FnDecl, body: &Block, _span: Span) where V: Visitor, { - walk_fn_decl(visitor, declaration); walk_fn_kind(visitor, kind); + walk_fn_decl(visitor, declaration); visitor.visit_block(body) } @@ -652,13 +652,13 @@ pub fn walk_expr(visitor: &mut V, expression: &Expr) { walk_list!(visitor, visit_expr, subexpressions); } ExprKind::Call(ref callee_expression, ref arguments) => { + visitor.visit_expr(callee_expression); walk_list!(visitor, visit_expr, arguments); - visitor.visit_expr(callee_expression) } ExprKind::MethodCall(ref ident, ref types, ref arguments) => { visitor.visit_ident(ident.span, ident.node); - walk_list!(visitor, visit_expr, arguments); walk_list!(visitor, visit_ty, types); + walk_list!(visitor, visit_expr, arguments); } ExprKind::Binary(_, ref left_expression, ref right_expression) => { visitor.visit_expr(left_expression); @@ -717,12 +717,12 @@ pub fn walk_expr(visitor: &mut V, expression: &Expr) { } ExprKind::Block(ref block) => visitor.visit_block(block), ExprKind::Assign(ref left_hand_expression, ref right_hand_expression) => { + visitor.visit_expr(left_hand_expression); visitor.visit_expr(right_hand_expression); - visitor.visit_expr(left_hand_expression) } ExprKind::AssignOp(_, ref left_expression, ref right_expression) => { + visitor.visit_expr(left_expression); visitor.visit_expr(right_expression); - visitor.visit_expr(left_expression) } ExprKind::Field(ref subexpression, ref ident) => { visitor.visit_expr(subexpression); From c7e4ae0d8d22847259e2e08a851f80e375221707 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Sat, 17 Sep 2016 23:31:32 +0000 Subject: [PATCH 393/443] Add regression test. --- src/test/run-pass/type-macros-simple.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/test/run-pass/type-macros-simple.rs b/src/test/run-pass/type-macros-simple.rs index 7d1045cf3f1a..6b0deff3ba4f 100644 --- a/src/test/run-pass/type-macros-simple.rs +++ b/src/test/run-pass/type-macros-simple.rs @@ -15,3 +15,22 @@ macro_rules! Tuple { fn main() { let x: Tuple!(i32, i32) = (1, 2); } + +fn issue_36540() { + let i32 = 0; + macro_rules! m { () => { i32 } } + struct S(m!(), T) where T: Trait; + + let x: m!() = m!(); + std::cell::Cell::::new(m!()); + impl std::ops::Index for Trait<(m!(), T)> + where T: Trait + { + type Output = m!(); + fn index(&self, i: m!()) -> &m!() { + unimplemented!() + } + } +} + +trait Trait {} From 5505ebc31d1d2e0bddbed815ad0c899c0d42585e Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sat, 10 Sep 2016 17:09:02 -0400 Subject: [PATCH 394/443] Add basic doc examples for `std::panic::{set_hook, take_hook}`. --- src/libstd/panicking.rs | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs index 0c10dcbdad64..1f5b3437b615 100644 --- a/src/libstd/panicking.rs +++ b/src/libstd/panicking.rs @@ -84,6 +84,20 @@ static mut HOOK: Hook = Hook::Default; /// # Panics /// /// Panics if called from a panicking thread. +/// +/// # Examples +/// +/// The following will print "Custom panic hook": +/// +/// ```should_panic +/// use std::panic; +/// +/// panic::set_hook(Box::new(|_| { +/// println!("Custom panic hook"); +/// })); +/// +/// panic!("Normal panic"); +/// ``` #[stable(feature = "panic_hooks", since = "1.10.0")] pub fn set_hook(hook: Box) { if thread::panicking() { @@ -109,6 +123,22 @@ pub fn set_hook(hook: Box) { /// # Panics /// /// Panics if called from a panicking thread. +/// +/// # Examples +/// +/// The following will print "Normal panic": +/// +/// ```should_panic +/// use std::panic; +/// +/// panic::set_hook(Box::new(|_| { +/// println!("Custom panic hook"); +/// })); +/// +/// let _ = panic::take_hook(); +/// +/// panic!("Normal panic"); +/// ``` #[stable(feature = "panic_hooks", since = "1.10.0")] pub fn take_hook() -> Box { if thread::panicking() { From 48e69e029b420aea09009ef1734bdfc5226a01de Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Mon, 19 Sep 2016 07:17:49 +1200 Subject: [PATCH 395/443] save-analysis: better 'parent' info In particular, this fixes some bugs displaying doc URLs for method calls. --- src/librustc_save_analysis/data.rs | 11 ++-- src/librustc_save_analysis/dump_visitor.rs | 72 ++++++++++++++------- src/librustc_save_analysis/external_data.rs | 14 ++-- src/librustc_save_analysis/lib.rs | 15 +++-- 4 files changed, 69 insertions(+), 43 deletions(-) diff --git a/src/librustc_save_analysis/data.rs b/src/librustc_save_analysis/data.rs index 5f6e65e289fd..4e03ea4218f0 100644 --- a/src/librustc_save_analysis/data.rs +++ b/src/librustc_save_analysis/data.rs @@ -167,7 +167,7 @@ pub struct FunctionData { pub scope: NodeId, pub value: String, pub visibility: Visibility, - pub parent: Option, + pub parent: Option, pub docs: String, } @@ -250,6 +250,7 @@ pub struct MethodData { pub scope: NodeId, pub value: String, pub decl_id: Option, + pub parent: Option, pub visibility: Visibility, pub docs: String, } @@ -300,7 +301,7 @@ pub struct StructVariantData { pub type_value: String, pub value: String, pub scope: NodeId, - pub parent: Option, + pub parent: Option, pub docs: String, } @@ -326,7 +327,7 @@ pub struct TupleVariantData { pub type_value: String, pub value: String, pub scope: NodeId, - pub parent: Option, + pub parent: Option, pub docs: String, } @@ -339,7 +340,7 @@ pub struct TypeDefData { pub qualname: String, pub value: String, pub visibility: Visibility, - pub parent: Option, + pub parent: Option, pub docs: String, } @@ -380,7 +381,7 @@ pub struct VariableData { pub qualname: String, pub span: Span, pub scope: NodeId, - pub parent: Option, + pub parent: Option, pub value: String, pub type_value: String, pub visibility: Visibility, diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index f31e12991c80..8820f3616d50 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -27,9 +27,10 @@ //! is used for recording the output in a format-agnostic way (see CsvDumper //! for an example). +use rustc::hir; use rustc::hir::def::Def; use rustc::hir::def_id::DefId; -use rustc::hir::map::Node; +use rustc::hir::map::{Node, NodeItem}; use rustc::session::Session; use rustc::ty::{self, TyCtxt, ImplOrTraitItem, ImplOrTraitItemContainer}; @@ -47,7 +48,7 @@ use syntax_pos::*; use super::{escape, generated_code, SaveContext, PathCollector, docs_for_attrs}; use super::data::*; use super::dump::Dump; -use super::external_data::Lower; +use super::external_data::{Lower, make_def_id}; use super::span_utils::SpanUtils; use super::recorder; @@ -271,11 +272,13 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { // looks up anything, not just a type fn lookup_type_ref(&self, ref_id: NodeId) -> Option { - match self.tcx.expect_def(ref_id) { - Def::PrimTy(..) => None, - Def::SelfTy(..) => None, - def => Some(def.def_id()), - } + self.tcx.expect_def_or_none(ref_id).and_then(|def| { + match def { + Def::PrimTy(..) => None, + Def::SelfTy(..) => None, + def => Some(def.def_id()), + } + }) } fn process_def_kind(&mut self, @@ -399,20 +402,36 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { if !self.span.filter_generated(Some(method_data.span), span) { let container = self.tcx.impl_or_trait_item(self.tcx.map.local_def_id(id)).container(); - let decl_id = if let ImplOrTraitItemContainer::ImplContainer(id) = container { - self.tcx.trait_id_of_impl(id).and_then(|id| { - for item in &**self.tcx.trait_items(id) { - if let &ImplOrTraitItem::MethodTraitItem(ref m) = item { - if m.name == name { - return Some(m.def_id); + let mut trait_id; + let mut decl_id = None; + match container { + ImplOrTraitItemContainer::ImplContainer(id) => { + trait_id = self.tcx.trait_id_of_impl(id); + + match trait_id { + Some(id) => { + for item in &**self.tcx.trait_items(id) { + if let &ImplOrTraitItem::MethodTraitItem(ref m) = item { + if m.name == name { + decl_id = Some(m.def_id); + break; + } + } + } + } + None => { + if let Some(NodeItem(item)) = self.tcx.map.get_if_local(id) { + if let hir::ItemImpl(_, _, _, _, ref ty, _) = item.node { + trait_id = self.lookup_type_ref(ty.id); + } } } } - None - }) - } else { - None - }; + } + ImplOrTraitItemContainer::TraitContainer(id) => { + trait_id = Some(id); + } + } self.dumper.method(MethodData { id: method_data.id, @@ -422,6 +441,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { qualname: method_data.qualname.clone(), value: sig_str, decl_id: decl_id, + parent: trait_id, visibility: vis, docs: docs_for_attrs(attrs), }.lower(self.tcx)); @@ -544,7 +564,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { span: Span, typ: &ast::Ty, expr: &ast::Expr, - parent_id: NodeId, + parent_id: DefId, vis: Visibility, attrs: &[Attribute]) { let qualname = format!("::{}", self.tcx.node_path_str(id)); @@ -659,7 +679,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { type_value: enum_data.qualname.clone(), value: val, scope: enum_data.scope, - parent: Some(item.id), + parent: Some(make_def_id(item.id, &self.tcx.map)), docs: docs_for_attrs(&variant.node.attrs), }.lower(self.tcx)); } @@ -684,7 +704,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { type_value: enum_data.qualname.clone(), value: val, scope: enum_data.scope, - parent: Some(item.id), + parent: Some(make_def_id(item.id, &self.tcx.map)), docs: docs_for_attrs(&variant.node.attrs), }.lower(self.tcx)); } @@ -738,7 +758,8 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { } self.process_generic_params(type_parameters, item.span, "", item.id); for impl_item in impl_items { - self.process_impl_item(impl_item, item.id); + let map = &self.tcx.map; + self.process_impl_item(impl_item, make_def_id(item.id, map)); } } @@ -809,7 +830,8 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { // walk generics and methods self.process_generic_params(generics, item.span, &qualname, item.id); for method in methods { - self.process_trait_item(method, item.id) + let map = &self.tcx.map; + self.process_trait_item(method, make_def_id(item.id, map)) } } @@ -1076,7 +1098,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { } } - fn process_trait_item(&mut self, trait_item: &ast::TraitItem, trait_id: NodeId) { + fn process_trait_item(&mut self, trait_item: &ast::TraitItem, trait_id: DefId) { self.process_macro_use(trait_item.span, trait_item.id); match trait_item.node { ast::TraitItemKind::Const(ref ty, Some(ref expr)) => { @@ -1104,7 +1126,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { } } - fn process_impl_item(&mut self, impl_item: &ast::ImplItem, impl_id: NodeId) { + fn process_impl_item(&mut self, impl_item: &ast::ImplItem, impl_id: DefId) { self.process_macro_use(impl_item.span, impl_item.id); match impl_item.node { ast::ImplItemKind::Const(ref ty, ref expr) => { diff --git a/src/librustc_save_analysis/external_data.rs b/src/librustc_save_analysis/external_data.rs index 3642346582bb..32280a5c9262 100644 --- a/src/librustc_save_analysis/external_data.rs +++ b/src/librustc_save_analysis/external_data.rs @@ -23,7 +23,7 @@ pub trait Lower { fn lower(self, tcx: TyCtxt) -> Self::Target; } -fn make_def_id(id: NodeId, map: &Map) -> DefId { +pub fn make_def_id(id: NodeId, map: &Map) -> DefId { map.opt_local_def_id(id).unwrap_or(null_def_id()) } @@ -188,7 +188,7 @@ impl Lower for data::FunctionData { scope: make_def_id(self.scope, &tcx.map), value: self.value, visibility: self.visibility, - parent: self.parent.map(|id| make_def_id(id, &tcx.map)), + parent: self.parent, docs: self.docs, } } @@ -353,7 +353,7 @@ impl Lower for data::MethodData { value: self.value, decl_id: self.decl_id, visibility: self.visibility, - parent: Some(make_def_id(self.scope, &tcx.map)), + parent: self.parent, docs: self.docs, } } @@ -471,7 +471,7 @@ impl Lower for data::StructVariantData { type_value: self.type_value, value: self.value, scope: make_def_id(self.scope, &tcx.map), - parent: self.parent.map(|id| make_def_id(id, &tcx.map)), + parent: self.parent, docs: self.docs, } } @@ -533,7 +533,7 @@ impl Lower for data::TupleVariantData { type_value: self.type_value, value: self.value, scope: make_def_id(self.scope, &tcx.map), - parent: self.parent.map(|id| make_def_id(id, &tcx.map)), + parent: self.parent, docs: self.docs, } } @@ -563,7 +563,7 @@ impl Lower for data::TypeDefData { qualname: self.qualname, value: self.value, visibility: self.visibility, - parent: self.parent.map(|id| make_def_id(id, &tcx.map)), + parent: self.parent, docs: self.docs, } } @@ -668,7 +668,7 @@ impl Lower for data::VariableData { scope: make_def_id(self.scope, &tcx.map), value: self.value, type_value: self.type_value, - parent: self.parent.map(|id| make_def_id(id, &tcx.map)), + parent: self.parent, visibility: self.visibility, docs: self.docs, } diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 35ad2d9316cd..51274068b26c 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -64,6 +64,7 @@ pub use self::csv_dumper::CsvDumper; pub use self::json_api_dumper::JsonApiDumper; pub use self::json_dumper::JsonDumper; pub use self::data::*; +pub use self::external_data::make_def_id; pub use self::dump::Dump; pub use self::dump_visitor::DumpVisitor; use self::span_utils::SpanUtils; @@ -295,7 +296,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { qualname: qualname, span: sub_span.unwrap(), scope: scope, - parent: Some(scope), + parent: Some(make_def_id(scope, &self.tcx.map)), value: "".to_owned(), type_value: typ, visibility: From::from(&field.vis), @@ -312,7 +313,8 @@ 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, vis, docs) = match self.tcx.impl_of_method(self.tcx.map.local_def_id(id)) { + let (qualname, parent_scope, vis, docs) = + match self.tcx.impl_of_method(self.tcx.map.local_def_id(id)) { Some(impl_id) => match self.tcx.map.get_if_local(impl_id) { Some(NodeItem(item)) => { match item.node { @@ -320,12 +322,13 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { let mut result = String::from("<"); result.push_str(&rustc::hir::print::ty_to_string(&ty)); - if let Some(def_id) = self.tcx.trait_id_of_impl(impl_id) { + let trait_id = self.tcx.trait_id_of_impl(impl_id); + if let Some(def_id) = trait_id { result.push_str(" as "); result.push_str(&self.tcx.item_path_str(def_id)); } result.push_str(">"); - (result, From::from(&item.vis), docs_for_attrs(&item.attrs)) + (result, trait_id, From::from(&item.vis), docs_for_attrs(&item.attrs)) } _ => { span_bug!(span, @@ -348,6 +351,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { match self.tcx.map.get_if_local(def_id) { Some(NodeItem(item)) => { (format!("::{}", self.tcx.item_path_str(def_id)), + Some(def_id), From::from(&item.vis), docs_for_attrs(&item.attrs)) } @@ -381,7 +385,6 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { let sub_span = self.span_utils.sub_span_after_keyword(span, keywords::Fn); filter!(self.span_utils, sub_span, span, None); - let parent_scope = self.enclosing_scope(id); Some(FunctionData { id: id, name: name.to_string(), @@ -392,7 +395,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { // FIXME you get better data here by using the visitor. value: String::new(), visibility: vis, - parent: Some(parent_scope), + parent: parent_scope, docs: docs, }) } From 2e6a91812c64a507e3d2ab727824ff9cda8449fc Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Thu, 15 Sep 2016 18:17:58 -0700 Subject: [PATCH 396/443] librustc: Add a new nop statement to the MIR. This is useful when passes want to remove statements without affecting `Location`s. --- src/librustc/mir/repr.rs | 20 +++++++++++++++++++ src/librustc/mir/visit.rs | 1 + .../borrowck/mir/dataflow/impls.rs | 3 ++- .../borrowck/mir/dataflow/sanity_check.rs | 3 ++- src/librustc_borrowck/borrowck/mir/mod.rs | 3 ++- src/librustc_mir/transform/qualify_consts.rs | 3 ++- src/librustc_mir/transform/type_check.rs | 1 + src/librustc_trans/mir/constant.rs | 3 ++- src/librustc_trans/mir/statement.rs | 1 + 9 files changed, 33 insertions(+), 5 deletions(-) diff --git a/src/librustc/mir/repr.rs b/src/librustc/mir/repr.rs index 53b6ccdbd530..3ab8ed5bce29 100644 --- a/src/librustc/mir/repr.rs +++ b/src/librustc/mir/repr.rs @@ -187,6 +187,14 @@ impl<'tcx> Mir<'tcx> { self.var_decls.len() + self.temp_decls.len() + 1 } + + /// Changes a statement to a nop. This is both faster than deleting instructions and avoids + /// invalidating statement indices in `Location`s. + pub fn make_statement_nop(&mut self, location: Location) { + let block = &mut self[location.block]; + debug_assert!(location.statement_index < block.statements.len()); + block.statements[location.statement_index].make_nop() + } } impl<'tcx> Index for Mir<'tcx> { @@ -686,6 +694,14 @@ pub struct Statement<'tcx> { pub kind: StatementKind<'tcx>, } +impl<'tcx> Statement<'tcx> { + /// Changes a statement to a nop. This is both faster than deleting instructions and avoids + /// invalidating statement indices in `Location`s. + pub fn make_nop(&mut self) { + self.kind = StatementKind::Nop + } +} + #[derive(Clone, Debug, RustcEncodable, RustcDecodable)] pub enum StatementKind<'tcx> { /// Write the RHS Rvalue to the LHS Lvalue. @@ -699,6 +715,9 @@ pub enum StatementKind<'tcx> { /// End the current live range for the storage of the local. StorageDead(Lvalue<'tcx>), + + /// No-op. Useful for deleting instructions without affecting statement indices. + Nop, } impl<'tcx> Debug for Statement<'tcx> { @@ -711,6 +730,7 @@ impl<'tcx> Debug for Statement<'tcx> { SetDiscriminant{lvalue: ref lv, variant_index: index} => { write!(fmt, "discriminant({:?}) = {:?}", lv, index) } + Nop => write!(fmt, "nop"), } } } diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index 16e0b376f4b5..072faf795220 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -346,6 +346,7 @@ macro_rules! make_mir_visitor { StatementKind::StorageDead(ref $($mutability)* lvalue) => { self.visit_lvalue(lvalue, LvalueContext::StorageDead, location); } + StatementKind::Nop => {} } } diff --git a/src/librustc_borrowck/borrowck/mir/dataflow/impls.rs b/src/librustc_borrowck/borrowck/mir/dataflow/impls.rs index 8ac59c60396f..55dda8eda3a4 100644 --- a/src/librustc_borrowck/borrowck/mir/dataflow/impls.rs +++ b/src/librustc_borrowck/borrowck/mir/dataflow/impls.rs @@ -455,7 +455,8 @@ impl<'a, 'tcx> BitDenotation for MovingOutStatements<'a, 'tcx> { }); } repr::StatementKind::StorageLive(_) | - repr::StatementKind::StorageDead(_) => {} + repr::StatementKind::StorageDead(_) | + repr::StatementKind::Nop => {} } } diff --git a/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs b/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs index 88f6d5fef562..aeb91f06a9aa 100644 --- a/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs +++ b/src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs @@ -105,7 +105,8 @@ fn each_block<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>, (lvalue, rvalue) } repr::StatementKind::StorageLive(_) | - repr::StatementKind::StorageDead(_) => continue, + repr::StatementKind::StorageDead(_) | + repr::StatementKind::Nop => continue, repr::StatementKind::SetDiscriminant{ .. } => span_bug!(stmt.source_info.span, "sanity_check should run before Deaggregator inserts SetDiscriminant"), diff --git a/src/librustc_borrowck/borrowck/mir/mod.rs b/src/librustc_borrowck/borrowck/mir/mod.rs index 5b5d782bc83a..f26afdc2b857 100644 --- a/src/librustc_borrowck/borrowck/mir/mod.rs +++ b/src/librustc_borrowck/borrowck/mir/mod.rs @@ -389,7 +389,8 @@ fn drop_flag_effects_for_location<'a, 'tcx, F>( |moi| callback(moi, DropFlagState::Present)) } repr::StatementKind::StorageLive(_) | - repr::StatementKind::StorageDead(_) => {} + repr::StatementKind::StorageDead(_) | + repr::StatementKind::Nop => {} }, None => { debug!("drop_flag_effects: replace {:?}", block.terminator()); diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index a3f8f7a63eea..9f162aabe0c2 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -910,7 +910,8 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { } StatementKind::SetDiscriminant { .. } | StatementKind::StorageLive(_) | - StatementKind::StorageDead(_) => {} + StatementKind::StorageDead(_) | + StatementKind::Nop => {} } }); } diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs index 7fda658185e0..412759cd5b2d 100644 --- a/src/librustc_mir/transform/type_check.rs +++ b/src/librustc_mir/transform/type_check.rs @@ -385,6 +385,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { } } } + StatementKind::Nop => {} } } diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index e9f324c0b08f..70d0a6184047 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -292,7 +292,8 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { } } mir::StatementKind::StorageLive(_) | - mir::StatementKind::StorageDead(_) => {} + mir::StatementKind::StorageDead(_) | + mir::StatementKind::Nop => {} mir::StatementKind::SetDiscriminant{ .. } => { span_bug!(span, "SetDiscriminant should not appear in constants?"); } diff --git a/src/librustc_trans/mir/statement.rs b/src/librustc_trans/mir/statement.rs index 116720895536..325bd655266c 100644 --- a/src/librustc_trans/mir/statement.rs +++ b/src/librustc_trans/mir/statement.rs @@ -78,6 +78,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { mir::StatementKind::StorageDead(ref lvalue) => { self.trans_storage_liveness(bcx, lvalue, base::Lifetime::End) } + mir::StatementKind::Nop => bcx, } } From 2ea3ab3a9022a93e45c4d50a1c43aec5f56ab4dc Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Mon, 19 Sep 2016 12:31:56 -0700 Subject: [PATCH 397/443] Add the ability to merge spans to codemap --- src/librustc_errors/lib.rs | 1 + src/libsyntax/codemap.rs | 82 ++++++++++++++++++++++++++++++++++++++ src/libsyntax_pos/lib.rs | 18 --------- 3 files changed, 83 insertions(+), 18 deletions(-) diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index d2f3eea85f22..bc599a820765 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -81,6 +81,7 @@ pub trait CodeMapper { fn span_to_string(&self, sp: Span) -> String; fn span_to_filename(&self, sp: Span) -> FileName; fn macro_backtrace(&self, span: Span) -> Vec; + fn merge_spans(&self, sp_lhs: Span, sp_rhs: Span) -> Option; } impl CodeSuggestion { diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index cd6f2874954b..ce15bd89590b 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -364,6 +364,46 @@ impl CodeMap { } } + /// Returns `Some(span)`, a union of the lhs and rhs span. The lhs must precede the rhs. If + /// there are gaps between lhs and rhs, the resulting union will cross these gaps. + /// For this to work, the spans have to be: + /// * the expn_id of both spans much match + /// * the lhs span needs to end on the same line the rhs span begins + /// * the lhs span must start at or before the rhs span + pub fn merge_spans(&self, sp_lhs: Span, sp_rhs: Span) -> Option { + use std::cmp; + + // make sure we're at the same expansion id + if sp_lhs.expn_id != sp_rhs.expn_id { + return None; + } + + let lhs_end = match self.lookup_line(sp_lhs.hi) { + Ok(x) => x, + Err(_) => return None + }; + let rhs_begin = match self.lookup_line(sp_rhs.lo) { + Ok(x) => x, + Err(_) => return None + }; + + // if we must cross lines to merge, don't merge + if lhs_end.line != rhs_begin.line { + return None; + } + + // ensure these follow the expected order + if sp_lhs.lo <= sp_rhs.lo { + Some(Span { + lo: cmp::min(sp_lhs.lo, sp_rhs.lo), + hi: cmp::max(sp_lhs.hi, sp_rhs.hi), + expn_id: sp_lhs.expn_id, + }) + } else { + None + } + } + pub fn span_to_string(&self, sp: Span) -> String { if sp == COMMAND_LINE_SP { return "".to_string(); @@ -819,6 +859,9 @@ impl CodeMapper for CodeMap { fn macro_backtrace(&self, span: Span) -> Vec { self.macro_backtrace(span) } + fn merge_spans(&self, sp_lhs: Span, sp_rhs: Span) -> Option { + self.merge_spans(sp_lhs, sp_rhs) + } } // _____________________________________________________________________________ @@ -1072,6 +1115,45 @@ mod tests { blork.rs:1:1: 1:12\n `first line.`\n"); } + /// Test merging two spans on the same line + #[test] + fn span_merging() { + let cm = CodeMap::new(); + let inputtext = "bbbb BB bb CCC\n"; + let selection1 = " ~~ \n"; + let selection2 = " ~~~\n"; + cm.new_filemap_and_lines("blork.rs", None, inputtext); + let span1 = span_from_selection(inputtext, selection1); + let span2 = span_from_selection(inputtext, selection2); + + if let Some(sp) = cm.merge_spans(span1, span2) { + let sstr = cm.span_to_expanded_string(sp); + assert_eq!(sstr, "blork.rs:1:6: 1:15\n`BB bb CCC`\n"); + } + else { + assert!(false); + } + } + + /// Test failing to merge two spans on different lines + #[test] + fn span_merging_fail() { + let cm = CodeMap::new(); + let inputtext = "bbbb BB\ncc CCC\n"; + let selection1 = " ~~\n \n"; + let selection2 = " \n ~~~\n"; + cm.new_filemap_and_lines("blork.rs", None, inputtext); + let span1 = span_from_selection(inputtext, selection1); + let span2 = span_from_selection(inputtext, selection2); + + if let Some(_) = cm.merge_spans(span1, span2) { + assert!(false); + } + else { + assert!(true); + } + } + /// Returns the span corresponding to the `n`th occurrence of /// `substring` in `source_text`. trait CodeMapExtension { diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index d835f8058fa0..0c0c62275d4d 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -96,24 +96,6 @@ impl Span { self.lo == other.lo && self.hi == other.hi } - /// Returns `Some(span)`, a union of `self` and `other`, on overlap. - pub fn merge(self, other: Span) -> Option { - if self.expn_id != other.expn_id { - return None; - } - - if (self.lo <= other.lo && self.hi > other.lo) || - (self.lo >= other.lo && self.lo < other.hi) { - Some(Span { - lo: cmp::min(self.lo, other.lo), - hi: cmp::max(self.hi, other.hi), - expn_id: self.expn_id, - }) - } else { - None - } - } - /// Returns `Some(span)`, where the start is trimmed by the end of `other` pub fn trim_start(self, other: Span) -> Option { if self.hi > other.hi { From 480287ec3b0260e26c8796506039c379bd7e0ead Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Thu, 15 Sep 2016 18:18:40 -0700 Subject: [PATCH 398/443] librustc: Implement def-use chains and trivial copy propagation on MIR. This only supports trivial cases in which there is exactly one def and one use. --- src/librustc/mir/repr.rs | 46 ++++ src/librustc/mir/visit.rs | 108 +++++++++- .../borrowck/mir/gather_moves.rs | 1 + src/librustc_driver/driver.rs | 1 + src/librustc_mir/def_use.rs | 197 ++++++++++++++++++ src/librustc_mir/lib.rs | 2 + src/librustc_mir/transform/copy_prop.rs | 180 ++++++++++++++++ src/librustc_mir/transform/mod.rs | 2 +- src/librustc_mir/transform/promote_consts.rs | 2 +- src/librustc_mir/transform/qualify_consts.rs | 5 +- src/librustc_trans/collector.rs | 2 +- src/librustc_trans/mir/analyze.rs | 4 +- src/test/codegen/refs.rs | 4 +- src/test/mir-opt/storage_ranges.rs | 38 ++-- 14 files changed, 560 insertions(+), 32 deletions(-) create mode 100644 src/librustc_mir/def_use.rs create mode 100644 src/librustc_mir/transform/copy_prop.rs diff --git a/src/librustc/mir/repr.rs b/src/librustc/mir/repr.rs index 3ab8ed5bce29..be761c95b611 100644 --- a/src/librustc/mir/repr.rs +++ b/src/librustc/mir/repr.rs @@ -188,6 +188,24 @@ impl<'tcx> Mir<'tcx> { self.temp_decls.len() + 1 } + pub fn format_local(&self, local: Local) -> String { + let mut index = local.index(); + index = match index.checked_sub(self.arg_decls.len()) { + None => return format!("{:?}", Arg::new(index)), + Some(index) => index, + }; + index = match index.checked_sub(self.var_decls.len()) { + None => return format!("{:?}", Var::new(index)), + Some(index) => index, + }; + index = match index.checked_sub(self.temp_decls.len()) { + None => return format!("{:?}", Temp::new(index)), + Some(index) => index, + }; + debug_assert!(index == 0); + return "ReturnPointer".to_string() + } + /// Changes a statement to a nop. This is both faster than deleting instructions and avoids /// invalidating statement indices in `Location`s. pub fn make_statement_nop(&mut self, location: Location) { @@ -844,6 +862,24 @@ impl<'tcx> Lvalue<'tcx> { elem: elem, })) } + + pub fn from_local(mir: &Mir<'tcx>, local: Local) -> Lvalue<'tcx> { + let mut index = local.index(); + index = match index.checked_sub(mir.arg_decls.len()) { + None => return Lvalue::Arg(Arg(index as u32)), + Some(index) => index, + }; + index = match index.checked_sub(mir.var_decls.len()) { + None => return Lvalue::Var(Var(index as u32)), + Some(index) => index, + }; + index = match index.checked_sub(mir.temp_decls.len()) { + None => return Lvalue::Temp(Temp(index as u32)), + Some(index) => index, + }; + debug_assert!(index == 0); + Lvalue::ReturnPointer + } } impl<'tcx> Debug for Lvalue<'tcx> { @@ -1278,3 +1314,13 @@ impl fmt::Debug for Location { write!(fmt, "{:?}[{}]", self.block, self.statement_index) } } + +impl Location { + pub fn dominates(&self, other: &Location, dominators: &Dominators) -> bool { + if self.block == other.block { + self.statement_index <= other.statement_index + } else { + dominators.is_dominated_by(other.block, self.block) + } + } +} diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index 072faf795220..2c58d35973e7 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -150,7 +150,7 @@ macro_rules! make_mir_visitor { fn visit_lvalue(&mut self, lvalue: & $($mutability)* Lvalue<'tcx>, - context: LvalueContext, + context: LvalueContext<'tcx>, location: Location) { self.super_lvalue(lvalue, context, location); } @@ -581,7 +581,7 @@ macro_rules! make_mir_visitor { fn super_lvalue(&mut self, lvalue: & $($mutability)* Lvalue<'tcx>, - context: LvalueContext, + context: LvalueContext<'tcx>, location: Location) { match *lvalue { Lvalue::Var(_) | @@ -606,7 +606,12 @@ macro_rules! make_mir_visitor { ref $($mutability)* base, ref $($mutability)* elem, } = *proj; - self.visit_lvalue(base, LvalueContext::Projection, location); + let context = if context.is_mutating_use() { + LvalueContext::Projection(Mutability::Mut) + } else { + LvalueContext::Projection(Mutability::Not) + }; + self.visit_lvalue(base, context, location); self.visit_projection_elem(elem, context, location); } @@ -751,6 +756,21 @@ macro_rules! make_mir_visitor { fn super_const_usize(&mut self, _substs: & $($mutability)* ConstUsize) { } + + // Convenience methods + + fn visit_location(&mut self, mir: & $($mutability)* Mir<'tcx>, location: Location) { + let basic_block = & $($mutability)* mir[location.block]; + if basic_block.statements.len() == location.statement_index { + if let Some(ref $($mutability)* terminator) = basic_block.terminator { + self.visit_terminator(location.block, terminator, location) + } + } else { + let statement = & $($mutability)* + basic_block.statements[location.statement_index]; + self.visit_statement(location.block, statement, location) + } + } } } } @@ -775,8 +795,20 @@ pub enum LvalueContext<'tcx> { // Being borrowed Borrow { region: &'tcx Region, kind: BorrowKind }, - // Used as base for another lvalue, e.g. `x` in `x.y` - Projection, + // Used as base for another lvalue, e.g. `x` in `x.y`. + // + // The `Mutability` argument specifies whether the projection is being performed in order to + // (potentially) mutate the lvalue. For example, the projection `x.y` is marked as a mutation + // in these cases: + // + // x.y = ...; + // f(&mut x.y); + // + // But not in these cases: + // + // z = x.y; + // f(&x.y); + Projection(Mutability), // Consumed as part of an operand Consume, @@ -785,3 +817,69 @@ pub enum LvalueContext<'tcx> { StorageLive, StorageDead, } + +impl<'tcx> LvalueContext<'tcx> { + /// Returns true if this lvalue context represents a drop. + pub fn is_drop(&self) -> bool { + match *self { + LvalueContext::Drop => true, + _ => false, + } + } + + /// Returns true if this lvalue context represents a storage live or storage dead marker. + pub fn is_storage_marker(&self) -> bool { + match *self { + LvalueContext::StorageLive | LvalueContext::StorageDead => true, + _ => false, + } + } + + /// Returns true if this lvalue context represents a storage live marker. + pub fn is_storage_live_marker(&self) -> bool { + match *self { + LvalueContext::StorageLive => true, + _ => false, + } + } + + /// Returns true if this lvalue context represents a storage dead marker. + pub fn is_storage_dead_marker(&self) -> bool { + match *self { + LvalueContext::StorageDead => true, + _ => false, + } + } + + /// Returns true if this lvalue context represents a use that potentially changes the value. + pub fn is_mutating_use(&self) -> bool { + match *self { + LvalueContext::Store | LvalueContext::Call | + LvalueContext::Borrow { kind: BorrowKind::Mut, .. } | + LvalueContext::Projection(Mutability::Mut) | + LvalueContext::Drop => true, + LvalueContext::Inspect | + LvalueContext::Borrow { kind: BorrowKind::Shared, .. } | + LvalueContext::Borrow { kind: BorrowKind::Unique, .. } | + LvalueContext::Projection(Mutability::Not) | LvalueContext::Consume | + LvalueContext::StorageLive | LvalueContext::StorageDead => false, + } + } + + /// Returns true if this lvalue context represents a use that does not change the value. + pub fn is_nonmutating_use(&self) -> bool { + match *self { + LvalueContext::Inspect | LvalueContext::Borrow { kind: BorrowKind::Shared, .. } | + LvalueContext::Borrow { kind: BorrowKind::Unique, .. } | + LvalueContext::Projection(Mutability::Not) | LvalueContext::Consume => true, + LvalueContext::Borrow { kind: BorrowKind::Mut, .. } | LvalueContext::Store | + LvalueContext::Call | LvalueContext::Projection(Mutability::Mut) | + LvalueContext::Drop | LvalueContext::StorageLive | LvalueContext::StorageDead => false, + } + } + + pub fn is_use(&self) -> bool { + self.is_mutating_use() || self.is_nonmutating_use() + } +} + diff --git a/src/librustc_borrowck/borrowck/mir/gather_moves.rs b/src/librustc_borrowck/borrowck/mir/gather_moves.rs index bd38f554dc9b..6346c1e58897 100644 --- a/src/librustc_borrowck/borrowck/mir/gather_moves.rs +++ b/src/librustc_borrowck/borrowck/mir/gather_moves.rs @@ -438,6 +438,7 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> { span_bug!(stmt.source_info.span, "SetDiscriminant should not exist during borrowck"); } + StatementKind::Nop => {} } } diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index c02c5f18b4c6..55892801247b 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -1028,6 +1028,7 @@ pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // No lifetime analysis based on borrowing can be done from here on out. 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); passes.push_pass(box mir::transform::add_call_guards::AddCallGuards); passes.push_pass(box mir::transform::dump_mir::Marker("PreTrans")); diff --git a/src/librustc_mir/def_use.rs b/src/librustc_mir/def_use.rs new file mode 100644 index 000000000000..7329a20c4970 --- /dev/null +++ b/src/librustc_mir/def_use.rs @@ -0,0 +1,197 @@ +// 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. + +//! Def-use analysis. + +use rustc::mir::repr::{Local, Location, Lvalue, Mir}; +use rustc::mir::visit::{LvalueContext, MutVisitor, Visitor}; +use rustc_data_structures::indexed_vec::{Idx, IndexVec}; +use std::marker::PhantomData; +use std::mem; + +pub struct DefUseAnalysis<'tcx> { + info: IndexVec>, + mir_summary: MirSummary, +} + +#[derive(Clone)] +pub struct Info<'tcx> { + pub defs_and_uses: Vec>, +} + +#[derive(Clone)] +pub struct Use<'tcx> { + pub context: LvalueContext<'tcx>, + pub location: Location, +} + +impl<'tcx> DefUseAnalysis<'tcx> { + pub fn new(mir: &Mir<'tcx>) -> DefUseAnalysis<'tcx> { + DefUseAnalysis { + info: IndexVec::from_elem_n(Info::new(), mir.count_locals()), + mir_summary: MirSummary::new(mir), + } + } + + pub fn analyze(&mut self, mir: &Mir<'tcx>) { + let mut finder = DefUseFinder { + info: mem::replace(&mut self.info, IndexVec::new()), + mir_summary: self.mir_summary, + }; + finder.visit_mir(mir); + self.info = finder.info + } + + pub fn local_info(&self, local: Local) -> &Info<'tcx> { + &self.info[local] + } + + pub fn local_info_mut(&mut self, local: Local) -> &mut Info<'tcx> { + &mut self.info[local] + } + + fn mutate_defs_and_uses(&self, local: Local, mir: &mut Mir<'tcx>, mut callback: F) + where F: for<'a> FnMut(&'a mut Lvalue<'tcx>, + LvalueContext<'tcx>, + Location) { + for lvalue_use in &self.info[local].defs_and_uses { + MutateUseVisitor::new(local, + &mut callback, + self.mir_summary, + mir).visit_location(mir, lvalue_use.location) + } + } + + /// FIXME(pcwalton): This should update the def-use chains. + pub fn replace_all_defs_and_uses_with(&self, + local: Local, + mir: &mut Mir<'tcx>, + new_lvalue: Lvalue<'tcx>) { + self.mutate_defs_and_uses(local, mir, |lvalue, _, _| *lvalue = new_lvalue.clone()) + } +} + +struct DefUseFinder<'tcx> { + info: IndexVec>, + mir_summary: MirSummary, +} + +impl<'tcx> DefUseFinder<'tcx> { + fn lvalue_mut_info(&mut self, lvalue: &Lvalue<'tcx>) -> Option<&mut Info<'tcx>> { + let info = &mut self.info; + self.mir_summary.local_index(lvalue).map(move |local| &mut info[local]) + } +} + +impl<'tcx> Visitor<'tcx> for DefUseFinder<'tcx> { + fn visit_lvalue(&mut self, + lvalue: &Lvalue<'tcx>, + context: LvalueContext<'tcx>, + location: Location) { + if let Some(ref mut info) = self.lvalue_mut_info(lvalue) { + info.defs_and_uses.push(Use { + context: context, + location: location, + }) + } + self.super_lvalue(lvalue, context, location) + } +} + +impl<'tcx> Info<'tcx> { + fn new() -> Info<'tcx> { + Info { + defs_and_uses: vec![], + } + } + + pub fn def_count(&self) -> usize { + self.defs_and_uses.iter().filter(|lvalue_use| lvalue_use.context.is_mutating_use()).count() + } + + pub fn def_count_not_including_drop(&self) -> usize { + self.defs_and_uses.iter().filter(|lvalue_use| { + lvalue_use.context.is_mutating_use() && !lvalue_use.context.is_drop() + }).count() + } + + pub fn use_count(&self) -> usize { + self.defs_and_uses.iter().filter(|lvalue_use| { + lvalue_use.context.is_nonmutating_use() + }).count() + } +} + +struct MutateUseVisitor<'tcx, F> { + query: Local, + callback: F, + mir_summary: MirSummary, + phantom: PhantomData<&'tcx ()>, +} + +impl<'tcx, F> MutateUseVisitor<'tcx, F> { + fn new(query: Local, callback: F, mir_summary: MirSummary, _: &Mir<'tcx>) + -> MutateUseVisitor<'tcx, F> + where F: for<'a> FnMut(&'a mut Lvalue<'tcx>, LvalueContext<'tcx>, Location) { + MutateUseVisitor { + query: query, + callback: callback, + mir_summary: mir_summary, + phantom: PhantomData, + } + } +} + +impl<'tcx, F> MutVisitor<'tcx> for MutateUseVisitor<'tcx, F> + where F: for<'a> FnMut(&'a mut Lvalue<'tcx>, LvalueContext<'tcx>, Location) { + fn visit_lvalue(&mut self, + lvalue: &mut Lvalue<'tcx>, + context: LvalueContext<'tcx>, + location: Location) { + if self.mir_summary.local_index(lvalue) == Some(self.query) { + (self.callback)(lvalue, context, location) + } + self.super_lvalue(lvalue, context, location) + } +} + +/// A small structure that enables various metadata of the MIR to be queried +/// without a reference to the MIR itself. +#[derive(Clone, Copy)] +struct MirSummary { + arg_count: usize, + var_count: usize, + temp_count: usize, +} + +impl MirSummary { + fn new(mir: &Mir) -> MirSummary { + MirSummary { + arg_count: mir.arg_decls.len(), + var_count: mir.var_decls.len(), + temp_count: mir.temp_decls.len(), + } + } + + fn local_index<'tcx>(&self, lvalue: &Lvalue<'tcx>) -> Option { + match *lvalue { + Lvalue::Arg(arg) => Some(Local::new(arg.index())), + Lvalue::Var(var) => Some(Local::new(var.index() + self.arg_count)), + Lvalue::Temp(temp) => { + Some(Local::new(temp.index() + self.arg_count + self.var_count)) + } + Lvalue::ReturnPointer => { + Some(Local::new(self.arg_count + self.var_count + self.temp_count)) + } + _ => None, + } + } +} + diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index f580ceeee5d7..12f1eb8535a3 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -46,8 +46,10 @@ extern crate rustc_const_eval; pub mod diagnostics; pub mod build; +pub mod def_use; pub mod graphviz; mod hair; pub mod mir_map; pub mod pretty; pub mod transform; + diff --git a/src/librustc_mir/transform/copy_prop.rs b/src/librustc_mir/transform/copy_prop.rs new file mode 100644 index 000000000000..33f3d6d8842e --- /dev/null +++ b/src/librustc_mir/transform/copy_prop.rs @@ -0,0 +1,180 @@ +// 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. + +//! Trivial copy propagation pass. +//! +//! This uses def-use analysis to remove values that have exactly one def and one use, which must +//! be an assignment. +//! +//! To give an example, we look for patterns that look like: +//! +//! DEST = SRC +//! ... +//! USE(DEST) +//! +//! where `DEST` and `SRC` are both locals of some form. We replace that with: +//! +//! NOP +//! ... +//! USE(SRC) +//! +//! The assignment `DEST = SRC` must be (a) the only mutation of `DEST` and (b) the only +//! (non-mutating) use of `SRC`. These restrictions are conservative and may be relaxed in the +//! future. + +use def_use::DefUseAnalysis; +use rustc::mir::repr::{Local, Lvalue, Mir, Operand, Rvalue, StatementKind}; +use rustc::mir::transform::{MirPass, MirSource, Pass}; +use rustc::ty::TyCtxt; +use rustc_data_structures::indexed_vec::Idx; + +pub struct CopyPropagation; + +impl Pass for CopyPropagation {} + +impl<'tcx> MirPass<'tcx> for CopyPropagation { + fn run_pass<'a>(&mut self, _: TyCtxt<'a, 'tcx, 'tcx>, _: MirSource, mir: &mut Mir<'tcx>) { + loop { + let mut def_use_analysis = DefUseAnalysis::new(mir); + def_use_analysis.analyze(mir); + + let mut changed = false; + for dest_local_index in 0..mir.count_locals() { + let dest_local = Local::new(dest_local_index); + debug!("Considering destination local: {}", mir.format_local(dest_local)); + + let src_local; + let location; + { + // The destination must have exactly one def. + let dest_use_info = def_use_analysis.local_info(dest_local); + let dest_def_count = dest_use_info.def_count_not_including_drop(); + if dest_def_count == 0 { + debug!(" Can't copy-propagate local: dest {} undefined", + mir.format_local(dest_local)); + continue + } + if dest_def_count > 1 { + debug!(" Can't copy-propagate local: dest {} defined {} times", + mir.format_local(dest_local), + dest_use_info.def_count()); + continue + } + if dest_use_info.use_count() == 0 { + debug!(" Can't copy-propagate local: dest {} unused", + mir.format_local(dest_local)); + continue + } + let dest_lvalue_def = dest_use_info.defs_and_uses.iter().filter(|lvalue_def| { + lvalue_def.context.is_mutating_use() && !lvalue_def.context.is_drop() + }).next().unwrap(); + location = dest_lvalue_def.location; + + let basic_block = &mir[location.block]; + let statement_index = location.statement_index; + let statement = match basic_block.statements.get(statement_index) { + Some(statement) => statement, + None => { + debug!(" Can't copy-propagate local: used in terminator"); + continue + } + }; + + // That use of the source must be an assignment. + let src_lvalue = match statement.kind { + StatementKind::Assign( + ref dest_lvalue, + Rvalue::Use(Operand::Consume(ref src_lvalue))) + if Some(dest_local) == mir.local_index(dest_lvalue) => { + src_lvalue + } + _ => { + debug!(" Can't copy-propagate local: source use is not an \ + assignment"); + continue + } + }; + src_local = match mir.local_index(src_lvalue) { + Some(src_local) => src_local, + None => { + debug!(" Can't copy-propagate local: source is not a local"); + continue + } + }; + + // There must be exactly one use of the source used in a statement (not in a + // terminator). + let src_use_info = def_use_analysis.local_info(src_local); + let src_use_count = src_use_info.use_count(); + if src_use_count == 0 { + debug!(" Can't copy-propagate local: no uses"); + continue + } + if src_use_count != 1 { + debug!(" Can't copy-propagate local: {} uses", src_use_info.use_count()); + continue + } + + // Verify that the source doesn't change in between. This is done + // conservatively for now, by ensuring that the source has exactly one + // mutation. The goal is to prevent things like: + // + // DEST = SRC; + // SRC = X; + // USE(DEST); + // + // From being misoptimized into: + // + // SRC = X; + // USE(SRC); + let src_def_count = src_use_info.def_count_not_including_drop(); + if src_def_count != 1 { + debug!(" Can't copy-propagate local: {} defs of src", + src_use_info.def_count_not_including_drop()); + continue + } + } + + // If all checks passed, then we can eliminate the destination and the assignment. + // + // First, remove all markers. + // + // FIXME(pcwalton): Don't do this. Merge live ranges instead. + debug!(" Replacing all uses of {}", mir.format_local(dest_local)); + for lvalue_use in &def_use_analysis.local_info(dest_local).defs_and_uses { + if lvalue_use.context.is_storage_marker() { + mir.make_statement_nop(lvalue_use.location) + } + } + for lvalue_use in &def_use_analysis.local_info(src_local).defs_and_uses { + if lvalue_use.context.is_storage_marker() { + mir.make_statement_nop(lvalue_use.location) + } + } + + // Now replace all uses of the destination local with the source local. + let src_lvalue = Lvalue::from_local(mir, src_local); + def_use_analysis.replace_all_defs_and_uses_with(dest_local, mir, src_lvalue); + + // Finally, zap the now-useless assignment instruction. + mir.make_statement_nop(location); + + changed = true; + // FIXME(pcwalton): Update the use-def chains to delete the instructions instead of + // regenerating the chains. + break + } + if !changed { + break + } + } + } +} + diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs index e99b7a976e3e..7bcb89b5895e 100644 --- a/src/librustc_mir/transform/mod.rs +++ b/src/librustc_mir/transform/mod.rs @@ -19,4 +19,4 @@ pub mod qualify_consts; pub mod dump_mir; pub mod deaggregator; pub mod instcombine; - +pub mod copy_prop; diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs index f864f1678f23..57de68fce1d1 100644 --- a/src/librustc_mir/transform/promote_consts.rs +++ b/src/librustc_mir/transform/promote_consts.rs @@ -328,7 +328,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { impl<'a, 'tcx> MutVisitor<'tcx> for Promoter<'a, 'tcx> { fn visit_lvalue(&mut self, lvalue: &mut Lvalue<'tcx>, - context: LvalueContext, + context: LvalueContext<'tcx>, location: Location) { if let Lvalue::Temp(ref mut temp) = *lvalue { *temp = self.promote_temp(*temp); diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 9f162aabe0c2..c3a22853f843 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -475,7 +475,10 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> { /// For functions (constant or not), it also records /// candidates for promotion in promotion_candidates. impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { - fn visit_lvalue(&mut self, lvalue: &Lvalue<'tcx>, context: LvalueContext, location: Location) { + fn visit_lvalue(&mut self, + lvalue: &Lvalue<'tcx>, + context: LvalueContext<'tcx>, + location: Location) { match *lvalue { Lvalue::Arg(_) => { self.add(Qualif::FN_ARGUMENT); diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index a58de71ca41e..6648944540e3 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -523,7 +523,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { fn visit_lvalue(&mut self, lvalue: &mir::Lvalue<'tcx>, - context: mir_visit::LvalueContext, + context: mir_visit::LvalueContext<'tcx>, location: Location) { debug!("visiting lvalue {:?}", *lvalue); diff --git a/src/librustc_trans/mir/analyze.rs b/src/librustc_trans/mir/analyze.rs index e13da2531024..5de59b9f6bde 100644 --- a/src/librustc_trans/mir/analyze.rs +++ b/src/librustc_trans/mir/analyze.rs @@ -147,7 +147,7 @@ impl<'mir, 'bcx, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'bcx, 'tcx> { fn visit_lvalue(&mut self, lvalue: &mir::Lvalue<'tcx>, - context: LvalueContext, + context: LvalueContext<'tcx>, location: Location) { debug!("visit_lvalue(lvalue={:?}, context={:?})", lvalue, context); @@ -180,7 +180,7 @@ impl<'mir, 'bcx, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'bcx, 'tcx> { LvalueContext::Store | LvalueContext::Inspect | LvalueContext::Borrow { .. } | - LvalueContext::Projection => { + LvalueContext::Projection(..) => { self.mark_as_lvalue(index); } diff --git a/src/test/codegen/refs.rs b/src/test/codegen/refs.rs index 49ed2229fcd2..891ca03cc4dd 100644 --- a/src/test/codegen/refs.rs +++ b/src/test/codegen/refs.rs @@ -23,9 +23,9 @@ fn helper(_: usize) { pub fn ref_dst(s: &[u8]) { // We used to generate an extra alloca and memcpy to ref the dst, so check that we copy // directly to the alloca for "x" -// CHECK: [[X0:%[0-9]+]] = getelementptr {{.*}} { i8*, [[USIZE]] }* %x, i32 0, i32 0 +// CHECK: [[X0:%[0-9]+]] = getelementptr {{.*}} { i8*, [[USIZE]] }* %s, i32 0, i32 0 // CHECK: store i8* %0, i8** [[X0]] -// CHECK: [[X1:%[0-9]+]] = getelementptr {{.*}} { i8*, [[USIZE]] }* %x, i32 0, i32 1 +// CHECK: [[X1:%[0-9]+]] = getelementptr {{.*}} { i8*, [[USIZE]] }* %s, i32 0, i32 1 // CHECK: store [[USIZE]] %1, [[USIZE]]* [[X1]] let x = &*s; diff --git a/src/test/mir-opt/storage_ranges.rs b/src/test/mir-opt/storage_ranges.rs index f93447b642a2..8782dcf8898b 100644 --- a/src/test/mir-opt/storage_ranges.rs +++ b/src/test/mir-opt/storage_ranges.rs @@ -21,27 +21,27 @@ fn main() { // END RUST SOURCE // START rustc.node4.PreTrans.after.mir // bb0: { -// StorageLive(var0); // scope 0 at storage_ranges.rs:12:9: 12:10 -// var0 = const 0i32; // scope 0 at storage_ranges.rs:12:13: 12:14 -// StorageLive(var1); // scope 1 at storage_ranges.rs:14:13: 14:14 -// StorageLive(tmp1); // scope 1 at storage_ranges.rs:14:18: 14:25 -// StorageLive(tmp2); // scope 1 at storage_ranges.rs:14:23: 14:24 -// tmp2 = var0; // scope 1 at storage_ranges.rs:14:23: 14:24 -// tmp1 = std::option::Option::Some(tmp2,); // scope 1 at storage_ranges.rs:14:18: 14:25 -// var1 = &tmp1; // scope 1 at storage_ranges.rs:14:17: 14:25 -// StorageDead(tmp2); // scope 1 at storage_ranges.rs:14:23: 14:24 -// tmp0 = (); // scope 2 at storage_ranges.rs:13:5: 15:6 -// StorageDead(tmp1); // scope 1 at storage_ranges.rs:14:18: 14:25 -// StorageDead(var1); // scope 1 at storage_ranges.rs:14:13: 14:14 -// StorageLive(var2); // scope 1 at storage_ranges.rs:16:9: 16:10 -// var2 = const 1i32; // scope 1 at storage_ranges.rs:16:13: 16:14 -// return = (); // scope 3 at storage_ranges.rs:11:11: 17:2 -// StorageDead(var2); // scope 1 at storage_ranges.rs:16:9: 16:10 -// StorageDead(var0); // scope 0 at storage_ranges.rs:12:9: 12:10 -// goto -> bb1; // scope 0 at storage_ranges.rs:11:1: 17:2 +// nop; // scope 0 at storage_ranges.rs:14:9: 14:10 +// var0 = const 0i32; // scope 0 at storage_ranges.rs:14:13: 14:14 +// StorageLive(var1); // scope 1 at storage_ranges.rs:16:13: 16:14 +// StorageLive(tmp1); // scope 1 at storage_ranges.rs:16:18: 16:25 +// nop; // scope 1 at storage_ranges.rs:16:23: 16:24 +// nop; // scope 1 at storage_ranges.rs:16:23: 16:24 +// tmp1 = std::option::Option::Some(var0,); // scope 1 at storage_ranges.rs:16:18: 16:25 +// var1 = &tmp1; // scope 1 at storage_ranges.rs:16:17: 16:25 +// nop; // scope 1 at storage_ranges.rs:16:23: 16:24 +// tmp0 = (); // scope 2 at storage_ranges.rs:15:5: 17:6 +// StorageDead(tmp1); // scope 1 at storage_ranges.rs:16:18: 16:25 +// StorageDead(var1); // scope 1 at storage_ranges.rs:16:13: 16:14 +// StorageLive(var2); // scope 1 at storage_ranges.rs:18:9: 18:10 +// var2 = const 1i32; // scope 1 at storage_ranges.rs:18:13: 18:14 +// return = (); // scope 3 at storage_ranges.rs:13:11: 19:2 +// StorageDead(var2); // scope 1 at storage_ranges.rs:18:9: 18:10 +// nop; // scope 0 at storage_ranges.rs:14:9: 14:10 +// goto -> bb1; // scope 0 at storage_ranges.rs:13:1: 19:2 // } // // bb1: { -// return; // scope 0 at storage_ranges.rs:11:1: 17:2 +// return; // scope 0 at storage_ranges.rs:13:1: 19:2 // } // END rustc.node4.PreTrans.after.mir From 80a44779f7a211e075da9ed0ff2763afa00f43dc Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 20 Sep 2016 09:52:38 +1000 Subject: [PATCH 399/443] Lazily allocate TypedArena's first chunk. Currently `TypedArena` allocates its first chunk, which is usually 4096 bytes, as soon as it is created. If no allocations are ever made from the arena then this allocation (and the corresponding deallocation) is wasted effort. This commit changes `TypedArena` so it doesn't allocate the first chunk until the first allocation is made. This change speeds up rustc by a non-trivial amount because rustc uses `TypedArena` heavily: compilation speed (producing debug builds) on several of the rustc-benchmarks increases by 1.02--1.06x. The change should never cause a slow-down because the hot `alloc` function is unchanged. It does increase the size of `TypedArena` by one `usize` field, however. The commit also fixes some out-of-date comments. --- src/libarena/lib.rs | 93 +++++++++++++++++++++++++++------------------ 1 file changed, 55 insertions(+), 38 deletions(-) diff --git a/src/libarena/lib.rs b/src/libarena/lib.rs index b299b786b35a..556757ec84da 100644 --- a/src/libarena/lib.rs +++ b/src/libarena/lib.rs @@ -15,9 +15,8 @@ //! of individual objects while the arena itself is still alive. The benefit //! of an arena is very fast allocation; just a pointer bump. //! -//! This crate has two arenas implemented: `TypedArena`, which is a simpler -//! arena but can only hold objects of a single type, and `Arena`, which is a -//! more complex, slower arena which can hold objects of any type. +//! This crate implements `TypedArena`, a simple arena that can only hold +//! objects of a single type. #![crate_name = "arena"] #![unstable(feature = "rustc_private", issue = "27812")] @@ -51,8 +50,11 @@ use std::ptr; use alloc::heap; use alloc::raw_vec::RawVec; -/// A faster arena that can hold objects of only one type. +/// An arena that can hold objects of only one type. pub struct TypedArena { + /// The capacity of the first chunk (once it is allocated). + first_chunk_capacity: usize, + /// A pointer to the next object to be allocated. ptr: Cell<*mut T>, @@ -60,7 +62,7 @@ pub struct TypedArena { /// reached, a new chunk is allocated. end: Cell<*mut T>, - /// A vector arena segments. + /// A vector of arena chunks. chunks: RefCell>>, /// Marker indicating that dropping the arena causes its owned @@ -69,7 +71,7 @@ pub struct TypedArena { } struct TypedArenaChunk { - /// Pointer to the next arena segment. + /// The raw storage for the arena chunk. storage: RawVec, } @@ -117,7 +119,7 @@ impl TypedArenaChunk { const PAGE: usize = 4096; impl TypedArena { - /// Creates a new `TypedArena` with preallocated space for many objects. + /// Creates a new `TypedArena`. #[inline] pub fn new() -> TypedArena { // Reserve at least one page. @@ -125,18 +127,18 @@ impl TypedArena { TypedArena::with_capacity(PAGE / elem_size) } - /// Creates a new `TypedArena` with preallocated space for the given number of - /// objects. + /// Creates a new `TypedArena`. Each chunk used within the arena will have + /// space for at least the given number of objects. #[inline] pub fn with_capacity(capacity: usize) -> TypedArena { - unsafe { - let chunk = TypedArenaChunk::::new(cmp::max(1, capacity)); - TypedArena { - ptr: Cell::new(chunk.start()), - end: Cell::new(chunk.end()), - chunks: RefCell::new(vec![chunk]), - _own: PhantomData, - } + TypedArena { + first_chunk_capacity: cmp::max(1, capacity), + // We set both `ptr` and `end` to 0 so that the first call to + // alloc() will trigger a grow(). + ptr: Cell::new(0 as *mut T), + end: Cell::new(0 as *mut T), + chunks: RefCell::new(vec![]), + _own: PhantomData, } } @@ -171,16 +173,22 @@ impl TypedArena { fn grow(&self) { unsafe { let mut chunks = self.chunks.borrow_mut(); - let prev_capacity = chunks.last().unwrap().storage.cap(); - let new_capacity = prev_capacity.checked_mul(2).unwrap(); - if chunks.last_mut().unwrap().storage.double_in_place() { - self.end.set(chunks.last().unwrap().end()); + let (chunk, new_capacity); + if let Some(last_chunk) = chunks.last_mut() { + if last_chunk.storage.double_in_place() { + self.end.set(last_chunk.end()); + return; + } else { + let prev_capacity = last_chunk.storage.cap(); + new_capacity = prev_capacity.checked_mul(2).unwrap(); + } } else { - let chunk = TypedArenaChunk::::new(new_capacity); - self.ptr.set(chunk.start()); - self.end.set(chunk.end()); - chunks.push(chunk); + new_capacity = self.first_chunk_capacity; } + chunk = TypedArenaChunk::::new(new_capacity); + self.ptr.set(chunk.start()); + self.end.set(chunk.end()); + chunks.push(chunk); } } /// Clears the arena. Deallocates all but the longest chunk which may be reused. @@ -188,12 +196,14 @@ impl TypedArena { unsafe { // Clear the last chunk, which is partially filled. let mut chunks_borrow = self.chunks.borrow_mut(); - let last_idx = chunks_borrow.len() - 1; - self.clear_last_chunk(&mut chunks_borrow[last_idx]); - // If `T` is ZST, code below has no effect. - for mut chunk in chunks_borrow.drain(..last_idx) { - let cap = chunk.storage.cap(); - chunk.destroy(cap); + if let Some(mut last_chunk) = chunks_borrow.pop() { + self.clear_last_chunk(&mut last_chunk); + // If `T` is ZST, code below has no effect. + for mut chunk in chunks_borrow.drain(..) { + let cap = chunk.storage.cap(); + chunk.destroy(cap); + } + chunks_borrow.push(last_chunk); } } } @@ -230,13 +240,14 @@ impl Drop for TypedArena { unsafe { // Determine how much was filled. let mut chunks_borrow = self.chunks.borrow_mut(); - let mut last_chunk = chunks_borrow.pop().unwrap(); - // Drop the contents of the last chunk. - self.clear_last_chunk(&mut last_chunk); - // The last chunk will be dropped. Destroy all other chunks. - for chunk in chunks_borrow.iter_mut() { - let cap = chunk.storage.cap(); - chunk.destroy(cap); + if let Some(mut last_chunk) = chunks_borrow.pop() { + // Drop the contents of the last chunk. + self.clear_last_chunk(&mut last_chunk); + // The last chunk will be dropped. Destroy all other chunks. + for chunk in chunks_borrow.iter_mut() { + let cap = chunk.storage.cap(); + chunk.destroy(cap); + } } // RawVec handles deallocation of `last_chunk` and `self.chunks`. } @@ -260,6 +271,12 @@ mod tests { z: i32, } + #[test] + pub fn test_unused() { + let arena: TypedArena = TypedArena::new(); + assert!(arena.chunks.borrow().is_empty()); + } + #[test] fn test_arena_alloc_nested() { struct Inner { From c41a806e4efb8f6dc614ff0675189a6a2bdc8abf Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Thu, 15 Sep 2016 19:02:10 +0200 Subject: [PATCH 400/443] Workaround #34427 by using memset of 0 on ARM to set the discriminant. --- src/librustc_trans/adt.rs | 25 +++++++++++++++++++++---- src/test/run-pass/issue-34427.rs | 26 ++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 4 deletions(-) create mode 100644 src/test/run-pass/issue-34427.rs diff --git a/src/librustc_trans/adt.rs b/src/librustc_trans/adt.rs index 67e5ec2616d2..0fd208c95d4d 100644 --- a/src/librustc_trans/adt.rs +++ b/src/librustc_trans/adt.rs @@ -54,6 +54,7 @@ use syntax::ast; use syntax::attr; use syntax::attr::IntType; use abi::FAT_PTR_ADDR; +use base; use build::*; use common::*; use debuginfo::DebugLoc; @@ -963,16 +964,32 @@ pub fn trans_set_discr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr<'tcx>, Store(bcx, C_null(llptrty), val); } } - StructWrappedNullablePointer { nndiscr, ref discrfield, .. } => { + StructWrappedNullablePointer { nndiscr, ref discrfield, ref nonnull, .. } => { if discr != nndiscr { - let llptrptr = GEPi(bcx, val, &discrfield[..]); - let llptrty = val_ty(llptrptr).element_type(); - Store(bcx, C_null(llptrty), llptrptr); + if target_sets_discr_via_memset(bcx) { + // Issue #34427: As workaround for LLVM bug on + // ARM, use memset of 0 on whole struct rather + // than storing null to single target field. + let b = B(bcx); + let llptr = b.pointercast(val, Type::i8(b.ccx).ptr_to()); + let fill_byte = C_u8(b.ccx, 0); + let size = C_uint(b.ccx, nonnull.size); + let align = C_i32(b.ccx, nonnull.align as i32); + base::call_memset(&b, llptr, fill_byte, size, align, false); + } else { + let llptrptr = GEPi(bcx, val, &discrfield[..]); + let llptrty = val_ty(llptrptr).element_type(); + Store(bcx, C_null(llptrty), llptrptr); + } } } } } +fn target_sets_discr_via_memset<'blk, 'tcx>(bcx: Block<'blk, 'tcx>) -> bool { + bcx.sess().target.target.arch == "arm" || bcx.sess().target.target.arch == "aarch64" +} + fn assert_discr_in_range(ity: IntType, min: Disr, max: Disr, discr: Disr) { match ity { attr::UnsignedInt(_) => { diff --git a/src/test/run-pass/issue-34427.rs b/src/test/run-pass/issue-34427.rs new file mode 100644 index 000000000000..6bf8a2ac6a72 --- /dev/null +++ b/src/test/run-pass/issue-34427.rs @@ -0,0 +1,26 @@ +// 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. + +// Issue #34427: On ARM, the code in `foo` at one time was generating +// a machine code instruction of the form: `str r0, [r0, rN]!` (for +// some N), which is not legal because the source register and base +// register cannot be identical in the preindexed form signalled by +// the `!`. +// +// See LLVM bug: https://llvm.org/bugs/show_bug.cgi?id=28809 + +#[inline(never)] +fn foo(n: usize) -> Vec> { + (0..n).map(|_| None).collect() +} + +fn main() { + let _ = (foo(10), foo(32)); +} From a79104e0c639be1c79bafb338ad7214802caada9 Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Sat, 27 Aug 2016 20:18:02 +0300 Subject: [PATCH 401/443] serialize: extend with specialization-based encoding/decoding multi-dispatch. --- src/libserialize/lib.rs | 5 ++ src/libserialize/serialize.rs | 95 +++++++++++++++++++++++++++++++++++ 2 files changed, 100 insertions(+) diff --git a/src/libserialize/lib.rs b/src/libserialize/lib.rs index 80cd47c85ccd..ebd939120973 100644 --- a/src/libserialize/lib.rs +++ b/src/libserialize/lib.rs @@ -29,8 +29,10 @@ Core encoding and decoding interfaces. #![feature(box_syntax)] #![feature(collections)] +#![feature(core_intrinsics)] #![feature(enumset)] #![feature(rustc_private)] +#![feature(specialization)] #![feature(staged_api)] #![feature(unicode)] #![feature(question_mark)] @@ -46,6 +48,9 @@ extern crate collections; pub use self::serialize::{Decoder, Encoder, Decodable, Encodable, DecoderHelpers, EncoderHelpers}; +pub use self::serialize::{SpecializationError, SpecializedEncoder, SpecializedDecoder}; +pub use self::serialize::{UseSpecializedEncodable, UseSpecializedDecodable}; + mod serialize; mod collection_impls; diff --git a/src/libserialize/serialize.rs b/src/libserialize/serialize.rs index 8e271597dfcb..4414fee78788 100644 --- a/src/libserialize/serialize.rs +++ b/src/libserialize/serialize.rs @@ -14,6 +14,7 @@ Core encoding and decoding interfaces. */ +use std::intrinsics; use std::path; use std::rc::Rc; use std::cell::{Cell, RefCell}; @@ -635,3 +636,97 @@ impl DecoderHelpers for D { }) } } + +// ___________________________________________________________________________ +// Specialization-based interface for multi-dispatch Encodable/Decodable. + +/// Implement this trait on your `{Encodable,Decodable}::Error` types +/// to override the default panic behavior for missing specializations. +pub trait SpecializationError { + /// Create an error for a missing method specialization. + /// Defaults to panicking with type, trait & method names. + /// `S` is the encoder/decoder state type, + /// `T` is the type being encoded/decoded, and + /// the arguments are the names of the trait + /// and method that should've been overriden. + fn not_found(trait_name: &'static str, + method_name: &'static str) -> Self; +} + +impl SpecializationError for E { + default fn not_found(trait_name: &'static str, + method_name: &'static str) -> E { + panic!("missing specializaiton: `<{} as {}<{}>>::{}` not overriden", + unsafe { intrinsics::type_name::() }, + trait_name, + unsafe { intrinsics::type_name::() }, + method_name); + } +} + +/// Implement this trait on encoders, with `T` being the type +/// you want to encode (employing `UseSpecializedEncodable`), +/// using a strategy specific to the encoder. +/// Can also be implemented alongside `UseSpecializedEncodable` +/// to provide a default `specialized_encode` for encoders +/// which do not implement `SpecializedEncoder` themselves. +pub trait SpecializedEncoder: Encoder { + /// Encode the value in a manner specific to this encoder state. + /// Defaults to returning an error (see `SpecializationError`). + fn specialized_encode(&mut self, value: &T) -> Result<(), Self::Error>; +} + +impl SpecializedEncoder for E { + default fn specialized_encode(&mut self, _: &T) -> Result<(), E::Error> { + Err(E::Error::not_found::("SpecializedEncoder", "specialized_encode")) + } +} + +/// Implement this trait on decoders, with `T` being the type +/// you want to decode (employing `UseSpecializedDecodable`), +/// using a strategy specific to the decoder. +/// Can also be implemented alongside `UseSpecializedDecodable` +/// to provide a default `specialized_decode` for decoders +/// which do not implement `SpecializedDecoder` themselves. +pub trait SpecializedDecoder: Decoder { + /// Decode a value in a manner specific to this decoder state. + /// Defaults to returning an error (see `SpecializationError`). + fn specialized_decode(&mut self) -> Result; +} + +impl SpecializedDecoder for D { + default fn specialized_decode(&mut self) -> Result { + Err(D::Error::not_found::("SpecializedDecoder", "specialized_decode")) + } +} + +/// Implement this trait on your type to get an `Encodable` +/// implementation which goes through `SpecializedEncoder`. +pub trait UseSpecializedEncodable {} + +impl Encodable for T { + default fn encode(&self, e: &mut E) -> Result<(), E::Error> { + E::specialized_encode(e, self) + } +} + +/// Implement this trait on your type to get an `Decodable` +/// implementation which goes through `SpecializedDecoder`. +pub trait UseSpecializedDecodable: Sized {} + +impl Decodable for T { + default fn decode(d: &mut D) -> Result { + D::specialized_decode(d) + } +} + +// Can't avoid specialization for &T and Box impls, +// as proxy impls on them are blankets that conflict +// with the Encodable and Decodable impls above, +// which only have `default` on their methods +// for this exact reason. +// May be fixable in a simpler fashion via the +// more complex lattice model for specialization. +impl<'a, T: ?Sized + Encodable> UseSpecializedEncodable for &'a T {} +impl UseSpecializedEncodable for Box {} +impl UseSpecializedDecodable for Box {} From 3ad8aa6b87cb78803d284c37d33a064b5677a5fa Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Sun, 28 Aug 2016 07:10:22 +0300 Subject: [PATCH 402/443] rbml: move the tagged encoder/decoder to librustc_metadata. --- src/librbml/lib.rs | 1550 +------------------------- src/librbml/opaque.rs | 7 +- src/librustc_metadata/lib.rs | 14 +- src/librustc_metadata/rbml/reader.rs | 1025 +++++++++++++++++ src/librustc_metadata/rbml/writer.rs | 522 +++++++++ 5 files changed, 1564 insertions(+), 1554 deletions(-) create mode 100644 src/librustc_metadata/rbml/reader.rs create mode 100644 src/librustc_metadata/rbml/writer.rs diff --git a/src/librbml/lib.rs b/src/librbml/lib.rs index 5a8a52f7dfc6..65259f903a99 100644 --- a/src/librbml/lib.rs +++ b/src/librbml/lib.rs @@ -8,108 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Really Bad Markup Language (rbml) is an internal serialization format of rustc. -//! This is not intended to be used by users. -//! -//! Originally based on the Extensible Binary Markup Language -//! (ebml; http://www.matroska.org/technical/specs/rfc/index.html), -//! it is now a separate format tuned for the rust object metadata. -//! -//! # Encoding -//! -//! RBML document consists of the tag, length and data. -//! The encoded data can contain multiple RBML documents concatenated. -//! -//! **Tags** are a hint for the following data. -//! Tags are a number from 0x000 to 0xfff, where 0xf0 through 0xff is reserved. -//! Tags less than 0xf0 are encoded in one literal byte. -//! Tags greater than 0xff are encoded in two big-endian bytes, -//! where the tag number is ORed with 0xf000. (E.g. tag 0x123 = `f1 23`) -//! -//! **Lengths** encode the length of the following data. -//! It is a variable-length unsigned isize, and one of the following forms: -//! -//! - `80` through `fe` for lengths up to 0x7e; -//! - `40 ff` through `7f ff` for lengths up to 0x3fff; -//! - `20 40 00` through `3f ff ff` for lengths up to 0x1fffff; -//! - `10 20 00 00` through `1f ff ff ff` for lengths up to 0xfffffff. -//! -//! The "overlong" form is allowed so that the length can be encoded -//! without the prior knowledge of the encoded data. -//! For example, the length 0 can be represented either by `80`, `40 00`, -//! `20 00 00` or `10 00 00 00`. -//! The encoder tries to minimize the length if possible. -//! Also, some predefined tags listed below are so commonly used that -//! their lengths are omitted ("implicit length"). -//! -//! **Data** can be either binary bytes or zero or more nested RBML documents. -//! Nested documents cannot overflow, and should be entirely contained -//! within a parent document. -//! -//! # Predefined Tags -//! -//! Most RBML tags are defined by the application. -//! (For the rust object metadata, see also `rustc::metadata::common`.) -//! RBML itself does define a set of predefined tags however, -//! intended for the auto-serialization implementation. -//! -//! Predefined tags with an implicit length: -//! -//! - `U8` (`00`): 1-byte unsigned integer. -//! - `U16` (`01`): 2-byte big endian unsigned integer. -//! - `U32` (`02`): 4-byte big endian unsigned integer. -//! - `U64` (`03`): 8-byte big endian unsigned integer. -//! Any of `U*` tags can be used to encode primitive unsigned integer types, -//! as long as it is no greater than the actual size. -//! For example, `u8` can only be represented via the `U8` tag. -//! -//! - `I8` (`04`): 1-byte signed integer. -//! - `I16` (`05`): 2-byte big endian signed integer. -//! - `I32` (`06`): 4-byte big endian signed integer. -//! - `I64` (`07`): 8-byte big endian signed integer. -//! Similar to `U*` tags. Always uses two's complement encoding. -//! -//! - `Bool` (`08`): 1-byte boolean value, `00` for false and `01` for true. -//! -//! - `Char` (`09`): 4-byte big endian Unicode scalar value. -//! Surrogate pairs or out-of-bound values are invalid. -//! -//! - `F32` (`0a`): 4-byte big endian unsigned integer representing -//! IEEE 754 binary32 floating-point format. -//! - `F64` (`0b`): 8-byte big endian unsigned integer representing -//! IEEE 754 binary64 floating-point format. -//! -//! - `Sub8` (`0c`): 1-byte unsigned integer for supplementary information. -//! - `Sub32` (`0d`): 4-byte unsigned integer for supplementary information. -//! Those two tags normally occur as the first subdocument of certain tags, -//! namely `Enum`, `Vec` and `Map`, to provide a variant or size information. -//! They can be used interchangeably. -//! -//! Predefined tags with an explicit length: -//! -//! - `Str` (`10`): A UTF-8-encoded string. -//! -//! - `Enum` (`11`): An enum. -//! The first subdocument should be `Sub*` tags with a variant ID. -//! Subsequent subdocuments, if any, encode variant arguments. -//! -//! - `Vec` (`12`): A vector (sequence). -//! - `VecElt` (`13`): A vector element. -//! The first subdocument should be `Sub*` tags with the number of elements. -//! Subsequent subdocuments should be `VecElt` tag per each element. -//! -//! - `Map` (`14`): A map (associated array). -//! - `MapKey` (`15`): A key part of the map entry. -//! - `MapVal` (`16`): A value part of the map entry. -//! The first subdocument should be `Sub*` tags with the number of entries. -//! Subsequent subdocuments should be an alternating sequence of -//! `MapKey` and `MapVal` tags per each entry. -//! -//! - `Opaque` (`17`): An opaque, custom-format tag. -//! Used to wrap ordinary custom tags or data in the auto-serialized context. -//! Rustc typically uses this to encode type information. -//! -//! First 0x20 tags are reserved by RBML; custom tags start at 0x20. +//! Skeleton of RBML (Really Bad Markup Language). +//! See `src/librustc_metadata/reader.rs` for more details. #![crate_name = "rbml"] #![unstable(feature = "rustc_private", issue = "27812")] @@ -142,93 +42,10 @@ extern crate test; pub mod opaque; pub mod leb128; -pub use self::EbmlEncoderTag::*; pub use self::Error::*; -use std::str; use std::fmt; -/// Common data structures -#[derive(Clone, Copy)] -pub struct Doc<'a> { - pub data: &'a [u8], - pub start: usize, - pub end: usize, -} - -impl<'doc> Doc<'doc> { - pub fn new(data: &'doc [u8]) -> Doc<'doc> { - Doc { - data: data, - start: 0, - end: data.len(), - } - } - - pub fn get(&self, tag: usize) -> Doc<'doc> { - reader::get_doc(*self, tag) - } - - pub fn is_empty(&self) -> bool { - self.start == self.end - } - - pub fn as_str(&self) -> &'doc str { - str::from_utf8(&self.data[self.start..self.end]).unwrap() - } - - pub fn to_string(&self) -> String { - self.as_str().to_string() - } -} - -pub struct TaggedDoc<'a> { - tag: usize, - pub doc: Doc<'a>, -} - -#[derive(Copy, Clone, Debug)] -pub enum EbmlEncoderTag { - // tags 00..1f are reserved for auto-serialization. - // first NUM_IMPLICIT_TAGS tags are implicitly sized and lengths are not encoded. - EsU8 = 0x00, // + 1 byte - EsU16 = 0x01, // + 2 bytes - EsU32 = 0x02, // + 4 bytes - EsU64 = 0x03, // + 8 bytes - EsI8 = 0x04, // + 1 byte - EsI16 = 0x05, // + 2 bytes - EsI32 = 0x06, // + 4 bytes - EsI64 = 0x07, // + 8 bytes - EsBool = 0x08, // + 1 byte - EsChar = 0x09, // + 4 bytes - EsF32 = 0x0a, // + 4 bytes - EsF64 = 0x0b, // + 8 bytes - EsSub8 = 0x0c, // + 1 byte - EsSub32 = 0x0d, // + 4 bytes - // 0x0e and 0x0f are reserved - EsStr = 0x10, - EsEnum = 0x11, // encodes the variant id as the first EsSub* - EsVec = 0x12, // encodes the # of elements as the first EsSub* - EsVecElt = 0x13, - EsMap = 0x14, // encodes the # of pairs as the first EsSub* - EsMapKey = 0x15, - EsMapVal = 0x16, - EsOpaque = 0x17, -} - -const NUM_TAGS: usize = 0x1000; -const NUM_IMPLICIT_TAGS: usize = 0x0e; - -#[cfg_attr(rustfmt, rustfmt_skip)] -static TAG_IMPLICIT_LEN: [i8; NUM_IMPLICIT_TAGS] = [ - 1, 2, 4, 8, // EsU* - 1, 2, 4, 8, // ESI* - 1, // EsBool - 4, // EsChar - 4, 8, // EsF* - 1, 4, // EsSub* -]; - #[derive(Debug)] pub enum Error { IntTooBig(usize), @@ -244,1366 +61,3 @@ impl fmt::Display for Error { fmt::Debug::fmt(self, f) } } -// -------------------------------------- - -pub mod reader { - use std::char; - - use std::isize; - use std::mem::transmute; - - use serialize; - - use super::opaque; - use super::{ApplicationError, EsVec, EsMap, EsEnum, EsSub8, EsSub32, EsVecElt, EsMapKey, - EsU64, EsU32, EsU16, EsU8, EsI64, EsI32, EsI16, EsI8, EsBool, EsF64, EsF32, - EsChar, EsStr, EsMapVal, EsOpaque, EbmlEncoderTag, Doc, TaggedDoc, Error, - IntTooBig, InvalidTag, Expected, NUM_IMPLICIT_TAGS, TAG_IMPLICIT_LEN}; - - pub type DecodeResult = Result; - // rbml reading - - macro_rules! try_or { - ($e:expr, $r:expr) => ( - match $e { - Ok(e) => e, - Err(e) => { - debug!("ignored error: {:?}", e); - return $r - } - } - ) - } - - #[derive(Copy, Clone)] - pub struct Res { - pub val: usize, - pub next: usize, - } - - pub fn tag_at(data: &[u8], start: usize) -> DecodeResult { - let v = data[start] as usize; - if v < 0xf0 { - Ok(Res { - val: v, - next: start + 1, - }) - } else if v > 0xf0 { - Ok(Res { - val: ((v & 0xf) << 8) | data[start + 1] as usize, - next: start + 2, - }) - } else { - // every tag starting with byte 0xf0 is an overlong form, which is prohibited. - Err(InvalidTag(v)) - } - } - - #[inline(never)] - fn vuint_at_slow(data: &[u8], start: usize) -> DecodeResult { - let a = data[start]; - if a & 0x80 != 0 { - return Ok(Res { - val: (a & 0x7f) as usize, - next: start + 1, - }); - } - if a & 0x40 != 0 { - return Ok(Res { - val: ((a & 0x3f) as usize) << 8 | (data[start + 1] as usize), - next: start + 2, - }); - } - if a & 0x20 != 0 { - return Ok(Res { - val: ((a & 0x1f) as usize) << 16 | (data[start + 1] as usize) << 8 | - (data[start + 2] as usize), - next: start + 3, - }); - } - if a & 0x10 != 0 { - return Ok(Res { - val: ((a & 0x0f) as usize) << 24 | (data[start + 1] as usize) << 16 | - (data[start + 2] as usize) << 8 | - (data[start + 3] as usize), - next: start + 4, - }); - } - Err(IntTooBig(a as usize)) - } - - pub fn vuint_at(data: &[u8], start: usize) -> DecodeResult { - if data.len() - start < 4 { - return vuint_at_slow(data, start); - } - - // Lookup table for parsing EBML Element IDs as per - // http://ebml.sourceforge.net/specs/ The Element IDs are parsed by - // reading a big endian u32 positioned at data[start]. Using the four - // most significant bits of the u32 we lookup in the table below how - // the element ID should be derived from it. - // - // The table stores tuples (shift, mask) where shift is the number the - // u32 should be right shifted with and mask is the value the right - // shifted value should be masked with. If for example the most - // significant bit is set this means it's a class A ID and the u32 - // should be right shifted with 24 and masked with 0x7f. Therefore we - // store (24, 0x7f) at index 0x8 - 0xF (four bit numbers where the most - // significant bit is set). - // - // By storing the number of shifts and masks in a table instead of - // checking in order if the most significant bit is set, the second - // most significant bit is set etc. we can replace up to three - // "and+branch" with a single table lookup which gives us a measured - // speedup of around 2x on x86_64. - static SHIFT_MASK_TABLE: [(usize, u32); 16] = [(0, 0x0), - (0, 0x0fffffff), - (8, 0x1fffff), - (8, 0x1fffff), - (16, 0x3fff), - (16, 0x3fff), - (16, 0x3fff), - (16, 0x3fff), - (24, 0x7f), - (24, 0x7f), - (24, 0x7f), - (24, 0x7f), - (24, 0x7f), - (24, 0x7f), - (24, 0x7f), - (24, 0x7f)]; - - unsafe { - let ptr = data.as_ptr().offset(start as isize) as *const u32; - let val = u32::from_be(*ptr); - - let i = (val >> 28) as usize; - let (shift, mask) = SHIFT_MASK_TABLE[i]; - Ok(Res { - val: ((val >> shift) & mask) as usize, - next: start + ((32 - shift) >> 3), - }) - } - } - - pub fn tag_len_at(data: &[u8], tag: Res) -> DecodeResult { - if tag.val < NUM_IMPLICIT_TAGS && TAG_IMPLICIT_LEN[tag.val] >= 0 { - Ok(Res { - val: TAG_IMPLICIT_LEN[tag.val] as usize, - next: tag.next, - }) - } else { - vuint_at(data, tag.next) - } - } - - pub fn doc_at<'a>(data: &'a [u8], start: usize) -> DecodeResult> { - let elt_tag = tag_at(data, start)?; - let elt_size = tag_len_at(data, elt_tag)?; - let end = elt_size.next + elt_size.val; - Ok(TaggedDoc { - tag: elt_tag.val, - doc: Doc { - data: data, - start: elt_size.next, - end: end, - }, - }) - } - - pub fn maybe_get_doc<'a>(d: Doc<'a>, tg: usize) -> Option> { - let mut pos = d.start; - while pos < d.end { - let elt_tag = try_or!(tag_at(d.data, pos), None); - let elt_size = try_or!(tag_len_at(d.data, elt_tag), None); - pos = elt_size.next + elt_size.val; - if elt_tag.val == tg { - return Some(Doc { - data: d.data, - start: elt_size.next, - end: pos, - }); - } - } - None - } - - pub fn get_doc<'a>(d: Doc<'a>, tg: usize) -> Doc<'a> { - match maybe_get_doc(d, tg) { - Some(d) => d, - None => { - error!("failed to find block with tag {:?}", tg); - panic!(); - } - } - } - - pub fn docs<'a>(d: Doc<'a>) -> DocsIterator<'a> { - DocsIterator { d: d } - } - - pub struct DocsIterator<'a> { - d: Doc<'a>, - } - - impl<'a> Iterator for DocsIterator<'a> { - type Item = (usize, Doc<'a>); - - fn next(&mut self) -> Option<(usize, Doc<'a>)> { - if self.d.start >= self.d.end { - return None; - } - - let elt_tag = try_or!(tag_at(self.d.data, self.d.start), { - self.d.start = self.d.end; - None - }); - let elt_size = try_or!(tag_len_at(self.d.data, elt_tag), { - self.d.start = self.d.end; - None - }); - - let end = elt_size.next + elt_size.val; - let doc = Doc { - data: self.d.data, - start: elt_size.next, - end: end, - }; - - self.d.start = end; - return Some((elt_tag.val, doc)); - } - } - - pub fn tagged_docs<'a>(d: Doc<'a>, tag: usize) -> TaggedDocsIterator<'a> { - TaggedDocsIterator { - iter: docs(d), - tag: tag, - } - } - - pub struct TaggedDocsIterator<'a> { - iter: DocsIterator<'a>, - tag: usize, - } - - impl<'a> Iterator for TaggedDocsIterator<'a> { - type Item = Doc<'a>; - - fn next(&mut self) -> Option> { - while let Some((tag, doc)) = self.iter.next() { - if tag == self.tag { - return Some(doc); - } - } - None - } - } - - pub fn with_doc_data(d: Doc, f: F) -> T - where F: FnOnce(&[u8]) -> T - { - f(&d.data[d.start..d.end]) - } - - pub fn doc_as_u8(d: Doc) -> u8 { - assert_eq!(d.end, d.start + 1); - d.data[d.start] - } - - pub fn doc_as_u64(d: Doc) -> u64 { - if d.end >= 8 { - // For performance, we read 8 big-endian bytes, - // and mask off the junk if there is any. This - // obviously won't work on the first 8 bytes - // of a file - we will fall of the start - // of the page and segfault. - - let mut b = [0; 8]; - b.copy_from_slice(&d.data[d.end - 8..d.end]); - let data = unsafe { (*(b.as_ptr() as *const u64)).to_be() }; - let len = d.end - d.start; - if len < 8 { - data & ((1 << (len * 8)) - 1) - } else { - data - } - } else { - let mut result = 0; - for b in &d.data[d.start..d.end] { - result = (result << 8) + (*b as u64); - } - result - } - } - - #[inline] - pub fn doc_as_u16(d: Doc) -> u16 { - doc_as_u64(d) as u16 - } - #[inline] - pub fn doc_as_u32(d: Doc) -> u32 { - doc_as_u64(d) as u32 - } - - #[inline] - pub fn doc_as_i8(d: Doc) -> i8 { - doc_as_u8(d) as i8 - } - #[inline] - pub fn doc_as_i16(d: Doc) -> i16 { - doc_as_u16(d) as i16 - } - #[inline] - pub fn doc_as_i32(d: Doc) -> i32 { - doc_as_u32(d) as i32 - } - #[inline] - pub fn doc_as_i64(d: Doc) -> i64 { - doc_as_u64(d) as i64 - } - - pub struct Decoder<'a> { - parent: Doc<'a>, - pos: usize, - } - - impl<'doc> Decoder<'doc> { - pub fn new(d: Doc<'doc>) -> Decoder<'doc> { - Decoder { - parent: d, - pos: d.start, - } - } - - fn next_doc(&mut self, exp_tag: EbmlEncoderTag) -> DecodeResult> { - debug!(". next_doc(exp_tag={:?})", exp_tag); - if self.pos >= self.parent.end { - return Err(Expected(format!("no more documents in current node!"))); - } - let TaggedDoc { tag: r_tag, doc: r_doc } = doc_at(self.parent.data, self.pos)?; - debug!("self.parent={:?}-{:?} self.pos={:?} r_tag={:?} r_doc={:?}-{:?}", - self.parent.start, - self.parent.end, - self.pos, - r_tag, - r_doc.start, - r_doc.end); - if r_tag != (exp_tag as usize) { - return Err(Expected(format!("expected EBML doc with tag {:?} but found tag {:?}", - exp_tag, - r_tag))); - } - if r_doc.end > self.parent.end { - return Err(Expected(format!("invalid EBML, child extends to {:#x}, parent to \ - {:#x}", - r_doc.end, - self.parent.end))); - } - self.pos = r_doc.end; - Ok(r_doc) - } - - fn push_doc(&mut self, exp_tag: EbmlEncoderTag, f: F) -> DecodeResult - where F: FnOnce(&mut Decoder<'doc>) -> DecodeResult - { - let d = self.next_doc(exp_tag)?; - let old_parent = self.parent; - let old_pos = self.pos; - self.parent = d; - self.pos = d.start; - let r = f(self)?; - self.parent = old_parent; - self.pos = old_pos; - Ok(r) - } - - fn _next_sub(&mut self) -> DecodeResult { - // empty vector/map optimization - if self.parent.is_empty() { - return Ok(0); - } - - let TaggedDoc { tag: r_tag, doc: r_doc } = doc_at(self.parent.data, self.pos)?; - let r = if r_tag == (EsSub8 as usize) { - doc_as_u8(r_doc) as usize - } else if r_tag == (EsSub32 as usize) { - doc_as_u32(r_doc) as usize - } else { - return Err(Expected(format!("expected EBML doc with tag {:?} or {:?} but found \ - tag {:?}", - EsSub8, - EsSub32, - r_tag))); - }; - if r_doc.end > self.parent.end { - return Err(Expected(format!("invalid EBML, child extends to {:#x}, parent to \ - {:#x}", - r_doc.end, - self.parent.end))); - } - self.pos = r_doc.end; - debug!("_next_sub result={:?}", r); - Ok(r) - } - - // variable-length unsigned integer with different tags. - // `first_tag` should be a tag for u8 or i8. - // `last_tag` should be the largest allowed integer tag with the matching signedness. - // all tags between them should be valid, in the order of u8, u16, u32 and u64. - fn _next_int(&mut self, - first_tag: EbmlEncoderTag, - last_tag: EbmlEncoderTag) - -> DecodeResult { - if self.pos >= self.parent.end { - return Err(Expected(format!("no more documents in current node!"))); - } - - let TaggedDoc { tag: r_tag, doc: r_doc } = doc_at(self.parent.data, self.pos)?; - let r = if first_tag as usize <= r_tag && r_tag <= last_tag as usize { - match r_tag - first_tag as usize { - 0 => doc_as_u8(r_doc) as u64, - 1 => doc_as_u16(r_doc) as u64, - 2 => doc_as_u32(r_doc) as u64, - 3 => doc_as_u64(r_doc), - _ => unreachable!(), - } - } else { - return Err(Expected(format!("expected EBML doc with tag {:?} through {:?} but \ - found tag {:?}", - first_tag, - last_tag, - r_tag))); - }; - if r_doc.end > self.parent.end { - return Err(Expected(format!("invalid EBML, child extends to {:#x}, parent to \ - {:#x}", - r_doc.end, - self.parent.end))); - } - self.pos = r_doc.end; - debug!("_next_int({:?}, {:?}) result={:?}", first_tag, last_tag, r); - Ok(r) - } - - pub fn read_opaque(&mut self, op: F) -> DecodeResult - where F: FnOnce(&mut opaque::Decoder, Doc) -> DecodeResult - { - let doc = self.next_doc(EsOpaque)?; - - let result = { - let mut opaque_decoder = opaque::Decoder::new(doc.data, doc.start); - op(&mut opaque_decoder, doc)? - }; - - Ok(result) - } - - pub fn position(&self) -> usize { - self.pos - } - - pub fn advance(&mut self, bytes: usize) { - self.pos += bytes; - } - } - - impl<'doc> serialize::Decoder for Decoder<'doc> { - type Error = Error; - fn read_nil(&mut self) -> DecodeResult<()> { - Ok(()) - } - - fn read_u64(&mut self) -> DecodeResult { - self._next_int(EsU8, EsU64) - } - fn read_u32(&mut self) -> DecodeResult { - Ok(self._next_int(EsU8, EsU32)? as u32) - } - fn read_u16(&mut self) -> DecodeResult { - Ok(self._next_int(EsU8, EsU16)? as u16) - } - fn read_u8(&mut self) -> DecodeResult { - Ok(doc_as_u8(self.next_doc(EsU8)?)) - } - fn read_usize(&mut self) -> DecodeResult { - let v = self._next_int(EsU8, EsU64)?; - if v > (::std::usize::MAX as u64) { - Err(IntTooBig(v as usize)) - } else { - Ok(v as usize) - } - } - - fn read_i64(&mut self) -> DecodeResult { - Ok(self._next_int(EsI8, EsI64)? as i64) - } - fn read_i32(&mut self) -> DecodeResult { - Ok(self._next_int(EsI8, EsI32)? as i32) - } - fn read_i16(&mut self) -> DecodeResult { - Ok(self._next_int(EsI8, EsI16)? as i16) - } - fn read_i8(&mut self) -> DecodeResult { - Ok(doc_as_u8(self.next_doc(EsI8)?) as i8) - } - fn read_isize(&mut self) -> DecodeResult { - let v = self._next_int(EsI8, EsI64)? as i64; - if v > (isize::MAX as i64) || v < (isize::MIN as i64) { - debug!("FIXME \\#6122: Removing this makes this function miscompile"); - Err(IntTooBig(v as usize)) - } else { - Ok(v as isize) - } - } - - fn read_bool(&mut self) -> DecodeResult { - Ok(doc_as_u8(self.next_doc(EsBool)?) != 0) - } - - fn read_f64(&mut self) -> DecodeResult { - let bits = doc_as_u64(self.next_doc(EsF64)?); - Ok(unsafe { transmute(bits) }) - } - fn read_f32(&mut self) -> DecodeResult { - let bits = doc_as_u32(self.next_doc(EsF32)?); - Ok(unsafe { transmute(bits) }) - } - fn read_char(&mut self) -> DecodeResult { - Ok(char::from_u32(doc_as_u32(self.next_doc(EsChar)?)).unwrap()) - } - fn read_str(&mut self) -> DecodeResult { - Ok(self.next_doc(EsStr)?.to_string()) - } - - // Compound types: - fn read_enum(&mut self, name: &str, f: F) -> DecodeResult - where F: FnOnce(&mut Decoder<'doc>) -> DecodeResult - { - debug!("read_enum({})", name); - - let doc = self.next_doc(EsEnum)?; - - let (old_parent, old_pos) = (self.parent, self.pos); - self.parent = doc; - self.pos = self.parent.start; - - let result = f(self)?; - - self.parent = old_parent; - self.pos = old_pos; - Ok(result) - } - - fn read_enum_variant(&mut self, _: &[&str], mut f: F) -> DecodeResult - where F: FnMut(&mut Decoder<'doc>, usize) -> DecodeResult - { - debug!("read_enum_variant()"); - let idx = self._next_sub()?; - debug!(" idx={}", idx); - - f(self, idx) - } - - fn read_enum_variant_arg(&mut self, idx: usize, f: F) -> DecodeResult - where F: FnOnce(&mut Decoder<'doc>) -> DecodeResult - { - debug!("read_enum_variant_arg(idx={})", idx); - f(self) - } - - fn read_enum_struct_variant(&mut self, _: &[&str], mut f: F) -> DecodeResult - where F: FnMut(&mut Decoder<'doc>, usize) -> DecodeResult - { - debug!("read_enum_struct_variant()"); - let idx = self._next_sub()?; - debug!(" idx={}", idx); - - f(self, idx) - } - - fn read_enum_struct_variant_field(&mut self, - name: &str, - idx: usize, - f: F) - -> DecodeResult - where F: FnOnce(&mut Decoder<'doc>) -> DecodeResult - { - debug!("read_enum_struct_variant_arg(name={}, idx={})", name, idx); - f(self) - } - - fn read_struct(&mut self, name: &str, _: usize, f: F) -> DecodeResult - where F: FnOnce(&mut Decoder<'doc>) -> DecodeResult - { - debug!("read_struct(name={})", name); - f(self) - } - - fn read_struct_field(&mut self, name: &str, idx: usize, f: F) -> DecodeResult - where F: FnOnce(&mut Decoder<'doc>) -> DecodeResult - { - debug!("read_struct_field(name={}, idx={})", name, idx); - f(self) - } - - fn read_tuple(&mut self, tuple_len: usize, f: F) -> DecodeResult - where F: FnOnce(&mut Decoder<'doc>) -> DecodeResult - { - debug!("read_tuple()"); - self.read_seq(move |d, len| { - if len == tuple_len { - f(d) - } else { - Err(Expected(format!("Expected tuple of length `{}`, found tuple of length \ - `{}`", - tuple_len, - len))) - } - }) - } - - fn read_tuple_arg(&mut self, idx: usize, f: F) -> DecodeResult - where F: FnOnce(&mut Decoder<'doc>) -> DecodeResult - { - debug!("read_tuple_arg(idx={})", idx); - self.read_seq_elt(idx, f) - } - - fn read_tuple_struct(&mut self, name: &str, len: usize, f: F) -> DecodeResult - where F: FnOnce(&mut Decoder<'doc>) -> DecodeResult - { - debug!("read_tuple_struct(name={})", name); - self.read_tuple(len, f) - } - - fn read_tuple_struct_arg(&mut self, idx: usize, f: F) -> DecodeResult - where F: FnOnce(&mut Decoder<'doc>) -> DecodeResult - { - debug!("read_tuple_struct_arg(idx={})", idx); - self.read_tuple_arg(idx, f) - } - - fn read_option(&mut self, mut f: F) -> DecodeResult - where F: FnMut(&mut Decoder<'doc>, bool) -> DecodeResult - { - debug!("read_option()"); - self.read_enum("Option", move |this| { - this.read_enum_variant(&["None", "Some"], move |this, idx| { - match idx { - 0 => f(this, false), - 1 => f(this, true), - _ => Err(Expected(format!("Expected None or Some"))), - } - }) - }) - } - - fn read_seq(&mut self, f: F) -> DecodeResult - where F: FnOnce(&mut Decoder<'doc>, usize) -> DecodeResult - { - debug!("read_seq()"); - self.push_doc(EsVec, move |d| { - let len = d._next_sub()?; - debug!(" len={}", len); - f(d, len) - }) - } - - fn read_seq_elt(&mut self, idx: usize, f: F) -> DecodeResult - where F: FnOnce(&mut Decoder<'doc>) -> DecodeResult - { - debug!("read_seq_elt(idx={})", idx); - self.push_doc(EsVecElt, f) - } - - fn read_map(&mut self, f: F) -> DecodeResult - where F: FnOnce(&mut Decoder<'doc>, usize) -> DecodeResult - { - debug!("read_map()"); - self.push_doc(EsMap, move |d| { - let len = d._next_sub()?; - debug!(" len={}", len); - f(d, len) - }) - } - - fn read_map_elt_key(&mut self, idx: usize, f: F) -> DecodeResult - where F: FnOnce(&mut Decoder<'doc>) -> DecodeResult - { - debug!("read_map_elt_key(idx={})", idx); - self.push_doc(EsMapKey, f) - } - - fn read_map_elt_val(&mut self, idx: usize, f: F) -> DecodeResult - where F: FnOnce(&mut Decoder<'doc>) -> DecodeResult - { - debug!("read_map_elt_val(idx={})", idx); - self.push_doc(EsMapVal, f) - } - - fn error(&mut self, err: &str) -> Error { - ApplicationError(err.to_string()) - } - } -} - -pub mod writer { - use std::mem; - use std::io::prelude::*; - use std::io::{self, SeekFrom, Cursor}; - - use super::opaque; - use super::{EsVec, EsMap, EsEnum, EsSub8, EsSub32, EsVecElt, EsMapKey, EsU64, EsU32, EsU16, - EsU8, EsI64, EsI32, EsI16, EsI8, EsBool, EsF64, EsF32, EsChar, EsStr, EsMapVal, - EsOpaque, NUM_IMPLICIT_TAGS, NUM_TAGS}; - - use serialize; - - - pub type EncodeResult = io::Result<()>; - - // rbml writing - pub struct Encoder<'a> { - pub writer: &'a mut Cursor>, - size_positions: Vec, - relax_limit: u64, // do not move encoded bytes before this position - } - - fn write_tag(w: &mut W, n: usize) -> EncodeResult { - if n < 0xf0 { - w.write_all(&[n as u8]) - } else if 0x100 <= n && n < NUM_TAGS { - w.write_all(&[0xf0 | (n >> 8) as u8, n as u8]) - } else { - Err(io::Error::new(io::ErrorKind::Other, &format!("invalid tag: {}", n)[..])) - } - } - - fn write_sized_vuint(w: &mut W, n: usize, size: usize) -> EncodeResult { - match size { - 1 => w.write_all(&[0x80 | (n as u8)]), - 2 => w.write_all(&[0x40 | ((n >> 8) as u8), n as u8]), - 3 => w.write_all(&[0x20 | ((n >> 16) as u8), (n >> 8) as u8, n as u8]), - 4 => w.write_all(&[0x10 | ((n >> 24) as u8), (n >> 16) as u8, (n >> 8) as u8, n as u8]), - _ => Err(io::Error::new(io::ErrorKind::Other, &format!("isize too big: {}", n)[..])), - } - } - - pub fn write_vuint(w: &mut W, n: usize) -> EncodeResult { - if n < 0x7f { - return write_sized_vuint(w, n, 1); - } - if n < 0x4000 { - return write_sized_vuint(w, n, 2); - } - if n < 0x200000 { - return write_sized_vuint(w, n, 3); - } - if n < 0x10000000 { - return write_sized_vuint(w, n, 4); - } - Err(io::Error::new(io::ErrorKind::Other, &format!("isize too big: {}", n)[..])) - } - - impl<'a> Encoder<'a> { - pub fn new(w: &'a mut Cursor>) -> Encoder<'a> { - Encoder { - writer: w, - size_positions: vec![], - relax_limit: 0, - } - } - - pub fn start_tag(&mut self, tag_id: usize) -> EncodeResult { - debug!("Start tag {:?}", tag_id); - assert!(tag_id >= NUM_IMPLICIT_TAGS); - - // Write the enum ID: - write_tag(self.writer, tag_id)?; - - // Write a placeholder four-byte size. - let cur_pos = self.writer.seek(SeekFrom::Current(0))?; - self.size_positions.push(cur_pos); - let zeroes: &[u8] = &[0, 0, 0, 0]; - self.writer.write_all(zeroes) - } - - pub fn end_tag(&mut self) -> EncodeResult { - let last_size_pos = self.size_positions.pop().unwrap(); - let cur_pos = self.writer.seek(SeekFrom::Current(0))?; - self.writer.seek(SeekFrom::Start(last_size_pos))?; - let size = (cur_pos - last_size_pos - 4) as usize; - - // relax the size encoding for small tags (bigger tags are costly to move). - // we should never try to move the stable positions, however. - const RELAX_MAX_SIZE: usize = 0x100; - if size <= RELAX_MAX_SIZE && last_size_pos >= self.relax_limit { - // we can't alter the buffer in place, so have a temporary buffer - let mut buf = [0u8; RELAX_MAX_SIZE]; - { - let last_size_pos = last_size_pos as usize; - let data = &self.writer.get_ref()[last_size_pos + 4..cur_pos as usize]; - buf[..size].copy_from_slice(data); - } - - // overwrite the size and data and continue - write_vuint(self.writer, size)?; - self.writer.write_all(&buf[..size])?; - } else { - // overwrite the size with an overlong encoding and skip past the data - write_sized_vuint(self.writer, size, 4)?; - self.writer.seek(SeekFrom::Start(cur_pos))?; - } - - debug!("End tag (size = {:?})", size); - Ok(()) - } - - pub fn wr_tag(&mut self, tag_id: usize, blk: F) -> EncodeResult - where F: FnOnce() -> EncodeResult - { - self.start_tag(tag_id)?; - blk()?; - self.end_tag() - } - - pub fn wr_tagged_bytes(&mut self, tag_id: usize, b: &[u8]) -> EncodeResult { - assert!(tag_id >= NUM_IMPLICIT_TAGS); - write_tag(self.writer, tag_id)?; - write_vuint(self.writer, b.len())?; - self.writer.write_all(b) - } - - pub fn wr_tagged_u64(&mut self, tag_id: usize, v: u64) -> EncodeResult { - let bytes: [u8; 8] = unsafe { mem::transmute(v.to_be()) }; - // tagged integers are emitted in big-endian, with no - // leading zeros. - let leading_zero_bytes = v.leading_zeros() / 8; - self.wr_tagged_bytes(tag_id, &bytes[leading_zero_bytes as usize..]) - } - - #[inline] - pub fn wr_tagged_u32(&mut self, tag_id: usize, v: u32) -> EncodeResult { - self.wr_tagged_u64(tag_id, v as u64) - } - - #[inline] - pub fn wr_tagged_u16(&mut self, tag_id: usize, v: u16) -> EncodeResult { - self.wr_tagged_u64(tag_id, v as u64) - } - - #[inline] - pub fn wr_tagged_u8(&mut self, tag_id: usize, v: u8) -> EncodeResult { - self.wr_tagged_bytes(tag_id, &[v]) - } - - #[inline] - pub fn wr_tagged_i64(&mut self, tag_id: usize, v: i64) -> EncodeResult { - self.wr_tagged_u64(tag_id, v as u64) - } - - #[inline] - pub fn wr_tagged_i32(&mut self, tag_id: usize, v: i32) -> EncodeResult { - self.wr_tagged_u32(tag_id, v as u32) - } - - #[inline] - pub fn wr_tagged_i16(&mut self, tag_id: usize, v: i16) -> EncodeResult { - self.wr_tagged_u16(tag_id, v as u16) - } - - #[inline] - pub fn wr_tagged_i8(&mut self, tag_id: usize, v: i8) -> EncodeResult { - self.wr_tagged_bytes(tag_id, &[v as u8]) - } - - pub fn wr_tagged_str(&mut self, tag_id: usize, v: &str) -> EncodeResult { - self.wr_tagged_bytes(tag_id, v.as_bytes()) - } - - // for auto-serialization - fn wr_tagged_raw_bytes(&mut self, tag_id: usize, b: &[u8]) -> EncodeResult { - write_tag(self.writer, tag_id)?; - self.writer.write_all(b) - } - - fn wr_tagged_raw_u64(&mut self, tag_id: usize, v: u64) -> EncodeResult { - let bytes: [u8; 8] = unsafe { mem::transmute(v.to_be()) }; - self.wr_tagged_raw_bytes(tag_id, &bytes) - } - - fn wr_tagged_raw_u32(&mut self, tag_id: usize, v: u32) -> EncodeResult { - let bytes: [u8; 4] = unsafe { mem::transmute(v.to_be()) }; - self.wr_tagged_raw_bytes(tag_id, &bytes) - } - - fn wr_tagged_raw_u16(&mut self, tag_id: usize, v: u16) -> EncodeResult { - let bytes: [u8; 2] = unsafe { mem::transmute(v.to_be()) }; - self.wr_tagged_raw_bytes(tag_id, &bytes) - } - - fn wr_tagged_raw_u8(&mut self, tag_id: usize, v: u8) -> EncodeResult { - self.wr_tagged_raw_bytes(tag_id, &[v]) - } - - fn wr_tagged_raw_i64(&mut self, tag_id: usize, v: i64) -> EncodeResult { - self.wr_tagged_raw_u64(tag_id, v as u64) - } - - fn wr_tagged_raw_i32(&mut self, tag_id: usize, v: i32) -> EncodeResult { - self.wr_tagged_raw_u32(tag_id, v as u32) - } - - fn wr_tagged_raw_i16(&mut self, tag_id: usize, v: i16) -> EncodeResult { - self.wr_tagged_raw_u16(tag_id, v as u16) - } - - fn wr_tagged_raw_i8(&mut self, tag_id: usize, v: i8) -> EncodeResult { - self.wr_tagged_raw_bytes(tag_id, &[v as u8]) - } - - pub fn wr_bytes(&mut self, b: &[u8]) -> EncodeResult { - debug!("Write {:?} bytes", b.len()); - self.writer.write_all(b) - } - - pub fn wr_str(&mut self, s: &str) -> EncodeResult { - debug!("Write str: {:?}", s); - self.writer.write_all(s.as_bytes()) - } - - /// Returns the current position while marking it stable, i.e. - /// generated bytes so far wouldn't be affected by relaxation. - pub fn mark_stable_position(&mut self) -> u64 { - let pos = self.writer.seek(SeekFrom::Current(0)).unwrap(); - if self.relax_limit < pos { - self.relax_limit = pos; - } - pos - } - } - - impl<'a> Encoder<'a> { - // used internally to emit things like the vector length and so on - fn _emit_tagged_sub(&mut self, v: usize) -> EncodeResult { - if v as u8 as usize == v { - self.wr_tagged_raw_u8(EsSub8 as usize, v as u8) - } else if v as u32 as usize == v { - self.wr_tagged_raw_u32(EsSub32 as usize, v as u32) - } else { - Err(io::Error::new(io::ErrorKind::Other, - &format!("length or variant id too big: {}", v)[..])) - } - } - - pub fn emit_opaque(&mut self, f: F) -> EncodeResult - where F: FnOnce(&mut opaque::Encoder) -> EncodeResult - { - self.start_tag(EsOpaque as usize)?; - - { - let mut opaque_encoder = opaque::Encoder::new(self.writer); - f(&mut opaque_encoder)?; - } - - self.mark_stable_position(); - self.end_tag() - } - } - - impl<'a> serialize::Encoder for Encoder<'a> { - type Error = io::Error; - - fn emit_nil(&mut self) -> EncodeResult { - Ok(()) - } - - fn emit_usize(&mut self, v: usize) -> EncodeResult { - self.emit_u64(v as u64) - } - fn emit_u64(&mut self, v: u64) -> EncodeResult { - if v as u32 as u64 == v { - self.emit_u32(v as u32) - } else { - self.wr_tagged_raw_u64(EsU64 as usize, v) - } - } - fn emit_u32(&mut self, v: u32) -> EncodeResult { - if v as u16 as u32 == v { - self.emit_u16(v as u16) - } else { - self.wr_tagged_raw_u32(EsU32 as usize, v) - } - } - fn emit_u16(&mut self, v: u16) -> EncodeResult { - if v as u8 as u16 == v { - self.emit_u8(v as u8) - } else { - self.wr_tagged_raw_u16(EsU16 as usize, v) - } - } - fn emit_u8(&mut self, v: u8) -> EncodeResult { - self.wr_tagged_raw_u8(EsU8 as usize, v) - } - - fn emit_isize(&mut self, v: isize) -> EncodeResult { - self.emit_i64(v as i64) - } - fn emit_i64(&mut self, v: i64) -> EncodeResult { - if v as i32 as i64 == v { - self.emit_i32(v as i32) - } else { - self.wr_tagged_raw_i64(EsI64 as usize, v) - } - } - fn emit_i32(&mut self, v: i32) -> EncodeResult { - if v as i16 as i32 == v { - self.emit_i16(v as i16) - } else { - self.wr_tagged_raw_i32(EsI32 as usize, v) - } - } - fn emit_i16(&mut self, v: i16) -> EncodeResult { - if v as i8 as i16 == v { - self.emit_i8(v as i8) - } else { - self.wr_tagged_raw_i16(EsI16 as usize, v) - } - } - fn emit_i8(&mut self, v: i8) -> EncodeResult { - self.wr_tagged_raw_i8(EsI8 as usize, v) - } - - fn emit_bool(&mut self, v: bool) -> EncodeResult { - self.wr_tagged_raw_u8(EsBool as usize, v as u8) - } - - fn emit_f64(&mut self, v: f64) -> EncodeResult { - let bits = unsafe { mem::transmute(v) }; - self.wr_tagged_raw_u64(EsF64 as usize, bits) - } - fn emit_f32(&mut self, v: f32) -> EncodeResult { - let bits = unsafe { mem::transmute(v) }; - self.wr_tagged_raw_u32(EsF32 as usize, bits) - } - fn emit_char(&mut self, v: char) -> EncodeResult { - self.wr_tagged_raw_u32(EsChar as usize, v as u32) - } - - fn emit_str(&mut self, v: &str) -> EncodeResult { - self.wr_tagged_str(EsStr as usize, v) - } - - fn emit_enum(&mut self, _name: &str, f: F) -> EncodeResult - where F: FnOnce(&mut Encoder<'a>) -> EncodeResult - { - self.start_tag(EsEnum as usize)?; - f(self)?; - self.end_tag() - } - - fn emit_enum_variant(&mut self, _: &str, v_id: usize, _: usize, f: F) -> EncodeResult - where F: FnOnce(&mut Encoder<'a>) -> EncodeResult - { - self._emit_tagged_sub(v_id)?; - f(self) - } - - fn emit_enum_variant_arg(&mut self, _: usize, f: F) -> EncodeResult - where F: FnOnce(&mut Encoder<'a>) -> EncodeResult - { - f(self) - } - - fn emit_enum_struct_variant(&mut self, - v_name: &str, - v_id: usize, - cnt: usize, - f: F) - -> EncodeResult - where F: FnOnce(&mut Encoder<'a>) -> EncodeResult - { - self.emit_enum_variant(v_name, v_id, cnt, f) - } - - fn emit_enum_struct_variant_field(&mut self, _: &str, idx: usize, f: F) -> EncodeResult - where F: FnOnce(&mut Encoder<'a>) -> EncodeResult - { - self.emit_enum_variant_arg(idx, f) - } - - fn emit_struct(&mut self, _: &str, _len: usize, f: F) -> EncodeResult - where F: FnOnce(&mut Encoder<'a>) -> EncodeResult - { - f(self) - } - - fn emit_struct_field(&mut self, _name: &str, _: usize, f: F) -> EncodeResult - where F: FnOnce(&mut Encoder<'a>) -> EncodeResult - { - f(self) - } - - fn emit_tuple(&mut self, len: usize, f: F) -> EncodeResult - where F: FnOnce(&mut Encoder<'a>) -> EncodeResult - { - self.emit_seq(len, f) - } - fn emit_tuple_arg(&mut self, idx: usize, f: F) -> EncodeResult - where F: FnOnce(&mut Encoder<'a>) -> EncodeResult - { - self.emit_seq_elt(idx, f) - } - - fn emit_tuple_struct(&mut self, _: &str, len: usize, f: F) -> EncodeResult - where F: FnOnce(&mut Encoder<'a>) -> EncodeResult - { - self.emit_seq(len, f) - } - fn emit_tuple_struct_arg(&mut self, idx: usize, f: F) -> EncodeResult - where F: FnOnce(&mut Encoder<'a>) -> EncodeResult - { - self.emit_seq_elt(idx, f) - } - - fn emit_option(&mut self, f: F) -> EncodeResult - where F: FnOnce(&mut Encoder<'a>) -> EncodeResult - { - self.emit_enum("Option", f) - } - fn emit_option_none(&mut self) -> EncodeResult { - self.emit_enum_variant("None", 0, 0, |_| Ok(())) - } - fn emit_option_some(&mut self, f: F) -> EncodeResult - where F: FnOnce(&mut Encoder<'a>) -> EncodeResult - { - - self.emit_enum_variant("Some", 1, 1, f) - } - - fn emit_seq(&mut self, len: usize, f: F) -> EncodeResult - where F: FnOnce(&mut Encoder<'a>) -> EncodeResult - { - if len == 0 { - // empty vector optimization - return self.wr_tagged_bytes(EsVec as usize, &[]); - } - - self.start_tag(EsVec as usize)?; - self._emit_tagged_sub(len)?; - f(self)?; - self.end_tag() - } - - fn emit_seq_elt(&mut self, _idx: usize, f: F) -> EncodeResult - where F: FnOnce(&mut Encoder<'a>) -> EncodeResult - { - - self.start_tag(EsVecElt as usize)?; - f(self)?; - self.end_tag() - } - - fn emit_map(&mut self, len: usize, f: F) -> EncodeResult - where F: FnOnce(&mut Encoder<'a>) -> EncodeResult - { - if len == 0 { - // empty map optimization - return self.wr_tagged_bytes(EsMap as usize, &[]); - } - - self.start_tag(EsMap as usize)?; - self._emit_tagged_sub(len)?; - f(self)?; - self.end_tag() - } - - fn emit_map_elt_key(&mut self, _idx: usize, f: F) -> EncodeResult - where F: FnOnce(&mut Encoder<'a>) -> EncodeResult - { - - self.start_tag(EsMapKey as usize)?; - f(self)?; - self.end_tag() - } - - fn emit_map_elt_val(&mut self, _idx: usize, f: F) -> EncodeResult - where F: FnOnce(&mut Encoder<'a>) -> EncodeResult - { - self.start_tag(EsMapVal as usize)?; - f(self)?; - self.end_tag() - } - } -} - -// ___________________________________________________________________________ -// Testing - -#[cfg(test)] -mod tests { - use super::{Doc, reader, writer}; - - use serialize::{Encodable, Decodable}; - - use std::io::Cursor; - - #[test] - fn test_vuint_at() { - let data = &[ - 0x80, - 0xff, - 0x40, 0x00, - 0x7f, 0xff, - 0x20, 0x00, 0x00, - 0x3f, 0xff, 0xff, - 0x10, 0x00, 0x00, 0x00, - 0x1f, 0xff, 0xff, 0xff - ]; - - let mut res: reader::Res; - - // Class A - res = reader::vuint_at(data, 0).unwrap(); - assert_eq!(res.val, 0); - assert_eq!(res.next, 1); - res = reader::vuint_at(data, res.next).unwrap(); - assert_eq!(res.val, (1 << 7) - 1); - assert_eq!(res.next, 2); - - // Class B - res = reader::vuint_at(data, res.next).unwrap(); - assert_eq!(res.val, 0); - assert_eq!(res.next, 4); - res = reader::vuint_at(data, res.next).unwrap(); - assert_eq!(res.val, (1 << 14) - 1); - assert_eq!(res.next, 6); - - // Class C - res = reader::vuint_at(data, res.next).unwrap(); - assert_eq!(res.val, 0); - assert_eq!(res.next, 9); - res = reader::vuint_at(data, res.next).unwrap(); - assert_eq!(res.val, (1 << 21) - 1); - assert_eq!(res.next, 12); - - // Class D - res = reader::vuint_at(data, res.next).unwrap(); - assert_eq!(res.val, 0); - assert_eq!(res.next, 16); - res = reader::vuint_at(data, res.next).unwrap(); - assert_eq!(res.val, (1 << 28) - 1); - assert_eq!(res.next, 20); - } - - #[test] - fn test_option_int() { - fn test_v(v: Option) { - debug!("v == {:?}", v); - let mut wr = Cursor::new(Vec::new()); - { - let mut rbml_w = writer::Encoder::new(&mut wr); - let _ = v.encode(&mut rbml_w); - } - let rbml_doc = Doc::new(wr.get_ref()); - let mut deser = reader::Decoder::new(rbml_doc); - let v1 = Decodable::decode(&mut deser).unwrap(); - debug!("v1 == {:?}", v1); - assert_eq!(v, v1); - } - - test_v(Some(22)); - test_v(None); - test_v(Some(3)); - } -} - -#[cfg(test)] -mod bench { - #![allow(non_snake_case)] - use test::Bencher; - use super::reader; - - #[bench] - pub fn vuint_at_A_aligned(b: &mut Bencher) { - let data = (0..4 * 100) - .map(|i| { - match i % 2 { - 0 => 0x80, - _ => i as u8, - } - }) - .collect::>(); - let mut sum = 0; - b.iter(|| { - let mut i = 0; - while i < data.len() { - sum += reader::vuint_at(&data, i).unwrap().val; - i += 4; - } - }); - } - - #[bench] - pub fn vuint_at_A_unaligned(b: &mut Bencher) { - let data = (0..4 * 100 + 1) - .map(|i| { - match i % 2 { - 1 => 0x80, - _ => i as u8, - } - }) - .collect::>(); - let mut sum = 0; - b.iter(|| { - let mut i = 1; - while i < data.len() { - sum += reader::vuint_at(&data, i).unwrap().val; - i += 4; - } - }); - } - - #[bench] - pub fn vuint_at_D_aligned(b: &mut Bencher) { - let data = (0..4 * 100) - .map(|i| { - match i % 4 { - 0 => 0x10, - 3 => i as u8, - _ => 0, - } - }) - .collect::>(); - let mut sum = 0; - b.iter(|| { - let mut i = 0; - while i < data.len() { - sum += reader::vuint_at(&data, i).unwrap().val; - i += 4; - } - }); - } - - #[bench] - pub fn vuint_at_D_unaligned(b: &mut Bencher) { - let data = (0..4 * 100 + 1) - .map(|i| { - match i % 4 { - 1 => 0x10, - 0 => i as u8, - _ => 0, - } - }) - .collect::>(); - let mut sum = 0; - b.iter(|| { - let mut i = 1; - while i < data.len() { - sum += reader::vuint_at(&data, i).unwrap().val; - i += 4; - } - }); - } -} diff --git a/src/librbml/opaque.rs b/src/librbml/opaque.rs index 6dc7a72b1b1b..55ab2afe4454 100644 --- a/src/librbml/opaque.rs +++ b/src/librbml/opaque.rs @@ -9,7 +9,6 @@ // except according to those terms. use Error as DecodeError; -use writer::EncodeResult; use leb128::{read_signed_leb128, read_unsigned_leb128, write_signed_leb128, write_unsigned_leb128}; use std::io::{self, Write}; use serialize; @@ -18,6 +17,8 @@ use serialize; // Encoder // ----------------------------------------------------------------------------- +pub type EncodeResult = io::Result<()>; + pub struct Encoder<'a> { pub cursor: &'a mut io::Cursor>, } @@ -255,10 +256,6 @@ impl<'a> Encoder<'a> { pub fn position(&self) -> usize { self.cursor.position() as usize } - - pub fn from_rbml<'b: 'c, 'c>(rbml: &'c mut ::writer::Encoder<'b>) -> Encoder<'c> { - Encoder { cursor: rbml.writer } - } } // ----------------------------------------------------------------------------- diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs index 9fb619340098..d0d3d822f860 100644 --- a/src/librustc_metadata/lib.rs +++ b/src/librustc_metadata/lib.rs @@ -27,13 +27,13 @@ #![feature(rustc_macro_internals)] #![feature(rustc_private)] #![feature(staged_api)] +#![cfg_attr(test, feature(test))] #[macro_use] extern crate log; #[macro_use] extern crate syntax; #[macro_use] #[no_link] extern crate rustc_bitflags; extern crate syntax_pos; extern crate flate; -extern crate rbml; extern crate serialize as rustc_serialize; // used by deriving extern crate rustc_errors as errors; extern crate syntax_ext; @@ -46,6 +46,18 @@ extern crate rustc_llvm; extern crate rustc_macro; extern crate rustc_const_math; +#[cfg(test)] +extern crate test; + +pub mod rbml { + pub extern crate rbml as rbml_crate; + pub use self::rbml_crate::{Error, leb128, opaque}; + + pub mod writer; + pub mod reader; + pub use self::reader::Doc; +} + pub use rustc::middle; #[macro_use] diff --git a/src/librustc_metadata/rbml/reader.rs b/src/librustc_metadata/rbml/reader.rs new file mode 100644 index 000000000000..0950372477e4 --- /dev/null +++ b/src/librustc_metadata/rbml/reader.rs @@ -0,0 +1,1025 @@ +// Copyright 2012-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. + +//! Really Bad Markup Language (rbml) is an internal serialization format of rustc. +//! This is not intended to be used by users. +//! +//! Originally based on the Extensible Binary Markup Language +//! (ebml; http://www.matroska.org/technical/specs/rfc/index.html), +//! it is now a separate format tuned for the rust object metadata. +//! +//! # Encoding +//! +//! RBML document consists of the tag, length and data. +//! The encoded data can contain multiple RBML documents concatenated. +//! +//! **Tags** are a hint for the following data. +//! Tags are a number from 0x000 to 0xfff, where 0xf0 through 0xff is reserved. +//! Tags less than 0xf0 are encoded in one literal byte. +//! Tags greater than 0xff are encoded in two big-endian bytes, +//! where the tag number is ORed with 0xf000. (E.g. tag 0x123 = `f1 23`) +//! +//! **Lengths** encode the length of the following data. +//! It is a variable-length unsigned isize, and one of the following forms: +//! +//! - `80` through `fe` for lengths up to 0x7e; +//! - `40 ff` through `7f ff` for lengths up to 0x3fff; +//! - `20 40 00` through `3f ff ff` for lengths up to 0x1fffff; +//! - `10 20 00 00` through `1f ff ff ff` for lengths up to 0xfffffff. +//! +//! The "overlong" form is allowed so that the length can be encoded +//! without the prior knowledge of the encoded data. +//! For example, the length 0 can be represented either by `80`, `40 00`, +//! `20 00 00` or `10 00 00 00`. +//! The encoder tries to minimize the length if possible. +//! Also, some predefined tags listed below are so commonly used that +//! their lengths are omitted ("implicit length"). +//! +//! **Data** can be either binary bytes or zero or more nested RBML documents. +//! Nested documents cannot overflow, and should be entirely contained +//! within a parent document. +//! +//! # Predefined Tags +//! +//! Most RBML tags are defined by the application. +//! (For the rust object metadata, see also `rustc::metadata::common`.) +//! RBML itself does define a set of predefined tags however, +//! intended for the auto-serialization implementation. +//! +//! Predefined tags with an implicit length: +//! +//! - `U8` (`00`): 1-byte unsigned integer. +//! - `U16` (`01`): 2-byte big endian unsigned integer. +//! - `U32` (`02`): 4-byte big endian unsigned integer. +//! - `U64` (`03`): 8-byte big endian unsigned integer. +//! Any of `U*` tags can be used to encode primitive unsigned integer types, +//! as long as it is no greater than the actual size. +//! For example, `u8` can only be represented via the `U8` tag. +//! +//! - `I8` (`04`): 1-byte signed integer. +//! - `I16` (`05`): 2-byte big endian signed integer. +//! - `I32` (`06`): 4-byte big endian signed integer. +//! - `I64` (`07`): 8-byte big endian signed integer. +//! Similar to `U*` tags. Always uses two's complement encoding. +//! +//! - `Bool` (`08`): 1-byte boolean value, `00` for false and `01` for true. +//! +//! - `Char` (`09`): 4-byte big endian Unicode scalar value. +//! Surrogate pairs or out-of-bound values are invalid. +//! +//! - `F32` (`0a`): 4-byte big endian unsigned integer representing +//! IEEE 754 binary32 floating-point format. +//! - `F64` (`0b`): 8-byte big endian unsigned integer representing +//! IEEE 754 binary64 floating-point format. +//! +//! - `Sub8` (`0c`): 1-byte unsigned integer for supplementary information. +//! - `Sub32` (`0d`): 4-byte unsigned integer for supplementary information. +//! Those two tags normally occur as the first subdocument of certain tags, +//! namely `Enum`, `Vec` and `Map`, to provide a variant or size information. +//! They can be used interchangeably. +//! +//! Predefined tags with an explicit length: +//! +//! - `Str` (`10`): A UTF-8-encoded string. +//! +//! - `Enum` (`11`): An enum. +//! The first subdocument should be `Sub*` tags with a variant ID. +//! Subsequent subdocuments, if any, encode variant arguments. +//! +//! - `Vec` (`12`): A vector (sequence). +//! - `VecElt` (`13`): A vector element. +//! The first subdocument should be `Sub*` tags with the number of elements. +//! Subsequent subdocuments should be `VecElt` tag per each element. +//! +//! - `Map` (`14`): A map (associated array). +//! - `MapKey` (`15`): A key part of the map entry. +//! - `MapVal` (`16`): A value part of the map entry. +//! The first subdocument should be `Sub*` tags with the number of entries. +//! Subsequent subdocuments should be an alternating sequence of +//! `MapKey` and `MapVal` tags per each entry. +//! +//! - `Opaque` (`17`): An opaque, custom-format tag. +//! Used to wrap ordinary custom tags or data in the auto-serialized context. +//! Rustc typically uses this to encode type information. +//! +//! First 0x20 tags are reserved by RBML; custom tags start at 0x20. + +#[cfg(test)] +use test::Bencher; + +pub use self::EbmlEncoderTag::*; + +use std::char; +use std::isize; +use std::mem::transmute; +use std::str; + +use rustc_serialize as serialize; + +use rbml::opaque; +use rbml::Error; +use rbml::Error::*; + +#[derive(Clone, Copy)] +pub struct Doc<'a> { + pub data: &'a [u8], + pub start: usize, + pub end: usize, +} + +impl<'doc> Doc<'doc> { + pub fn new(data: &'doc [u8]) -> Doc<'doc> { + Doc { + data: data, + start: 0, + end: data.len(), + } + } + + pub fn get(&self, tag: usize) -> Doc<'doc> { + get_doc(*self, tag) + } + + pub fn is_empty(&self) -> bool { + self.start == self.end + } + + pub fn as_str(&self) -> &'doc str { + str::from_utf8(&self.data[self.start..self.end]).unwrap() + } + + pub fn to_string(&self) -> String { + self.as_str().to_string() + } +} + +pub struct TaggedDoc<'a> { + tag: usize, + pub doc: Doc<'a>, +} + +pub type DecodeResult = Result; + +#[derive(Copy, Clone, Debug)] +pub enum EbmlEncoderTag { + // tags 00..1f are reserved for auto-serialization. + // first NUM_IMPLICIT_TAGS tags are implicitly sized and lengths are not encoded. + EsU8 = 0x00, // + 1 byte + EsU16 = 0x01, // + 2 bytes + EsU32 = 0x02, // + 4 bytes + EsU64 = 0x03, // + 8 bytes + EsI8 = 0x04, // + 1 byte + EsI16 = 0x05, // + 2 bytes + EsI32 = 0x06, // + 4 bytes + EsI64 = 0x07, // + 8 bytes + EsBool = 0x08, // + 1 byte + EsChar = 0x09, // + 4 bytes + EsF32 = 0x0a, // + 4 bytes + EsF64 = 0x0b, // + 8 bytes + EsSub8 = 0x0c, // + 1 byte + EsSub32 = 0x0d, // + 4 bytes + // 0x0e and 0x0f are reserved + EsStr = 0x10, + EsEnum = 0x11, // encodes the variant id as the first EsSub* + EsVec = 0x12, // encodes the # of elements as the first EsSub* + EsVecElt = 0x13, + EsMap = 0x14, // encodes the # of pairs as the first EsSub* + EsMapKey = 0x15, + EsMapVal = 0x16, + EsOpaque = 0x17, +} + +pub const NUM_IMPLICIT_TAGS: usize = 0x0e; + +#[cfg_attr(rustfmt, rustfmt_skip)] +static TAG_IMPLICIT_LEN: [i8; NUM_IMPLICIT_TAGS] = [ + 1, 2, 4, 8, // EsU* + 1, 2, 4, 8, // ESI* + 1, // EsBool + 4, // EsChar + 4, 8, // EsF* + 1, 4, // EsSub* +]; + +// rbml reading + +macro_rules! try_or { + ($e:expr, $r:expr) => ( + match $e { + Ok(e) => e, + Err(e) => { + debug!("ignored error: {:?}", e); + return $r + } + } + ) +} + +#[derive(Copy, Clone)] +pub struct Res { + pub val: usize, + pub next: usize, +} + +pub fn tag_at(data: &[u8], start: usize) -> DecodeResult { + let v = data[start] as usize; + if v < 0xf0 { + Ok(Res { + val: v, + next: start + 1, + }) + } else if v > 0xf0 { + Ok(Res { + val: ((v & 0xf) << 8) | data[start + 1] as usize, + next: start + 2, + }) + } else { + // every tag starting with byte 0xf0 is an overlong form, which is prohibited. + Err(InvalidTag(v)) + } +} + +#[inline(never)] +fn vuint_at_slow(data: &[u8], start: usize) -> DecodeResult { + let a = data[start]; + if a & 0x80 != 0 { + return Ok(Res { + val: (a & 0x7f) as usize, + next: start + 1, + }); + } + if a & 0x40 != 0 { + return Ok(Res { + val: ((a & 0x3f) as usize) << 8 | (data[start + 1] as usize), + next: start + 2, + }); + } + if a & 0x20 != 0 { + return Ok(Res { + val: ((a & 0x1f) as usize) << 16 | (data[start + 1] as usize) << 8 | + (data[start + 2] as usize), + next: start + 3, + }); + } + if a & 0x10 != 0 { + return Ok(Res { + val: ((a & 0x0f) as usize) << 24 | (data[start + 1] as usize) << 16 | + (data[start + 2] as usize) << 8 | + (data[start + 3] as usize), + next: start + 4, + }); + } + Err(IntTooBig(a as usize)) +} + +pub fn vuint_at(data: &[u8], start: usize) -> DecodeResult { + if data.len() - start < 4 { + return vuint_at_slow(data, start); + } + + // Lookup table for parsing EBML Element IDs as per + // http://ebml.sourceforge.net/specs/ The Element IDs are parsed by + // reading a big endian u32 positioned at data[start]. Using the four + // most significant bits of the u32 we lookup in the table below how + // the element ID should be derived from it. + // + // The table stores tuples (shift, mask) where shift is the number the + // u32 should be right shifted with and mask is the value the right + // shifted value should be masked with. If for example the most + // significant bit is set this means it's a class A ID and the u32 + // should be right shifted with 24 and masked with 0x7f. Therefore we + // store (24, 0x7f) at index 0x8 - 0xF (four bit numbers where the most + // significant bit is set). + // + // By storing the number of shifts and masks in a table instead of + // checking in order if the most significant bit is set, the second + // most significant bit is set etc. we can replace up to three + // "and+branch" with a single table lookup which gives us a measured + // speedup of around 2x on x86_64. + static SHIFT_MASK_TABLE: [(usize, u32); 16] = [(0, 0x0), + (0, 0x0fffffff), + (8, 0x1fffff), + (8, 0x1fffff), + (16, 0x3fff), + (16, 0x3fff), + (16, 0x3fff), + (16, 0x3fff), + (24, 0x7f), + (24, 0x7f), + (24, 0x7f), + (24, 0x7f), + (24, 0x7f), + (24, 0x7f), + (24, 0x7f), + (24, 0x7f)]; + + unsafe { + let ptr = data.as_ptr().offset(start as isize) as *const u32; + let val = u32::from_be(*ptr); + + let i = (val >> 28) as usize; + let (shift, mask) = SHIFT_MASK_TABLE[i]; + Ok(Res { + val: ((val >> shift) & mask) as usize, + next: start + ((32 - shift) >> 3), + }) + } +} + +pub fn tag_len_at(data: &[u8], tag: Res) -> DecodeResult { + if tag.val < NUM_IMPLICIT_TAGS && TAG_IMPLICIT_LEN[tag.val] >= 0 { + Ok(Res { + val: TAG_IMPLICIT_LEN[tag.val] as usize, + next: tag.next, + }) + } else { + vuint_at(data, tag.next) + } +} + +pub fn doc_at<'a>(data: &'a [u8], start: usize) -> DecodeResult> { + let elt_tag = tag_at(data, start)?; + let elt_size = tag_len_at(data, elt_tag)?; + let end = elt_size.next + elt_size.val; + Ok(TaggedDoc { + tag: elt_tag.val, + doc: Doc { + data: data, + start: elt_size.next, + end: end, + }, + }) +} + +pub fn maybe_get_doc<'a>(d: Doc<'a>, tg: usize) -> Option> { + let mut pos = d.start; + while pos < d.end { + let elt_tag = try_or!(tag_at(d.data, pos), None); + let elt_size = try_or!(tag_len_at(d.data, elt_tag), None); + pos = elt_size.next + elt_size.val; + if elt_tag.val == tg { + return Some(Doc { + data: d.data, + start: elt_size.next, + end: pos, + }); + } + } + None +} + +pub fn get_doc<'a>(d: Doc<'a>, tg: usize) -> Doc<'a> { + match maybe_get_doc(d, tg) { + Some(d) => d, + None => { + error!("failed to find block with tag {:?}", tg); + panic!(); + } + } +} + +pub fn docs<'a>(d: Doc<'a>) -> DocsIterator<'a> { + DocsIterator { d: d } +} + +pub struct DocsIterator<'a> { + d: Doc<'a>, +} + +impl<'a> Iterator for DocsIterator<'a> { + type Item = (usize, Doc<'a>); + + fn next(&mut self) -> Option<(usize, Doc<'a>)> { + if self.d.start >= self.d.end { + return None; + } + + let elt_tag = try_or!(tag_at(self.d.data, self.d.start), { + self.d.start = self.d.end; + None + }); + let elt_size = try_or!(tag_len_at(self.d.data, elt_tag), { + self.d.start = self.d.end; + None + }); + + let end = elt_size.next + elt_size.val; + let doc = Doc { + data: self.d.data, + start: elt_size.next, + end: end, + }; + + self.d.start = end; + return Some((elt_tag.val, doc)); + } +} + +pub fn tagged_docs<'a>(d: Doc<'a>, tag: usize) -> TaggedDocsIterator<'a> { + TaggedDocsIterator { + iter: docs(d), + tag: tag, + } +} + +pub struct TaggedDocsIterator<'a> { + iter: DocsIterator<'a>, + tag: usize, +} + +impl<'a> Iterator for TaggedDocsIterator<'a> { + type Item = Doc<'a>; + + fn next(&mut self) -> Option> { + while let Some((tag, doc)) = self.iter.next() { + if tag == self.tag { + return Some(doc); + } + } + None + } +} + +pub fn with_doc_data(d: Doc, f: F) -> T + where F: FnOnce(&[u8]) -> T +{ + f(&d.data[d.start..d.end]) +} + +pub fn doc_as_u8(d: Doc) -> u8 { + assert_eq!(d.end, d.start + 1); + d.data[d.start] +} + +pub fn doc_as_u64(d: Doc) -> u64 { + if d.end >= 8 { + // For performance, we read 8 big-endian bytes, + // and mask off the junk if there is any. This + // obviously won't work on the first 8 bytes + // of a file - we will fall of the start + // of the page and segfault. + + let mut b = [0; 8]; + b.copy_from_slice(&d.data[d.end - 8..d.end]); + let data = unsafe { (*(b.as_ptr() as *const u64)).to_be() }; + let len = d.end - d.start; + if len < 8 { + data & ((1 << (len * 8)) - 1) + } else { + data + } + } else { + let mut result = 0; + for b in &d.data[d.start..d.end] { + result = (result << 8) + (*b as u64); + } + result + } +} + +#[inline] +pub fn doc_as_u16(d: Doc) -> u16 { + doc_as_u64(d) as u16 +} +#[inline] +pub fn doc_as_u32(d: Doc) -> u32 { + doc_as_u64(d) as u32 +} + +#[inline] +pub fn doc_as_i8(d: Doc) -> i8 { + doc_as_u8(d) as i8 +} +#[inline] +pub fn doc_as_i16(d: Doc) -> i16 { + doc_as_u16(d) as i16 +} +#[inline] +pub fn doc_as_i32(d: Doc) -> i32 { + doc_as_u32(d) as i32 +} +#[inline] +pub fn doc_as_i64(d: Doc) -> i64 { + doc_as_u64(d) as i64 +} + +pub struct Decoder<'a> { + parent: Doc<'a>, + pos: usize, +} + +impl<'doc> Decoder<'doc> { + pub fn new(d: Doc<'doc>) -> Decoder<'doc> { + Decoder { + parent: d, + pos: d.start, + } + } + + fn next_doc(&mut self, exp_tag: EbmlEncoderTag) -> DecodeResult> { + debug!(". next_doc(exp_tag={:?})", exp_tag); + if self.pos >= self.parent.end { + return Err(Expected(format!("no more documents in current node!"))); + } + let TaggedDoc { tag: r_tag, doc: r_doc } = doc_at(self.parent.data, self.pos)?; + debug!("self.parent={:?}-{:?} self.pos={:?} r_tag={:?} r_doc={:?}-{:?}", + self.parent.start, + self.parent.end, + self.pos, + r_tag, + r_doc.start, + r_doc.end); + if r_tag != (exp_tag as usize) { + return Err(Expected(format!("expected EBML doc with tag {:?} but found tag {:?}", + exp_tag, + r_tag))); + } + if r_doc.end > self.parent.end { + return Err(Expected(format!("invalid EBML, child extends to {:#x}, parent to \ + {:#x}", + r_doc.end, + self.parent.end))); + } + self.pos = r_doc.end; + Ok(r_doc) + } + + fn push_doc(&mut self, exp_tag: EbmlEncoderTag, f: F) -> DecodeResult + where F: FnOnce(&mut Decoder<'doc>) -> DecodeResult + { + let d = self.next_doc(exp_tag)?; + let old_parent = self.parent; + let old_pos = self.pos; + self.parent = d; + self.pos = d.start; + let r = f(self)?; + self.parent = old_parent; + self.pos = old_pos; + Ok(r) + } + + fn _next_sub(&mut self) -> DecodeResult { + // empty vector/map optimization + if self.parent.is_empty() { + return Ok(0); + } + + let TaggedDoc { tag: r_tag, doc: r_doc } = doc_at(self.parent.data, self.pos)?; + let r = if r_tag == (EsSub8 as usize) { + doc_as_u8(r_doc) as usize + } else if r_tag == (EsSub32 as usize) { + doc_as_u32(r_doc) as usize + } else { + return Err(Expected(format!("expected EBML doc with tag {:?} or {:?} but found \ + tag {:?}", + EsSub8, + EsSub32, + r_tag))); + }; + if r_doc.end > self.parent.end { + return Err(Expected(format!("invalid EBML, child extends to {:#x}, parent to \ + {:#x}", + r_doc.end, + self.parent.end))); + } + self.pos = r_doc.end; + debug!("_next_sub result={:?}", r); + Ok(r) + } + + // variable-length unsigned integer with different tags. + // `first_tag` should be a tag for u8 or i8. + // `last_tag` should be the largest allowed integer tag with the matching signedness. + // all tags between them should be valid, in the order of u8, u16, u32 and u64. + fn _next_int(&mut self, + first_tag: EbmlEncoderTag, + last_tag: EbmlEncoderTag) + -> DecodeResult { + if self.pos >= self.parent.end { + return Err(Expected(format!("no more documents in current node!"))); + } + + let TaggedDoc { tag: r_tag, doc: r_doc } = doc_at(self.parent.data, self.pos)?; + let r = if first_tag as usize <= r_tag && r_tag <= last_tag as usize { + match r_tag - first_tag as usize { + 0 => doc_as_u8(r_doc) as u64, + 1 => doc_as_u16(r_doc) as u64, + 2 => doc_as_u32(r_doc) as u64, + 3 => doc_as_u64(r_doc), + _ => unreachable!(), + } + } else { + return Err(Expected(format!("expected EBML doc with tag {:?} through {:?} but \ + found tag {:?}", + first_tag, + last_tag, + r_tag))); + }; + if r_doc.end > self.parent.end { + return Err(Expected(format!("invalid EBML, child extends to {:#x}, parent to \ + {:#x}", + r_doc.end, + self.parent.end))); + } + self.pos = r_doc.end; + debug!("_next_int({:?}, {:?}) result={:?}", first_tag, last_tag, r); + Ok(r) + } + + pub fn read_opaque(&mut self, op: F) -> DecodeResult + where F: FnOnce(&mut opaque::Decoder, Doc) -> DecodeResult + { + let doc = self.next_doc(EsOpaque)?; + + let result = { + let mut opaque_decoder = opaque::Decoder::new(doc.data, doc.start); + op(&mut opaque_decoder, doc)? + }; + + Ok(result) + } + + pub fn position(&self) -> usize { + self.pos + } + + pub fn advance(&mut self, bytes: usize) { + self.pos += bytes; + } +} + +impl<'doc> serialize::Decoder for Decoder<'doc> { + type Error = Error; + fn read_nil(&mut self) -> DecodeResult<()> { + Ok(()) + } + + fn read_u64(&mut self) -> DecodeResult { + self._next_int(EsU8, EsU64) + } + fn read_u32(&mut self) -> DecodeResult { + Ok(self._next_int(EsU8, EsU32)? as u32) + } + fn read_u16(&mut self) -> DecodeResult { + Ok(self._next_int(EsU8, EsU16)? as u16) + } + fn read_u8(&mut self) -> DecodeResult { + Ok(doc_as_u8(self.next_doc(EsU8)?)) + } + fn read_usize(&mut self) -> DecodeResult { + let v = self._next_int(EsU8, EsU64)?; + if v > (::std::usize::MAX as u64) { + Err(IntTooBig(v as usize)) + } else { + Ok(v as usize) + } + } + + fn read_i64(&mut self) -> DecodeResult { + Ok(self._next_int(EsI8, EsI64)? as i64) + } + fn read_i32(&mut self) -> DecodeResult { + Ok(self._next_int(EsI8, EsI32)? as i32) + } + fn read_i16(&mut self) -> DecodeResult { + Ok(self._next_int(EsI8, EsI16)? as i16) + } + fn read_i8(&mut self) -> DecodeResult { + Ok(doc_as_u8(self.next_doc(EsI8)?) as i8) + } + fn read_isize(&mut self) -> DecodeResult { + let v = self._next_int(EsI8, EsI64)? as i64; + if v > (isize::MAX as i64) || v < (isize::MIN as i64) { + debug!("FIXME \\#6122: Removing this makes this function miscompile"); + Err(IntTooBig(v as usize)) + } else { + Ok(v as isize) + } + } + + fn read_bool(&mut self) -> DecodeResult { + Ok(doc_as_u8(self.next_doc(EsBool)?) != 0) + } + + fn read_f64(&mut self) -> DecodeResult { + let bits = doc_as_u64(self.next_doc(EsF64)?); + Ok(unsafe { transmute(bits) }) + } + fn read_f32(&mut self) -> DecodeResult { + let bits = doc_as_u32(self.next_doc(EsF32)?); + Ok(unsafe { transmute(bits) }) + } + fn read_char(&mut self) -> DecodeResult { + Ok(char::from_u32(doc_as_u32(self.next_doc(EsChar)?)).unwrap()) + } + fn read_str(&mut self) -> DecodeResult { + Ok(self.next_doc(EsStr)?.to_string()) + } + + // Compound types: + fn read_enum(&mut self, name: &str, f: F) -> DecodeResult + where F: FnOnce(&mut Decoder<'doc>) -> DecodeResult + { + debug!("read_enum({})", name); + + let doc = self.next_doc(EsEnum)?; + + let (old_parent, old_pos) = (self.parent, self.pos); + self.parent = doc; + self.pos = self.parent.start; + + let result = f(self)?; + + self.parent = old_parent; + self.pos = old_pos; + Ok(result) + } + + fn read_enum_variant(&mut self, _: &[&str], mut f: F) -> DecodeResult + where F: FnMut(&mut Decoder<'doc>, usize) -> DecodeResult + { + debug!("read_enum_variant()"); + let idx = self._next_sub()?; + debug!(" idx={}", idx); + + f(self, idx) + } + + fn read_enum_variant_arg(&mut self, idx: usize, f: F) -> DecodeResult + where F: FnOnce(&mut Decoder<'doc>) -> DecodeResult + { + debug!("read_enum_variant_arg(idx={})", idx); + f(self) + } + + fn read_enum_struct_variant(&mut self, _: &[&str], mut f: F) -> DecodeResult + where F: FnMut(&mut Decoder<'doc>, usize) -> DecodeResult + { + debug!("read_enum_struct_variant()"); + let idx = self._next_sub()?; + debug!(" idx={}", idx); + + f(self, idx) + } + + fn read_enum_struct_variant_field(&mut self, + name: &str, + idx: usize, + f: F) + -> DecodeResult + where F: FnOnce(&mut Decoder<'doc>) -> DecodeResult + { + debug!("read_enum_struct_variant_arg(name={}, idx={})", name, idx); + f(self) + } + + fn read_struct(&mut self, name: &str, _: usize, f: F) -> DecodeResult + where F: FnOnce(&mut Decoder<'doc>) -> DecodeResult + { + debug!("read_struct(name={})", name); + f(self) + } + + fn read_struct_field(&mut self, name: &str, idx: usize, f: F) -> DecodeResult + where F: FnOnce(&mut Decoder<'doc>) -> DecodeResult + { + debug!("read_struct_field(name={}, idx={})", name, idx); + f(self) + } + + fn read_tuple(&mut self, tuple_len: usize, f: F) -> DecodeResult + where F: FnOnce(&mut Decoder<'doc>) -> DecodeResult + { + debug!("read_tuple()"); + self.read_seq(move |d, len| { + if len == tuple_len { + f(d) + } else { + Err(Expected(format!("Expected tuple of length `{}`, found tuple of length \ + `{}`", + tuple_len, + len))) + } + }) + } + + fn read_tuple_arg(&mut self, idx: usize, f: F) -> DecodeResult + where F: FnOnce(&mut Decoder<'doc>) -> DecodeResult + { + debug!("read_tuple_arg(idx={})", idx); + self.read_seq_elt(idx, f) + } + + fn read_tuple_struct(&mut self, name: &str, len: usize, f: F) -> DecodeResult + where F: FnOnce(&mut Decoder<'doc>) -> DecodeResult + { + debug!("read_tuple_struct(name={})", name); + self.read_tuple(len, f) + } + + fn read_tuple_struct_arg(&mut self, idx: usize, f: F) -> DecodeResult + where F: FnOnce(&mut Decoder<'doc>) -> DecodeResult + { + debug!("read_tuple_struct_arg(idx={})", idx); + self.read_tuple_arg(idx, f) + } + + fn read_option(&mut self, mut f: F) -> DecodeResult + where F: FnMut(&mut Decoder<'doc>, bool) -> DecodeResult + { + debug!("read_option()"); + self.read_enum("Option", move |this| { + this.read_enum_variant(&["None", "Some"], move |this, idx| { + match idx { + 0 => f(this, false), + 1 => f(this, true), + _ => Err(Expected(format!("Expected None or Some"))), + } + }) + }) + } + + fn read_seq(&mut self, f: F) -> DecodeResult + where F: FnOnce(&mut Decoder<'doc>, usize) -> DecodeResult + { + debug!("read_seq()"); + self.push_doc(EsVec, move |d| { + let len = d._next_sub()?; + debug!(" len={}", len); + f(d, len) + }) + } + + fn read_seq_elt(&mut self, idx: usize, f: F) -> DecodeResult + where F: FnOnce(&mut Decoder<'doc>) -> DecodeResult + { + debug!("read_seq_elt(idx={})", idx); + self.push_doc(EsVecElt, f) + } + + fn read_map(&mut self, f: F) -> DecodeResult + where F: FnOnce(&mut Decoder<'doc>, usize) -> DecodeResult + { + debug!("read_map()"); + self.push_doc(EsMap, move |d| { + let len = d._next_sub()?; + debug!(" len={}", len); + f(d, len) + }) + } + + fn read_map_elt_key(&mut self, idx: usize, f: F) -> DecodeResult + where F: FnOnce(&mut Decoder<'doc>) -> DecodeResult + { + debug!("read_map_elt_key(idx={})", idx); + self.push_doc(EsMapKey, f) + } + + fn read_map_elt_val(&mut self, idx: usize, f: F) -> DecodeResult + where F: FnOnce(&mut Decoder<'doc>) -> DecodeResult + { + debug!("read_map_elt_val(idx={})", idx); + self.push_doc(EsMapVal, f) + } + + fn error(&mut self, err: &str) -> Error { + ApplicationError(err.to_string()) + } +} + +#[test] +fn test_vuint_at() { + let data = &[ + 0x80, + 0xff, + 0x40, 0x00, + 0x7f, 0xff, + 0x20, 0x00, 0x00, + 0x3f, 0xff, 0xff, + 0x10, 0x00, 0x00, 0x00, + 0x1f, 0xff, 0xff, 0xff + ]; + + let mut res: Res; + + // Class A + res = vuint_at(data, 0).unwrap(); + assert_eq!(res.val, 0); + assert_eq!(res.next, 1); + res = vuint_at(data, res.next).unwrap(); + assert_eq!(res.val, (1 << 7) - 1); + assert_eq!(res.next, 2); + + // Class B + res = vuint_at(data, res.next).unwrap(); + assert_eq!(res.val, 0); + assert_eq!(res.next, 4); + res = vuint_at(data, res.next).unwrap(); + assert_eq!(res.val, (1 << 14) - 1); + assert_eq!(res.next, 6); + + // Class C + res = vuint_at(data, res.next).unwrap(); + assert_eq!(res.val, 0); + assert_eq!(res.next, 9); + res = vuint_at(data, res.next).unwrap(); + assert_eq!(res.val, (1 << 21) - 1); + assert_eq!(res.next, 12); + + // Class D + res = vuint_at(data, res.next).unwrap(); + assert_eq!(res.val, 0); + assert_eq!(res.next, 16); + res = vuint_at(data, res.next).unwrap(); + assert_eq!(res.val, (1 << 28) - 1); + assert_eq!(res.next, 20); +} + +#[bench] +pub fn vuint_at_A_aligned(b: &mut Bencher) { + let data = (0..4 * 100) + .map(|i| { + match i % 2 { + 0 => 0x80, + _ => i as u8, + } + }) + .collect::>(); + let mut sum = 0; + b.iter(|| { + let mut i = 0; + while i < data.len() { + sum += vuint_at(&data, i).unwrap().val; + i += 4; + } + }); +} + +#[bench] +pub fn vuint_at_A_unaligned(b: &mut Bencher) { + let data = (0..4 * 100 + 1) + .map(|i| { + match i % 2 { + 1 => 0x80, + _ => i as u8, + } + }) + .collect::>(); + let mut sum = 0; + b.iter(|| { + let mut i = 1; + while i < data.len() { + sum += vuint_at(&data, i).unwrap().val; + i += 4; + } + }); +} + +#[bench] +pub fn vuint_at_D_aligned(b: &mut Bencher) { + let data = (0..4 * 100) + .map(|i| { + match i % 4 { + 0 => 0x10, + 3 => i as u8, + _ => 0, + } + }) + .collect::>(); + let mut sum = 0; + b.iter(|| { + let mut i = 0; + while i < data.len() { + sum += vuint_at(&data, i).unwrap().val; + i += 4; + } + }); +} + +#[bench] +pub fn vuint_at_D_unaligned(b: &mut Bencher) { + let data = (0..4 * 100 + 1) + .map(|i| { + match i % 4 { + 1 => 0x10, + 0 => i as u8, + _ => 0, + } + }) + .collect::>(); + let mut sum = 0; + b.iter(|| { + let mut i = 1; + while i < data.len() { + sum += vuint_at(&data, i).unwrap().val; + i += 4; + } + }); +} diff --git a/src/librustc_metadata/rbml/writer.rs b/src/librustc_metadata/rbml/writer.rs new file mode 100644 index 000000000000..d6f4b0d03f22 --- /dev/null +++ b/src/librustc_metadata/rbml/writer.rs @@ -0,0 +1,522 @@ +// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::mem; +use std::io::prelude::*; +use std::io::{self, SeekFrom, Cursor}; + +use rbml::opaque; +use rbml::reader::EbmlEncoderTag::*; +use rbml::reader::NUM_IMPLICIT_TAGS; + +use rustc_serialize as serialize; + +pub type EncodeResult = io::Result<()>; + +// rbml writing +pub struct Encoder<'a> { + pub writer: &'a mut Cursor>, + size_positions: Vec, + relax_limit: u64, // do not move encoded bytes before this position +} + +const NUM_TAGS: usize = 0x1000; + +fn write_tag(w: &mut W, n: usize) -> EncodeResult { + if n < 0xf0 { + w.write_all(&[n as u8]) + } else if 0x100 <= n && n < NUM_TAGS { + w.write_all(&[0xf0 | (n >> 8) as u8, n as u8]) + } else { + Err(io::Error::new(io::ErrorKind::Other, &format!("invalid tag: {}", n)[..])) + } +} + +fn write_sized_vuint(w: &mut W, n: usize, size: usize) -> EncodeResult { + match size { + 1 => w.write_all(&[0x80 | (n as u8)]), + 2 => w.write_all(&[0x40 | ((n >> 8) as u8), n as u8]), + 3 => w.write_all(&[0x20 | ((n >> 16) as u8), (n >> 8) as u8, n as u8]), + 4 => w.write_all(&[0x10 | ((n >> 24) as u8), (n >> 16) as u8, (n >> 8) as u8, n as u8]), + _ => Err(io::Error::new(io::ErrorKind::Other, &format!("isize too big: {}", n)[..])), + } +} + +pub fn write_vuint(w: &mut W, n: usize) -> EncodeResult { + if n < 0x7f { + return write_sized_vuint(w, n, 1); + } + if n < 0x4000 { + return write_sized_vuint(w, n, 2); + } + if n < 0x200000 { + return write_sized_vuint(w, n, 3); + } + if n < 0x10000000 { + return write_sized_vuint(w, n, 4); + } + Err(io::Error::new(io::ErrorKind::Other, &format!("isize too big: {}", n)[..])) +} + +impl<'a> Encoder<'a> { + pub fn new(w: &'a mut Cursor>) -> Encoder<'a> { + Encoder { + writer: w, + size_positions: vec![], + relax_limit: 0, + } + } + + pub fn start_tag(&mut self, tag_id: usize) -> EncodeResult { + debug!("Start tag {:?}", tag_id); + assert!(tag_id >= NUM_IMPLICIT_TAGS); + + // Write the enum ID: + write_tag(self.writer, tag_id)?; + + // Write a placeholder four-byte size. + let cur_pos = self.writer.seek(SeekFrom::Current(0))?; + self.size_positions.push(cur_pos); + let zeroes: &[u8] = &[0, 0, 0, 0]; + self.writer.write_all(zeroes) + } + + pub fn end_tag(&mut self) -> EncodeResult { + let last_size_pos = self.size_positions.pop().unwrap(); + let cur_pos = self.writer.seek(SeekFrom::Current(0))?; + self.writer.seek(SeekFrom::Start(last_size_pos))?; + let size = (cur_pos - last_size_pos - 4) as usize; + + // relax the size encoding for small tags (bigger tags are costly to move). + // we should never try to move the stable positions, however. + const RELAX_MAX_SIZE: usize = 0x100; + if size <= RELAX_MAX_SIZE && last_size_pos >= self.relax_limit { + // we can't alter the buffer in place, so have a temporary buffer + let mut buf = [0u8; RELAX_MAX_SIZE]; + { + let last_size_pos = last_size_pos as usize; + let data = &self.writer.get_ref()[last_size_pos + 4..cur_pos as usize]; + buf[..size].copy_from_slice(data); + } + + // overwrite the size and data and continue + write_vuint(self.writer, size)?; + self.writer.write_all(&buf[..size])?; + } else { + // overwrite the size with an overlong encoding and skip past the data + write_sized_vuint(self.writer, size, 4)?; + self.writer.seek(SeekFrom::Start(cur_pos))?; + } + + debug!("End tag (size = {:?})", size); + Ok(()) + } + + pub fn wr_tag(&mut self, tag_id: usize, blk: F) -> EncodeResult + where F: FnOnce() -> EncodeResult + { + self.start_tag(tag_id)?; + blk()?; + self.end_tag() + } + + pub fn wr_tagged_bytes(&mut self, tag_id: usize, b: &[u8]) -> EncodeResult { + assert!(tag_id >= NUM_IMPLICIT_TAGS); + write_tag(self.writer, tag_id)?; + write_vuint(self.writer, b.len())?; + self.writer.write_all(b) + } + + pub fn wr_tagged_u64(&mut self, tag_id: usize, v: u64) -> EncodeResult { + let bytes: [u8; 8] = unsafe { mem::transmute(v.to_be()) }; + // tagged integers are emitted in big-endian, with no + // leading zeros. + let leading_zero_bytes = v.leading_zeros() / 8; + self.wr_tagged_bytes(tag_id, &bytes[leading_zero_bytes as usize..]) + } + + #[inline] + pub fn wr_tagged_u32(&mut self, tag_id: usize, v: u32) -> EncodeResult { + self.wr_tagged_u64(tag_id, v as u64) + } + + #[inline] + pub fn wr_tagged_u16(&mut self, tag_id: usize, v: u16) -> EncodeResult { + self.wr_tagged_u64(tag_id, v as u64) + } + + #[inline] + pub fn wr_tagged_u8(&mut self, tag_id: usize, v: u8) -> EncodeResult { + self.wr_tagged_bytes(tag_id, &[v]) + } + + #[inline] + pub fn wr_tagged_i64(&mut self, tag_id: usize, v: i64) -> EncodeResult { + self.wr_tagged_u64(tag_id, v as u64) + } + + #[inline] + pub fn wr_tagged_i32(&mut self, tag_id: usize, v: i32) -> EncodeResult { + self.wr_tagged_u32(tag_id, v as u32) + } + + #[inline] + pub fn wr_tagged_i16(&mut self, tag_id: usize, v: i16) -> EncodeResult { + self.wr_tagged_u16(tag_id, v as u16) + } + + #[inline] + pub fn wr_tagged_i8(&mut self, tag_id: usize, v: i8) -> EncodeResult { + self.wr_tagged_bytes(tag_id, &[v as u8]) + } + + pub fn wr_tagged_str(&mut self, tag_id: usize, v: &str) -> EncodeResult { + self.wr_tagged_bytes(tag_id, v.as_bytes()) + } + + // for auto-serialization + fn wr_tagged_raw_bytes(&mut self, tag_id: usize, b: &[u8]) -> EncodeResult { + write_tag(self.writer, tag_id)?; + self.writer.write_all(b) + } + + fn wr_tagged_raw_u64(&mut self, tag_id: usize, v: u64) -> EncodeResult { + let bytes: [u8; 8] = unsafe { mem::transmute(v.to_be()) }; + self.wr_tagged_raw_bytes(tag_id, &bytes) + } + + fn wr_tagged_raw_u32(&mut self, tag_id: usize, v: u32) -> EncodeResult { + let bytes: [u8; 4] = unsafe { mem::transmute(v.to_be()) }; + self.wr_tagged_raw_bytes(tag_id, &bytes) + } + + fn wr_tagged_raw_u16(&mut self, tag_id: usize, v: u16) -> EncodeResult { + let bytes: [u8; 2] = unsafe { mem::transmute(v.to_be()) }; + self.wr_tagged_raw_bytes(tag_id, &bytes) + } + + fn wr_tagged_raw_u8(&mut self, tag_id: usize, v: u8) -> EncodeResult { + self.wr_tagged_raw_bytes(tag_id, &[v]) + } + + fn wr_tagged_raw_i64(&mut self, tag_id: usize, v: i64) -> EncodeResult { + self.wr_tagged_raw_u64(tag_id, v as u64) + } + + fn wr_tagged_raw_i32(&mut self, tag_id: usize, v: i32) -> EncodeResult { + self.wr_tagged_raw_u32(tag_id, v as u32) + } + + fn wr_tagged_raw_i16(&mut self, tag_id: usize, v: i16) -> EncodeResult { + self.wr_tagged_raw_u16(tag_id, v as u16) + } + + fn wr_tagged_raw_i8(&mut self, tag_id: usize, v: i8) -> EncodeResult { + self.wr_tagged_raw_bytes(tag_id, &[v as u8]) + } + + pub fn wr_bytes(&mut self, b: &[u8]) -> EncodeResult { + debug!("Write {:?} bytes", b.len()); + self.writer.write_all(b) + } + + pub fn wr_str(&mut self, s: &str) -> EncodeResult { + debug!("Write str: {:?}", s); + self.writer.write_all(s.as_bytes()) + } + + /// Returns the current position while marking it stable, i.e. + /// generated bytes so far wouldn't be affected by relaxation. + pub fn mark_stable_position(&mut self) -> u64 { + let pos = self.writer.seek(SeekFrom::Current(0)).unwrap(); + if self.relax_limit < pos { + self.relax_limit = pos; + } + pos + } +} + +impl<'a> Encoder<'a> { + // used internally to emit things like the vector length and so on + fn _emit_tagged_sub(&mut self, v: usize) -> EncodeResult { + if v as u8 as usize == v { + self.wr_tagged_raw_u8(EsSub8 as usize, v as u8) + } else if v as u32 as usize == v { + self.wr_tagged_raw_u32(EsSub32 as usize, v as u32) + } else { + Err(io::Error::new(io::ErrorKind::Other, + &format!("length or variant id too big: {}", v)[..])) + } + } + + pub fn emit_opaque(&mut self, f: F) -> EncodeResult + where F: FnOnce(&mut opaque::Encoder) -> EncodeResult + { + self.start_tag(EsOpaque as usize)?; + + { + let mut opaque_encoder = opaque::Encoder::new(self.writer); + f(&mut opaque_encoder)?; + } + + self.mark_stable_position(); + self.end_tag() + } +} + +impl<'a> serialize::Encoder for Encoder<'a> { + type Error = io::Error; + + fn emit_nil(&mut self) -> EncodeResult { + Ok(()) + } + + fn emit_usize(&mut self, v: usize) -> EncodeResult { + self.emit_u64(v as u64) + } + fn emit_u64(&mut self, v: u64) -> EncodeResult { + if v as u32 as u64 == v { + self.emit_u32(v as u32) + } else { + self.wr_tagged_raw_u64(EsU64 as usize, v) + } + } + fn emit_u32(&mut self, v: u32) -> EncodeResult { + if v as u16 as u32 == v { + self.emit_u16(v as u16) + } else { + self.wr_tagged_raw_u32(EsU32 as usize, v) + } + } + fn emit_u16(&mut self, v: u16) -> EncodeResult { + if v as u8 as u16 == v { + self.emit_u8(v as u8) + } else { + self.wr_tagged_raw_u16(EsU16 as usize, v) + } + } + fn emit_u8(&mut self, v: u8) -> EncodeResult { + self.wr_tagged_raw_u8(EsU8 as usize, v) + } + + fn emit_isize(&mut self, v: isize) -> EncodeResult { + self.emit_i64(v as i64) + } + fn emit_i64(&mut self, v: i64) -> EncodeResult { + if v as i32 as i64 == v { + self.emit_i32(v as i32) + } else { + self.wr_tagged_raw_i64(EsI64 as usize, v) + } + } + fn emit_i32(&mut self, v: i32) -> EncodeResult { + if v as i16 as i32 == v { + self.emit_i16(v as i16) + } else { + self.wr_tagged_raw_i32(EsI32 as usize, v) + } + } + fn emit_i16(&mut self, v: i16) -> EncodeResult { + if v as i8 as i16 == v { + self.emit_i8(v as i8) + } else { + self.wr_tagged_raw_i16(EsI16 as usize, v) + } + } + fn emit_i8(&mut self, v: i8) -> EncodeResult { + self.wr_tagged_raw_i8(EsI8 as usize, v) + } + + fn emit_bool(&mut self, v: bool) -> EncodeResult { + self.wr_tagged_raw_u8(EsBool as usize, v as u8) + } + + fn emit_f64(&mut self, v: f64) -> EncodeResult { + let bits = unsafe { mem::transmute(v) }; + self.wr_tagged_raw_u64(EsF64 as usize, bits) + } + fn emit_f32(&mut self, v: f32) -> EncodeResult { + let bits = unsafe { mem::transmute(v) }; + self.wr_tagged_raw_u32(EsF32 as usize, bits) + } + fn emit_char(&mut self, v: char) -> EncodeResult { + self.wr_tagged_raw_u32(EsChar as usize, v as u32) + } + + fn emit_str(&mut self, v: &str) -> EncodeResult { + self.wr_tagged_str(EsStr as usize, v) + } + + fn emit_enum(&mut self, _name: &str, f: F) -> EncodeResult + where F: FnOnce(&mut Encoder<'a>) -> EncodeResult + { + self.start_tag(EsEnum as usize)?; + f(self)?; + self.end_tag() + } + + fn emit_enum_variant(&mut self, _: &str, v_id: usize, _: usize, f: F) -> EncodeResult + where F: FnOnce(&mut Encoder<'a>) -> EncodeResult + { + self._emit_tagged_sub(v_id)?; + f(self) + } + + fn emit_enum_variant_arg(&mut self, _: usize, f: F) -> EncodeResult + where F: FnOnce(&mut Encoder<'a>) -> EncodeResult + { + f(self) + } + + fn emit_enum_struct_variant(&mut self, + v_name: &str, + v_id: usize, + cnt: usize, + f: F) + -> EncodeResult + where F: FnOnce(&mut Encoder<'a>) -> EncodeResult + { + self.emit_enum_variant(v_name, v_id, cnt, f) + } + + fn emit_enum_struct_variant_field(&mut self, _: &str, idx: usize, f: F) -> EncodeResult + where F: FnOnce(&mut Encoder<'a>) -> EncodeResult + { + self.emit_enum_variant_arg(idx, f) + } + + fn emit_struct(&mut self, _: &str, _len: usize, f: F) -> EncodeResult + where F: FnOnce(&mut Encoder<'a>) -> EncodeResult + { + f(self) + } + + fn emit_struct_field(&mut self, _name: &str, _: usize, f: F) -> EncodeResult + where F: FnOnce(&mut Encoder<'a>) -> EncodeResult + { + f(self) + } + + fn emit_tuple(&mut self, len: usize, f: F) -> EncodeResult + where F: FnOnce(&mut Encoder<'a>) -> EncodeResult + { + self.emit_seq(len, f) + } + fn emit_tuple_arg(&mut self, idx: usize, f: F) -> EncodeResult + where F: FnOnce(&mut Encoder<'a>) -> EncodeResult + { + self.emit_seq_elt(idx, f) + } + + fn emit_tuple_struct(&mut self, _: &str, len: usize, f: F) -> EncodeResult + where F: FnOnce(&mut Encoder<'a>) -> EncodeResult + { + self.emit_seq(len, f) + } + fn emit_tuple_struct_arg(&mut self, idx: usize, f: F) -> EncodeResult + where F: FnOnce(&mut Encoder<'a>) -> EncodeResult + { + self.emit_seq_elt(idx, f) + } + + fn emit_option(&mut self, f: F) -> EncodeResult + where F: FnOnce(&mut Encoder<'a>) -> EncodeResult + { + self.emit_enum("Option", f) + } + fn emit_option_none(&mut self) -> EncodeResult { + self.emit_enum_variant("None", 0, 0, |_| Ok(())) + } + fn emit_option_some(&mut self, f: F) -> EncodeResult + where F: FnOnce(&mut Encoder<'a>) -> EncodeResult + { + + self.emit_enum_variant("Some", 1, 1, f) + } + + fn emit_seq(&mut self, len: usize, f: F) -> EncodeResult + where F: FnOnce(&mut Encoder<'a>) -> EncodeResult + { + if len == 0 { + // empty vector optimization + return self.wr_tagged_bytes(EsVec as usize, &[]); + } + + self.start_tag(EsVec as usize)?; + self._emit_tagged_sub(len)?; + f(self)?; + self.end_tag() + } + + fn emit_seq_elt(&mut self, _idx: usize, f: F) -> EncodeResult + where F: FnOnce(&mut Encoder<'a>) -> EncodeResult + { + + self.start_tag(EsVecElt as usize)?; + f(self)?; + self.end_tag() + } + + fn emit_map(&mut self, len: usize, f: F) -> EncodeResult + where F: FnOnce(&mut Encoder<'a>) -> EncodeResult + { + if len == 0 { + // empty map optimization + return self.wr_tagged_bytes(EsMap as usize, &[]); + } + + self.start_tag(EsMap as usize)?; + self._emit_tagged_sub(len)?; + f(self)?; + self.end_tag() + } + + fn emit_map_elt_key(&mut self, _idx: usize, f: F) -> EncodeResult + where F: FnOnce(&mut Encoder<'a>) -> EncodeResult + { + + self.start_tag(EsMapKey as usize)?; + f(self)?; + self.end_tag() + } + + fn emit_map_elt_val(&mut self, _idx: usize, f: F) -> EncodeResult + where F: FnOnce(&mut Encoder<'a>) -> EncodeResult + { + self.start_tag(EsMapVal as usize)?; + f(self)?; + self.end_tag() + } +} + +#[test] +fn test_option_int() { + use rbml::reader; + use serialize::{Encodable, Decodable}; + use std::io::Cursor; + + fn test_v(v: Option) { + debug!("v == {:?}", v); + let mut wr = Cursor::new(Vec::new()); + { + let mut rbml_w = Encoder::new(&mut wr); + let _ = v.encode(&mut rbml_w); + } + let rbml_doc = reader::Doc::new(wr.get_ref()); + let mut deser = reader::Decoder::new(rbml_doc); + let v1 = Decodable::decode(&mut deser).unwrap(); + debug!("v1 == {:?}", v1); + assert_eq!(v, v1); + } + + test_v(Some(22)); + test_v(None); + test_v(Some(3)); +} From 87db6b9e65d3ee67f2c3ff8312fa7fbbe89ac8e9 Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Mon, 29 Aug 2016 03:33:38 +0300 Subject: [PATCH 403/443] rustc_metadata: remove redundant lifetimes from astencode::DecodeContext. --- src/librustc_metadata/astencode.rs | 106 ++++++++++++++--------------- 1 file changed, 52 insertions(+), 54 deletions(-) diff --git a/src/librustc_metadata/astencode.rs b/src/librustc_metadata/astencode.rs index fb7e1c0f7895..4469a797eed9 100644 --- a/src/librustc_metadata/astencode.rs +++ b/src/librustc_metadata/astencode.rs @@ -58,9 +58,9 @@ use rustc_serialize::{Encodable, EncoderHelpers}; #[cfg(test)] use rustc::hir::print as pprust; #[cfg(test)] use rustc::hir::lowering::{LoweringContext, DummyResolver}; -struct DecodeContext<'a, 'b, 'tcx: 'a> { +struct DecodeContext<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, - cdata: &'b cstore::CrateMetadata, + cdata: &'a cstore::CrateMetadata, from_id_range: IdRange, to_id_range: IdRange, // Cache the last used filemap for translating spans as an optimization. @@ -102,7 +102,7 @@ pub fn encode_inlined_item(ecx: &e::EncodeContext, rbml_w.writer.seek(SeekFrom::Current(0))); } -impl<'a, 'b, 'c, 'tcx> ast_map::FoldOps for &'a DecodeContext<'b, 'c, 'tcx> { +impl<'a, 'b, 'tcx> ast_map::FoldOps for &'a DecodeContext<'b, 'tcx> { fn new_id(&self, id: ast::NodeId) -> ast::NodeId { if id == ast::DUMMY_NODE_ID { // Used by ast_map to map the NodeInlinedParent. @@ -177,7 +177,7 @@ fn reserve_id_range(sess: &Session, IdRange { min: to_id_min, max: to_id_max } } -impl<'a, 'b, 'tcx> DecodeContext<'a, 'b, 'tcx> { +impl<'a, 'tcx> DecodeContext<'a, 'tcx> { /// Translates an internal id, meaning a node id that is known to refer to some part of the /// item currently being inlined, such as a local variable or argument. All naked node-ids /// that appear in types have this property, since if something might refer to an external item @@ -462,8 +462,8 @@ impl tr for hir::Freevar { // Encoding and decoding of MethodCallee trait read_method_callee_helper<'tcx> { - fn read_method_callee<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) - -> (u32, ty::MethodCallee<'tcx>); + fn read_method_callee<'a>(&mut self, dcx: &DecodeContext<'a, 'tcx>) + -> (u32, ty::MethodCallee<'tcx>); } fn encode_method_callee<'a, 'tcx>(ecx: &e::EncodeContext<'a, 'tcx>, @@ -489,8 +489,8 @@ fn encode_method_callee<'a, 'tcx>(ecx: &e::EncodeContext<'a, 'tcx>, } impl<'a, 'tcx> read_method_callee_helper<'tcx> for reader::Decoder<'a> { - fn read_method_callee<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) - -> (u32, ty::MethodCallee<'tcx>) { + fn read_method_callee<'b>(&mut self, dcx: &DecodeContext<'b, 'tcx>) + -> (u32, ty::MethodCallee<'tcx>) { self.read_struct("MethodCallee", 4, |this| { let autoderef = this.read_struct_field("autoderef", 0, @@ -821,31 +821,30 @@ impl<'a> doc_decoder_helpers for rbml::Doc<'a> { } trait rbml_decoder_decoder_helpers<'tcx> { - fn read_ty_encoded<'a, 'b, F, R>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>, - f: F) -> R + fn read_ty_encoded<'a, F, R>(&mut self, dcx: &DecodeContext<'a, 'tcx>, f: F) -> R where F: for<'x> FnOnce(&mut tydecode::TyDecoder<'x, 'tcx>) -> R; - fn read_region<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) -> &'tcx ty::Region; - fn read_ty<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) -> Ty<'tcx>; - fn read_tys<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) -> Vec>; - fn read_trait_ref<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) - -> ty::TraitRef<'tcx>; - fn read_poly_trait_ref<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) - -> ty::PolyTraitRef<'tcx>; - fn read_predicate<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) - -> ty::Predicate<'tcx>; - fn read_substs<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) - -> &'tcx Substs<'tcx>; - fn read_upvar_capture<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) - -> ty::UpvarCapture<'tcx>; - fn read_auto_adjustment<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) - -> adjustment::AutoAdjustment<'tcx>; - fn read_cast_kind<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) - -> cast::CastKind; - fn read_auto_deref_ref<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) - -> adjustment::AutoDerefRef<'tcx>; - fn read_autoref<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) - -> adjustment::AutoRef<'tcx>; + fn read_region<'a>(&mut self, dcx: &DecodeContext<'a, 'tcx>) -> &'tcx ty::Region; + fn read_ty<'a>(&mut self, dcx: &DecodeContext<'a, 'tcx>) -> Ty<'tcx>; + fn read_tys<'a>(&mut self, dcx: &DecodeContext<'a, 'tcx>) -> Vec>; + fn read_trait_ref<'a>(&mut self, dcx: &DecodeContext<'a, 'tcx>) + -> ty::TraitRef<'tcx>; + fn read_poly_trait_ref<'a>(&mut self, dcx: &DecodeContext<'a, 'tcx>) + -> ty::PolyTraitRef<'tcx>; + fn read_predicate<'a>(&mut self, dcx: &DecodeContext<'a, 'tcx>) + -> ty::Predicate<'tcx>; + fn read_substs<'a>(&mut self, dcx: &DecodeContext<'a, 'tcx>) + -> &'tcx Substs<'tcx>; + fn read_upvar_capture<'a>(&mut self, dcx: &DecodeContext<'a, 'tcx>) + -> ty::UpvarCapture<'tcx>; + fn read_auto_adjustment<'a>(&mut self, dcx: &DecodeContext<'a, 'tcx>) + -> adjustment::AutoAdjustment<'tcx>; + fn read_cast_kind<'a>(&mut self, dcx: &DecodeContext<'a, 'tcx>) + -> cast::CastKind; + fn read_auto_deref_ref<'a>(&mut self, dcx: &DecodeContext<'a, 'tcx>) + -> adjustment::AutoDerefRef<'tcx>; + fn read_autoref<'a>(&mut self, dcx: &DecodeContext<'a, 'tcx>) + -> adjustment::AutoRef<'tcx>; // Versions of the type reading functions that don't need the full // DecodeContext. @@ -890,7 +889,7 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { }).unwrap() } - fn read_ty_encoded<'b, 'c, F, R>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>, op: F) -> R + fn read_ty_encoded<'b, F, R>(&mut self, dcx: &DecodeContext<'b, 'tcx>, op: F) -> R where F: for<'x> FnOnce(&mut tydecode::TyDecoder<'x,'tcx>) -> R { return self.read_opaque(|_, doc| { @@ -909,48 +908,47 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { str } } - fn read_region<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) -> &'tcx ty::Region { + fn read_region<'b>(&mut self, dcx: &DecodeContext<'b, 'tcx>) -> &'tcx ty::Region { // Note: regions types embed local node ids. In principle, we // should translate these node ids into the new decode // context. However, we do not bother, because region types // are not used during trans. This also applies to read_ty. return self.read_ty_encoded(dcx, |decoder| decoder.parse_region()); } - fn read_ty<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) -> Ty<'tcx> { + fn read_ty<'b>(&mut self, dcx: &DecodeContext<'b, 'tcx>) -> Ty<'tcx> { return self.read_ty_encoded(dcx, |decoder| decoder.parse_ty()); } - fn read_tys<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) - -> Vec> { + fn read_tys<'b>(&mut self, dcx: &DecodeContext<'b, 'tcx>) -> Vec> { self.read_to_vec(|this| Ok(this.read_ty(dcx))).unwrap().into_iter().collect() } - fn read_trait_ref<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) - -> ty::TraitRef<'tcx> { + fn read_trait_ref<'b>(&mut self, dcx: &DecodeContext<'b, 'tcx>) + -> ty::TraitRef<'tcx> { self.read_ty_encoded(dcx, |decoder| decoder.parse_trait_ref()) } - fn read_poly_trait_ref<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) - -> ty::PolyTraitRef<'tcx> { + fn read_poly_trait_ref<'b>(&mut self, dcx: &DecodeContext<'b, 'tcx>) + -> ty::PolyTraitRef<'tcx> { ty::Binder(self.read_ty_encoded(dcx, |decoder| decoder.parse_trait_ref())) } - fn read_predicate<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) - -> ty::Predicate<'tcx> + fn read_predicate<'b>(&mut self, dcx: &DecodeContext<'b, 'tcx>) + -> ty::Predicate<'tcx> { self.read_ty_encoded(dcx, |decoder| decoder.parse_predicate()) } - fn read_substs<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) - -> &'tcx Substs<'tcx> { + fn read_substs<'b>(&mut self, dcx: &DecodeContext<'b, 'tcx>) + -> &'tcx Substs<'tcx> { self.read_opaque(|_, doc| { Ok(tydecode::TyDecoder::with_doc(dcx.tcx, dcx.cdata.cnum, doc, &mut |d| convert_def_id(dcx, d)) .parse_substs()) }).unwrap() } - fn read_upvar_capture<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) - -> ty::UpvarCapture<'tcx> { + fn read_upvar_capture<'b>(&mut self, dcx: &DecodeContext<'b, 'tcx>) + -> ty::UpvarCapture<'tcx> { self.read_enum("UpvarCapture", |this| { let variants = ["ByValue", "ByRef"]; this.read_enum_variant(&variants, |this, i| { @@ -967,8 +965,8 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { }) }).unwrap() } - fn read_auto_adjustment<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) - -> adjustment::AutoAdjustment<'tcx> { + fn read_auto_adjustment<'b>(&mut self, dcx: &DecodeContext<'b, 'tcx>) + -> adjustment::AutoAdjustment<'tcx> { self.read_enum("AutoAdjustment", |this| { let variants = ["AdjustReifyFnPointer", "AdjustUnsafeFnPointer", "AdjustMutToConstPointer", "AdjustDerefRef", @@ -998,8 +996,8 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { }).unwrap() } - fn read_auto_deref_ref<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) - -> adjustment::AutoDerefRef<'tcx> { + fn read_auto_deref_ref<'b>(&mut self, dcx: &DecodeContext<'b, 'tcx>) + -> adjustment::AutoDerefRef<'tcx> { self.read_struct("AutoDerefRef", 2, |this| { Ok(adjustment::AutoDerefRef { autoderefs: this.read_struct_field("autoderefs", 0, |this| { @@ -1027,8 +1025,8 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { }).unwrap() } - fn read_autoref<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) - -> adjustment::AutoRef<'tcx> { + fn read_autoref<'b>(&mut self, dcx: &DecodeContext<'b, 'tcx>) + -> adjustment::AutoRef<'tcx> { self.read_enum("AutoRef", |this| { let variants = ["AutoPtr", "AutoUnsafe"]; this.read_enum_variant(&variants, |this, i| { @@ -1057,8 +1055,8 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { }).unwrap() } - fn read_cast_kind<'b, 'c>(&mut self, _dcx: &DecodeContext<'b, 'c, 'tcx>) - -> cast::CastKind + fn read_cast_kind<'b>(&mut self, _dcx: &DecodeContext<'b, 'tcx>) + -> cast::CastKind { Decodable::decode(self).unwrap() } From 78ace66b6a8833b709270584491a5ed8beb51bea Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Mon, 29 Aug 2016 05:03:55 +0300 Subject: [PATCH 404/443] rustc_metadata: remove extension traits from astencode. --- src/librustc_metadata/astencode.rs | 185 ++--------------------------- 1 file changed, 7 insertions(+), 178 deletions(-) diff --git a/src/librustc_metadata/astencode.rs b/src/librustc_metadata/astencode.rs index 4469a797eed9..ece4e8b10974 100644 --- a/src/librustc_metadata/astencode.rs +++ b/src/librustc_metadata/astencode.rs @@ -44,12 +44,10 @@ use syntax_pos; use std::cell::Cell; use std::io::SeekFrom; use std::io::prelude::*; -use std::fmt::Debug; use rbml::reader; use rbml::writer::Encoder; use rbml; -use rustc_serialize as serialize; use rustc_serialize::{Decodable, Decoder, DecoderHelpers}; use rustc_serialize::{Encodable, EncoderHelpers}; @@ -234,40 +232,6 @@ impl tr for syntax_pos::Span { } } -trait def_id_encoder_helpers { - fn emit_def_id(&mut self, did: DefId); -} - -impl def_id_encoder_helpers for S - where ::Error: Debug -{ - fn emit_def_id(&mut self, did: DefId) { - did.encode(self).unwrap() - } -} - -trait def_id_decoder_helpers { - fn read_def_id(&mut self, dcx: &DecodeContext) -> DefId; - fn read_def_id_nodcx(&mut self, - cdata: &cstore::CrateMetadata) -> DefId; -} - -impl def_id_decoder_helpers for D - where ::Error: Debug -{ - fn read_def_id(&mut self, dcx: &DecodeContext) -> DefId { - let did: DefId = Decodable::decode(self).unwrap(); - did.tr(dcx) - } - - fn read_def_id_nodcx(&mut self, - cdata: &cstore::CrateMetadata) - -> DefId { - let did: DefId = Decodable::decode(self).unwrap(); - decoder::translate_def_id(cdata, did) - } -} - // ______________________________________________________________________ // Encoding and decoding the AST itself // @@ -430,23 +394,12 @@ fn encode_freevar_entry(rbml_w: &mut Encoder, fv: &hir::Freevar) { (*fv).encode(rbml_w).unwrap(); } -trait rbml_decoder_helper { - fn read_freevar_entry(&mut self, dcx: &DecodeContext) - -> hir::Freevar; - fn read_capture_mode(&mut self) -> hir::CaptureClause; -} - -impl<'a> rbml_decoder_helper for reader::Decoder<'a> { +impl<'a> reader::Decoder<'a> { fn read_freevar_entry(&mut self, dcx: &DecodeContext) -> hir::Freevar { let fv: hir::Freevar = Decodable::decode(self).unwrap(); fv.tr(dcx) } - - fn read_capture_mode(&mut self) -> hir::CaptureClause { - let cm: hir::CaptureClause = Decodable::decode(self).unwrap(); - cm - } } impl tr for hir::Freevar { @@ -461,11 +414,6 @@ impl tr for hir::Freevar { // ______________________________________________________________________ // Encoding and decoding of MethodCallee -trait read_method_callee_helper<'tcx> { - fn read_method_callee<'a>(&mut self, dcx: &DecodeContext<'a, 'tcx>) - -> (u32, ty::MethodCallee<'tcx>); -} - fn encode_method_callee<'a, 'tcx>(ecx: &e::EncodeContext<'a, 'tcx>, rbml_w: &mut Encoder, autoderef: u32, @@ -477,7 +425,7 @@ fn encode_method_callee<'a, 'tcx>(ecx: &e::EncodeContext<'a, 'tcx>, autoderef.encode(rbml_w) }); rbml_w.emit_struct_field("def_id", 1, |rbml_w| { - Ok(rbml_w.emit_def_id(method.def_id)) + method.def_id.encode(rbml_w) }); rbml_w.emit_struct_field("ty", 2, |rbml_w| { Ok(rbml_w.emit_ty(ecx, method.ty)) @@ -488,7 +436,7 @@ fn encode_method_callee<'a, 'tcx>(ecx: &e::EncodeContext<'a, 'tcx>, }).unwrap(); } -impl<'a, 'tcx> read_method_callee_helper<'tcx> for reader::Decoder<'a> { +impl<'a, 'tcx> reader::Decoder<'a> { fn read_method_callee<'b>(&mut self, dcx: &DecodeContext<'b, 'tcx>) -> (u32, ty::MethodCallee<'tcx>) { @@ -497,7 +445,7 @@ impl<'a, 'tcx> read_method_callee_helper<'tcx> for reader::Decoder<'a> { Decodable::decode).unwrap(); Ok((autoderef, ty::MethodCallee { def_id: this.read_struct_field("def_id", 1, |this| { - Ok(this.read_def_id(dcx)) + DefId::decode(this).map(|d| d.tr(dcx)) }).unwrap(), ty: this.read_struct_field("ty", 2, |this| { Ok(this.read_ty(dcx)) @@ -517,21 +465,7 @@ pub fn encode_cast_kind(ebml_w: &mut Encoder, kind: cast::CastKind) { // ______________________________________________________________________ // Encoding and decoding the side tables -trait rbml_writer_helpers<'tcx> { - fn emit_region(&mut self, ecx: &e::EncodeContext, r: &'tcx ty::Region); - fn emit_ty<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, ty: Ty<'tcx>); - fn emit_substs<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, - substs: &Substs<'tcx>); - fn emit_upvar_capture(&mut self, ecx: &e::EncodeContext, capture: &ty::UpvarCapture); - fn emit_auto_adjustment<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, - adj: &adjustment::AutoAdjustment<'tcx>); - fn emit_autoref<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, - autoref: &adjustment::AutoRef<'tcx>); - fn emit_auto_deref_ref<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, - auto_deref_ref: &adjustment::AutoDerefRef<'tcx>); -} - -impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> { +impl<'a, 'tcx> Encoder<'a> { fn emit_region(&mut self, ecx: &e::EncodeContext, r: &'tcx ty::Region) { self.emit_opaque(|this| Ok(tyencode::enc_region(&mut this.cursor, &ecx.ty_str_ctxt(), @@ -661,12 +595,7 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> { } } -trait write_tag_and_id { - fn tag(&mut self, tag_id: c::astencode_tag, f: F) where F: FnOnce(&mut Self); - fn id(&mut self, id: ast::NodeId); -} - -impl<'a> write_tag_and_id for Encoder<'a> { +impl<'a> Encoder<'a> { fn tag(&mut self, tag_id: c::astencode_tag, f: F) where @@ -808,87 +737,7 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext, } } -trait doc_decoder_helpers: Sized { - fn as_int(&self) -> isize; - fn opt_child(&self, tag: c::astencode_tag) -> Option; -} - -impl<'a> doc_decoder_helpers for rbml::Doc<'a> { - fn as_int(&self) -> isize { reader::doc_as_u64(*self) as isize } - fn opt_child(&self, tag: c::astencode_tag) -> Option> { - reader::maybe_get_doc(*self, tag as usize) - } -} - -trait rbml_decoder_decoder_helpers<'tcx> { - fn read_ty_encoded<'a, F, R>(&mut self, dcx: &DecodeContext<'a, 'tcx>, f: F) -> R - where F: for<'x> FnOnce(&mut tydecode::TyDecoder<'x, 'tcx>) -> R; - - fn read_region<'a>(&mut self, dcx: &DecodeContext<'a, 'tcx>) -> &'tcx ty::Region; - fn read_ty<'a>(&mut self, dcx: &DecodeContext<'a, 'tcx>) -> Ty<'tcx>; - fn read_tys<'a>(&mut self, dcx: &DecodeContext<'a, 'tcx>) -> Vec>; - fn read_trait_ref<'a>(&mut self, dcx: &DecodeContext<'a, 'tcx>) - -> ty::TraitRef<'tcx>; - fn read_poly_trait_ref<'a>(&mut self, dcx: &DecodeContext<'a, 'tcx>) - -> ty::PolyTraitRef<'tcx>; - fn read_predicate<'a>(&mut self, dcx: &DecodeContext<'a, 'tcx>) - -> ty::Predicate<'tcx>; - fn read_substs<'a>(&mut self, dcx: &DecodeContext<'a, 'tcx>) - -> &'tcx Substs<'tcx>; - fn read_upvar_capture<'a>(&mut self, dcx: &DecodeContext<'a, 'tcx>) - -> ty::UpvarCapture<'tcx>; - fn read_auto_adjustment<'a>(&mut self, dcx: &DecodeContext<'a, 'tcx>) - -> adjustment::AutoAdjustment<'tcx>; - fn read_cast_kind<'a>(&mut self, dcx: &DecodeContext<'a, 'tcx>) - -> cast::CastKind; - fn read_auto_deref_ref<'a>(&mut self, dcx: &DecodeContext<'a, 'tcx>) - -> adjustment::AutoDerefRef<'tcx>; - fn read_autoref<'a>(&mut self, dcx: &DecodeContext<'a, 'tcx>) - -> adjustment::AutoRef<'tcx>; - - // Versions of the type reading functions that don't need the full - // DecodeContext. - fn read_ty_nodcx<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>, - cdata: &cstore::CrateMetadata) -> Ty<'tcx>; - fn read_tys_nodcx<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>, - cdata: &cstore::CrateMetadata) -> Vec>; - fn read_substs_nodcx<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>, - cdata: &cstore::CrateMetadata) - -> &'tcx Substs<'tcx>; -} - -impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { - fn read_ty_nodcx<'b>(&mut self, tcx: TyCtxt<'b, 'tcx, 'tcx>, - cdata: &cstore::CrateMetadata) - -> Ty<'tcx> { - self.read_opaque(|_, doc| { - Ok( - tydecode::TyDecoder::with_doc(tcx, cdata.cnum, doc, - &mut |id| decoder::translate_def_id(cdata, id)) - .parse_ty()) - }).unwrap() - } - - fn read_tys_nodcx<'b>(&mut self, tcx: TyCtxt<'b, 'tcx, 'tcx>, - cdata: &cstore::CrateMetadata) -> Vec> { - self.read_to_vec(|this| Ok(this.read_ty_nodcx(tcx, cdata)) ) - .unwrap() - .into_iter() - .collect() - } - - fn read_substs_nodcx<'b>(&mut self, tcx: TyCtxt<'b, 'tcx, 'tcx>, - cdata: &cstore::CrateMetadata) - -> &'tcx Substs<'tcx> - { - self.read_opaque(|_, doc| { - Ok( - tydecode::TyDecoder::with_doc(tcx, cdata.cnum, doc, - &mut |id| decoder::translate_def_id(cdata, id)) - .parse_substs()) - }).unwrap() - } - +impl<'a, 'tcx> reader::Decoder<'a> { fn read_ty_encoded<'b, F, R>(&mut self, dcx: &DecodeContext<'b, 'tcx>, op: F) -> R where F: for<'x> FnOnce(&mut tydecode::TyDecoder<'x,'tcx>) -> R { @@ -919,26 +768,6 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { return self.read_ty_encoded(dcx, |decoder| decoder.parse_ty()); } - fn read_tys<'b>(&mut self, dcx: &DecodeContext<'b, 'tcx>) -> Vec> { - self.read_to_vec(|this| Ok(this.read_ty(dcx))).unwrap().into_iter().collect() - } - - fn read_trait_ref<'b>(&mut self, dcx: &DecodeContext<'b, 'tcx>) - -> ty::TraitRef<'tcx> { - self.read_ty_encoded(dcx, |decoder| decoder.parse_trait_ref()) - } - - fn read_poly_trait_ref<'b>(&mut self, dcx: &DecodeContext<'b, 'tcx>) - -> ty::PolyTraitRef<'tcx> { - ty::Binder(self.read_ty_encoded(dcx, |decoder| decoder.parse_trait_ref())) - } - - fn read_predicate<'b>(&mut self, dcx: &DecodeContext<'b, 'tcx>) - -> ty::Predicate<'tcx> - { - self.read_ty_encoded(dcx, |decoder| decoder.parse_predicate()) - } - fn read_substs<'b>(&mut self, dcx: &DecodeContext<'b, 'tcx>) -> &'tcx Substs<'tcx> { self.read_opaque(|_, doc| { From 7b073343db09aa51c6ff181aa721d4d022aa6d6f Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Mon, 29 Aug 2016 05:12:03 +0300 Subject: [PATCH 405/443] rustc_metadata: remove astencode tests. --- src/librustc/hir/lowering.rs | 32 ++----- src/librustc_metadata/astencode.rs | 138 --------------------------- src/librustc_metadata/rbml/writer.rs | 25 ----- src/librustc_resolve/lib.rs | 4 +- 4 files changed, 12 insertions(+), 187 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 80e034721d63..f7c3eebdc298 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -81,21 +81,7 @@ pub trait Resolver { // We must keep the set of definitions up to date as we add nodes that weren't in the AST. // This should only return `None` during testing. - fn definitions(&mut self) -> Option<&mut Definitions>; -} - -pub struct DummyResolver; -impl Resolver for DummyResolver { - fn resolve_generated_global_path(&mut self, _path: &hir::Path, _is_value: bool) -> Def { - Def::Err - } - fn get_resolution(&mut self, _id: NodeId) -> Option { - None - } - fn record_resolution(&mut self, _id: NodeId, _def: Def) {} - fn definitions(&mut self) -> Option<&mut Definitions> { - None - } + fn definitions(&mut self) -> &mut Definitions; } pub fn lower_crate(sess: &Session, @@ -177,9 +163,9 @@ impl<'a> LoweringContext<'a> { where F: FnOnce(&mut LoweringContext) -> T { let old_def = self.parent_def; - self.parent_def = match self.resolver.definitions() { - Some(defs) => Some(defs.opt_def_index(parent_id).unwrap()), - None => old_def, + self.parent_def = { + let defs = self.resolver.definitions(); + Some(defs.opt_def_index(parent_id).unwrap()) }; let result = f(self); @@ -1719,9 +1705,10 @@ impl<'a> LoweringContext<'a> { let expr_path = hir::ExprPath(None, self.path_ident(span, id)); let expr = self.expr(span, expr_path, ThinVec::new()); - let def = self.resolver.definitions().map(|defs| { + let def = { + let defs = self.resolver.definitions(); Def::Local(defs.local_def_id(binding), binding) - }).unwrap_or(Def::Err); + }; self.resolver.record_resolution(expr.id, def); expr @@ -1869,11 +1856,12 @@ impl<'a> LoweringContext<'a> { let pat = self.pat(span, pat_ident); let parent_def = self.parent_def; - let def = self.resolver.definitions().map(|defs| { + let def = { + let defs = self.resolver.definitions(); let def_path_data = DefPathData::Binding(name.as_str()); let def_index = defs.create_def_with_parent(parent_def, pat.id, def_path_data); Def::Local(DefId::local(def_index), pat.id) - }).unwrap_or(Def::Err); + }; self.resolver.record_resolution(pat.id, def); pat diff --git a/src/librustc_metadata/astencode.rs b/src/librustc_metadata/astencode.rs index ece4e8b10974..b7781ef620fa 100644 --- a/src/librustc_metadata/astencode.rs +++ b/src/librustc_metadata/astencode.rs @@ -51,11 +51,6 @@ use rbml; use rustc_serialize::{Decodable, Decoder, DecoderHelpers}; use rustc_serialize::{Encodable, EncoderHelpers}; -#[cfg(test)] use std::io::Cursor; -#[cfg(test)] use syntax::parse; -#[cfg(test)] use rustc::hir::print as pprust; -#[cfg(test)] use rustc::hir::lowering::{LoweringContext, DummyResolver}; - struct DecodeContext<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, cdata: &'a cstore::CrateMetadata, @@ -1068,136 +1063,3 @@ fn inlined_item_id_range(ii: &InlinedItem) -> IdRange { ii.visit(&mut visitor); visitor.result() } - -// ______________________________________________________________________ -// Testing of astencode_gen - -#[cfg(test)] -fn encode_item_ast(rbml_w: &mut Encoder, item: &hir::Item) { - rbml_w.start_tag(c::tag_tree as usize); - (*item).encode(rbml_w); - rbml_w.end_tag(); -} - -#[cfg(test)] -fn decode_item_ast(item_doc: rbml::Doc) -> hir::Item { - let chi_doc = item_doc.get(c::tag_tree as usize); - let mut d = reader::Decoder::new(chi_doc); - Decodable::decode(&mut d).unwrap() -} - -#[cfg(test)] -trait FakeExtCtxt { - fn call_site(&self) -> syntax_pos::Span; - fn cfg(&self) -> ast::CrateConfig; - fn ident_of(&self, st: &str) -> ast::Ident; - fn name_of(&self, st: &str) -> ast::Name; - fn parse_sess(&self) -> &parse::ParseSess; -} - -#[cfg(test)] -impl FakeExtCtxt for parse::ParseSess { - fn call_site(&self) -> syntax_pos::Span { - syntax_pos::Span { - lo: syntax_pos::BytePos(0), - hi: syntax_pos::BytePos(0), - expn_id: syntax_pos::NO_EXPANSION, - } - } - fn cfg(&self) -> ast::CrateConfig { Vec::new() } - fn ident_of(&self, st: &str) -> ast::Ident { - parse::token::str_to_ident(st) - } - fn name_of(&self, st: &str) -> ast::Name { - parse::token::intern(st) - } - fn parse_sess(&self) -> &parse::ParseSess { self } -} - -#[cfg(test)] -fn mk_ctxt() -> parse::ParseSess { - parse::ParseSess::new() -} - -#[cfg(test)] -fn with_testing_context T>(f: F) -> T { - let mut resolver = DummyResolver; - let mut lcx = LoweringContext::testing_context(&mut resolver); - f(&mut lcx) -} - -#[cfg(test)] -fn roundtrip(in_item: hir::Item) { - let mut wr = Cursor::new(Vec::new()); - encode_item_ast(&mut Encoder::new(&mut wr), &in_item); - let rbml_doc = rbml::Doc::new(wr.get_ref()); - let out_item = decode_item_ast(rbml_doc); - - assert!(in_item == out_item); -} - -#[test] -fn test_basic() { - let cx = mk_ctxt(); - with_testing_context(|lcx| { - roundtrip(lcx.lower_item("e_item!(&cx, - fn foo() {} - ).unwrap())); - }); -} - -#[test] -fn test_smalltalk() { - let cx = mk_ctxt(); - with_testing_context(|lcx| { - roundtrip(lcx.lower_item("e_item!(&cx, - fn foo() -> isize { 3 + 4 } // first smalltalk program ever executed. - ).unwrap())); - }); -} - -#[test] -fn test_more() { - let cx = mk_ctxt(); - with_testing_context(|lcx| { - roundtrip(lcx.lower_item("e_item!(&cx, - fn foo(x: usize, y: usize) -> usize { - let z = x + y; - return z; - } - ).unwrap())); - }); -} - -#[test] -fn test_simplification() { - use middle::cstore::LOCAL_CRATE; - use rustc::hir::def_id::CRATE_DEF_INDEX; - - let cx = mk_ctxt(); - let item = quote_item!(&cx, - fn new_int_alist() -> alist { - fn eq_int(a: isize, b: isize) -> bool { a == b } - return alist {eq_fn: eq_int, data: Vec::new()}; - } - ).unwrap(); - let cx = mk_ctxt(); - with_testing_context(|lcx| { - let hir_item = lcx.lower_item(&item); - let def_id = DefId { krate: LOCAL_CRATE, index: CRATE_DEF_INDEX }; // dummy - let item_in = InlinedItemRef::Item(def_id, &hir_item); - let (item_out, _) = simplify_ast(item_in); - let item_exp = InlinedItem::Item(def_id, P(lcx.lower_item("e_item!(&cx, - fn new_int_alist() -> alist { - return alist {eq_fn: eq_int, data: Vec::new()}; - } - ).unwrap()))); - match (item_out, item_exp) { - (InlinedItem::Item(_, item_out), InlinedItem::Item(_, item_exp)) => { - assert!(pprust::item_to_string(&item_out) == - pprust::item_to_string(&item_exp)); - } - _ => bug!() - } - }); -} diff --git a/src/librustc_metadata/rbml/writer.rs b/src/librustc_metadata/rbml/writer.rs index d6f4b0d03f22..17b3c392edb3 100644 --- a/src/librustc_metadata/rbml/writer.rs +++ b/src/librustc_metadata/rbml/writer.rs @@ -495,28 +495,3 @@ impl<'a> serialize::Encoder for Encoder<'a> { self.end_tag() } } - -#[test] -fn test_option_int() { - use rbml::reader; - use serialize::{Encodable, Decodable}; - use std::io::Cursor; - - fn test_v(v: Option) { - debug!("v == {:?}", v); - let mut wr = Cursor::new(Vec::new()); - { - let mut rbml_w = Encoder::new(&mut wr); - let _ = v.encode(&mut rbml_w); - } - let rbml_doc = reader::Doc::new(wr.get_ref()); - let mut deser = reader::Decoder::new(rbml_doc); - let v1 = Decodable::decode(&mut deser).unwrap(); - debug!("v1 == {:?}", v1); - assert_eq!(v, v1); - } - - test_v(Some(22)); - test_v(None); - test_v(Some(3)); -} diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 912b39cafff3..31893b0873c7 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1151,8 +1151,8 @@ impl<'a> hir::lowering::Resolver for Resolver<'a> { self.def_map.insert(id, PathResolution::new(def)); } - fn definitions(&mut self) -> Option<&mut Definitions> { - Some(&mut self.definitions) + fn definitions(&mut self) -> &mut Definitions { + &mut self.definitions } } From 82197287a204376ac6c1aa102f8af79bd20246cf Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Mon, 29 Aug 2016 08:55:40 +0300 Subject: [PATCH 406/443] rustc_metadata: combine EncodeContext and rbml::writer::Encoder. --- src/librustc_metadata/astencode.rs | 209 ++-- src/librustc_metadata/csearch.rs | 6 +- src/librustc_metadata/decoder.rs | 6 +- src/librustc_metadata/encoder.rs | 1301 ++++++++++++------------ src/librustc_metadata/index_builder.rs | 67 +- src/librustc_metadata/rbml/writer.rs | 64 +- src/librustc_metadata/tyencode.rs | 7 +- 7 files changed, 798 insertions(+), 862 deletions(-) diff --git a/src/librustc_metadata/astencode.rs b/src/librustc_metadata/astencode.rs index b7781ef620fa..3fd4d0cf2727 100644 --- a/src/librustc_metadata/astencode.rs +++ b/src/librustc_metadata/astencode.rs @@ -46,7 +46,6 @@ use std::io::SeekFrom; use std::io::prelude::*; use rbml::reader; -use rbml::writer::Encoder; use rbml; use rustc_serialize::{Decodable, Decoder, DecoderHelpers}; use rustc_serialize::{Encodable, EncoderHelpers}; @@ -67,9 +66,7 @@ trait tr { // ______________________________________________________________________ // Top-level methods. -pub fn encode_inlined_item(ecx: &e::EncodeContext, - rbml_w: &mut Encoder, - ii: InlinedItemRef) { +pub fn encode_inlined_item(ecx: &mut e::EncodeContext, ii: InlinedItemRef) { let id = match ii { InlinedItemRef::Item(_, i) => i.id, InlinedItemRef::TraitItem(_, ti) => ti.id, @@ -77,22 +74,24 @@ pub fn encode_inlined_item(ecx: &e::EncodeContext, }; debug!("> Encoding inlined item: {} ({:?})", ecx.tcx.node_path_str(id), - rbml_w.writer.seek(SeekFrom::Current(0))); + ecx.writer.seek(SeekFrom::Current(0))); // Folding could be avoided with a smarter encoder. let (ii, expected_id_range) = simplify_ast(ii); let id_range = inlined_item_id_range(&ii); assert_eq!(expected_id_range, id_range); - rbml_w.start_tag(c::tag_ast as usize); - id_range.encode(rbml_w); - encode_ast(rbml_w, &ii); - encode_side_tables_for_ii(ecx, rbml_w, &ii); - rbml_w.end_tag(); + ecx.start_tag(c::tag_ast as usize); + id_range.encode(ecx); + ecx.start_tag(c::tag_tree as usize); + ecx.emit_opaque(|this| ii.encode(this)); + ecx.end_tag(); + encode_side_tables_for_ii(ecx, &ii); + ecx.end_tag(); debug!("< Encoded inlined fn: {} ({:?})", ecx.tcx.node_path_str(id), - rbml_w.writer.seek(SeekFrom::Current(0))); + ecx.writer.seek(SeekFrom::Current(0))); } impl<'a, 'b, 'tcx> ast_map::FoldOps for &'a DecodeContext<'b, 'tcx> { @@ -235,12 +234,6 @@ impl tr for syntax_pos::Span { // We also have to adjust the spans: for now we just insert a dummy span, // but eventually we should add entries to the local codemap as required. -fn encode_ast(rbml_w: &mut Encoder, item: &InlinedItem) { - rbml_w.start_tag(c::tag_tree as usize); - rbml_w.emit_opaque(|this| item.encode(this)); - rbml_w.end_tag(); -} - struct NestedItemsDropper { id_range: IdRange } @@ -385,10 +378,6 @@ impl tr for Def { // ______________________________________________________________________ // Encoding and decoding of freevar information -fn encode_freevar_entry(rbml_w: &mut Encoder, fv: &hir::Freevar) { - (*fv).encode(rbml_w).unwrap(); -} - impl<'a> reader::Decoder<'a> { fn read_freevar_entry(&mut self, dcx: &DecodeContext) -> hir::Freevar { @@ -409,26 +398,27 @@ impl tr for hir::Freevar { // ______________________________________________________________________ // Encoding and decoding of MethodCallee -fn encode_method_callee<'a, 'tcx>(ecx: &e::EncodeContext<'a, 'tcx>, - rbml_w: &mut Encoder, - autoderef: u32, - method: &ty::MethodCallee<'tcx>) { - use rustc_serialize::Encoder; +impl<'a, 'tcx> e::EncodeContext<'a, 'tcx> { + fn encode_method_callee(&mut self, + autoderef: u32, + method: &ty::MethodCallee<'tcx>) { + use rustc_serialize::Encoder; - rbml_w.emit_struct("MethodCallee", 4, |rbml_w| { - rbml_w.emit_struct_field("autoderef", 0, |rbml_w| { - autoderef.encode(rbml_w) - }); - rbml_w.emit_struct_field("def_id", 1, |rbml_w| { - method.def_id.encode(rbml_w) - }); - rbml_w.emit_struct_field("ty", 2, |rbml_w| { - Ok(rbml_w.emit_ty(ecx, method.ty)) - }); - rbml_w.emit_struct_field("substs", 3, |rbml_w| { - Ok(rbml_w.emit_substs(ecx, &method.substs)) - }) - }).unwrap(); + self.emit_struct("MethodCallee", 4, |this| { + this.emit_struct_field("autoderef", 0, |this| { + autoderef.encode(this) + }); + this.emit_struct_field("def_id", 1, |this| { + method.def_id.encode(this) + }); + this.emit_struct_field("ty", 2, |this| { + Ok(this.emit_ty(method.ty)) + }); + this.emit_struct_field("substs", 3, |this| { + Ok(this.emit_substs(&method.substs)) + }) + }).unwrap(); + } } impl<'a, 'tcx> reader::Decoder<'a> { @@ -453,27 +443,25 @@ impl<'a, 'tcx> reader::Decoder<'a> { } } -pub fn encode_cast_kind(ebml_w: &mut Encoder, kind: cast::CastKind) { - kind.encode(ebml_w).unwrap(); -} - // ______________________________________________________________________ // Encoding and decoding the side tables -impl<'a, 'tcx> Encoder<'a> { - fn emit_region(&mut self, ecx: &e::EncodeContext, r: &'tcx ty::Region) { +impl<'a, 'tcx> e::EncodeContext<'a, 'tcx> { + fn emit_region(&mut self, r: &'tcx ty::Region) { + let cx = self.ty_str_ctxt(); self.emit_opaque(|this| Ok(tyencode::enc_region(&mut this.cursor, - &ecx.ty_str_ctxt(), + &cx, r))); } - fn emit_ty<'b>(&mut self, ecx: &e::EncodeContext<'b, 'tcx>, ty: Ty<'tcx>) { + fn emit_ty(&mut self, ty: Ty<'tcx>) { + let cx = self.ty_str_ctxt(); self.emit_opaque(|this| Ok(tyencode::enc_ty(&mut this.cursor, - &ecx.ty_str_ctxt(), + &cx, ty))); } - fn emit_upvar_capture(&mut self, ecx: &e::EncodeContext, capture: &ty::UpvarCapture) { + fn emit_upvar_capture(&mut self, capture: &ty::UpvarCapture<'tcx>) { use rustc_serialize::Encoder; self.emit_enum("UpvarCapture", |this| { @@ -486,22 +474,21 @@ impl<'a, 'tcx> Encoder<'a> { this.emit_enum_variant_arg(0, |this| kind.encode(this)); this.emit_enum_variant_arg(1, - |this| Ok(this.emit_region(ecx, region))) + |this| Ok(this.emit_region(region))) }) } } }).unwrap() } - fn emit_substs<'b>(&mut self, ecx: &e::EncodeContext<'b, 'tcx>, - substs: &Substs<'tcx>) { + fn emit_substs(&mut self, substs: &Substs<'tcx>) { + let cx = self.ty_str_ctxt(); self.emit_opaque(|this| Ok(tyencode::enc_substs(&mut this.cursor, - &ecx.ty_str_ctxt(), + &cx, substs))); } - fn emit_auto_adjustment<'b>(&mut self, ecx: &e::EncodeContext<'b, 'tcx>, - adj: &adjustment::AutoAdjustment<'tcx>) { + fn emit_auto_adjustment(&mut self, adj: &adjustment::AutoAdjustment<'tcx>) { use rustc_serialize::Encoder; self.emit_enum("AutoAdjustment", |this| { @@ -525,21 +512,20 @@ impl<'a, 'tcx> Encoder<'a> { adjustment::AdjustDerefRef(ref auto_deref_ref) => { this.emit_enum_variant("AdjustDerefRef", 4, 2, |this| { this.emit_enum_variant_arg(0, - |this| Ok(this.emit_auto_deref_ref(ecx, auto_deref_ref))) + |this| Ok(this.emit_auto_deref_ref(auto_deref_ref))) }) } adjustment::AdjustNeverToAny(ref ty) => { this.emit_enum_variant("AdjustNeverToAny", 5, 1, |this| { - this.emit_enum_variant_arg(0, |this| Ok(this.emit_ty(ecx, ty))) + this.emit_enum_variant_arg(0, |this| Ok(this.emit_ty(ty))) }) } } }); } - fn emit_autoref<'b>(&mut self, ecx: &e::EncodeContext<'b, 'tcx>, - autoref: &adjustment::AutoRef<'tcx>) { + fn emit_autoref(&mut self, autoref: &adjustment::AutoRef<'tcx>) { use rustc_serialize::Encoder; self.emit_enum("AutoRef", |this| { @@ -547,7 +533,7 @@ impl<'a, 'tcx> Encoder<'a> { &adjustment::AutoPtr(r, m) => { this.emit_enum_variant("AutoPtr", 0, 2, |this| { this.emit_enum_variant_arg(0, - |this| Ok(this.emit_region(ecx, r))); + |this| Ok(this.emit_region(r))); this.emit_enum_variant_arg(1, |this| m.encode(this)) }) } @@ -560,8 +546,7 @@ impl<'a, 'tcx> Encoder<'a> { }); } - fn emit_auto_deref_ref<'b>(&mut self, ecx: &e::EncodeContext<'b, 'tcx>, - auto_deref_ref: &adjustment::AutoDerefRef<'tcx>) { + fn emit_auto_deref_ref(&mut self, auto_deref_ref: &adjustment::AutoDerefRef<'tcx>) { use rustc_serialize::Encoder; self.emit_struct("AutoDerefRef", 2, |this| { @@ -571,7 +556,7 @@ impl<'a, 'tcx> Encoder<'a> { this.emit_option(|this| { match auto_deref_ref.autoref { None => this.emit_option_none(), - Some(ref a) => this.emit_option_some(|this| Ok(this.emit_autoref(ecx, a))), + Some(ref a) => this.emit_option_some(|this| Ok(this.emit_autoref(a))), } }) }); @@ -581,20 +566,18 @@ impl<'a, 'tcx> Encoder<'a> { match auto_deref_ref.unsize { None => this.emit_option_none(), Some(target) => this.emit_option_some(|this| { - Ok(this.emit_ty(ecx, target)) + Ok(this.emit_ty(target)) }) } }) }) }); } -} -impl<'a> Encoder<'a> { fn tag(&mut self, tag_id: c::astencode_tag, f: F) where - F: FnOnce(&mut Encoder<'a>), + F: FnOnce(&mut Self), { self.start_tag(tag_id as usize); f(self); @@ -606,68 +589,61 @@ impl<'a> Encoder<'a> { } } -struct SideTableEncodingIdVisitor<'a, 'b:'a, 'c:'a, 'tcx:'c> { - ecx: &'a e::EncodeContext<'c, 'tcx>, - rbml_w: &'a mut Encoder<'b>, +struct SideTableEncodingIdVisitor<'a, 'b:'a, 'tcx:'b> { + ecx: &'a mut e::EncodeContext<'b, 'tcx>, } -impl<'a, 'b, 'c, 'tcx, 'v> Visitor<'v> for - SideTableEncodingIdVisitor<'a, 'b, 'c, 'tcx> { +impl<'a, 'b, 'tcx, 'v> Visitor<'v> for SideTableEncodingIdVisitor<'a, 'b, 'tcx> { fn visit_id(&mut self, id: ast::NodeId) { - encode_side_tables_for_id(self.ecx, self.rbml_w, id) + encode_side_tables_for_id(self.ecx, id) } } -fn encode_side_tables_for_ii(ecx: &e::EncodeContext, - rbml_w: &mut Encoder, - ii: &InlinedItem) { - rbml_w.start_tag(c::tag_table as usize); +fn encode_side_tables_for_ii(ecx: &mut e::EncodeContext, ii: &InlinedItem) { + ecx.start_tag(c::tag_table as usize); ii.visit(&mut SideTableEncodingIdVisitor { - ecx: ecx, - rbml_w: rbml_w + ecx: ecx }); - rbml_w.end_tag(); + ecx.end_tag(); } -fn encode_side_tables_for_id(ecx: &e::EncodeContext, - rbml_w: &mut Encoder, - id: ast::NodeId) { +fn encode_side_tables_for_id(ecx: &mut e::EncodeContext, id: ast::NodeId) { let tcx = ecx.tcx; debug!("Encoding side tables for id {}", id); if let Some(def) = tcx.expect_def_or_none(id) { - rbml_w.tag(c::tag_table_def, |rbml_w| { - rbml_w.id(id); - def.encode(rbml_w).unwrap(); + ecx.tag(c::tag_table_def, |ecx| { + ecx.id(id); + def.encode(ecx).unwrap(); }) } if let Some(ty) = tcx.node_types().get(&id) { - rbml_w.tag(c::tag_table_node_type, |rbml_w| { - rbml_w.id(id); - rbml_w.emit_ty(ecx, *ty); + ecx.tag(c::tag_table_node_type, |ecx| { + ecx.id(id); + ecx.emit_ty(*ty); }) } if let Some(item_substs) = tcx.tables.borrow().item_substs.get(&id) { - rbml_w.tag(c::tag_table_item_subst, |rbml_w| { - rbml_w.id(id); - rbml_w.emit_substs(ecx, &item_substs.substs); + ecx.tag(c::tag_table_item_subst, |ecx| { + ecx.id(id); + ecx.emit_substs(&item_substs.substs); }) } if let Some(fv) = tcx.freevars.borrow().get(&id) { - rbml_w.tag(c::tag_table_freevars, |rbml_w| { - rbml_w.id(id); - rbml_w.emit_from_vec(fv, |rbml_w, fv_entry| { - Ok(encode_freevar_entry(rbml_w, fv_entry)) + ecx.tag(c::tag_table_freevars, |ecx| { + ecx.id(id); + ecx.emit_from_vec(fv, |ecx, fv_entry| { + fv_entry.encode(ecx) }); }); for freevar in fv { - rbml_w.tag(c::tag_table_upvar_capture_map, |rbml_w| { - rbml_w.id(id); + ecx.tag(c::tag_table_upvar_capture_map, |ecx| { + ecx.id(id); let var_id = freevar.def.var_id(); let upvar_id = ty::UpvarId { @@ -680,17 +656,17 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext, .get(&upvar_id) .unwrap() .clone(); - var_id.encode(rbml_w); - rbml_w.emit_upvar_capture(ecx, &upvar_capture); + var_id.encode(ecx); + ecx.emit_upvar_capture(&upvar_capture); }) } } let method_call = ty::MethodCall::expr(id); if let Some(method) = tcx.tables.borrow().method_map.get(&method_call) { - rbml_w.tag(c::tag_table_method_map, |rbml_w| { - rbml_w.id(id); - encode_method_callee(ecx, rbml_w, method_call.autoderef, method) + ecx.tag(c::tag_table_method_map, |ecx| { + ecx.id(id); + ecx.encode_method_callee(method_call.autoderef, method) }) } @@ -700,10 +676,9 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext, for autoderef in 0..adj.autoderefs { let method_call = ty::MethodCall::autoderef(id, autoderef as u32); if let Some(method) = tcx.tables.borrow().method_map.get(&method_call) { - rbml_w.tag(c::tag_table_method_map, |rbml_w| { - rbml_w.id(id); - encode_method_callee(ecx, rbml_w, - method_call.autoderef, method) + ecx.tag(c::tag_table_method_map, |ecx| { + ecx.id(id); + ecx.encode_method_callee(method_call.autoderef, method) }) } } @@ -711,23 +686,23 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext, _ => {} } - rbml_w.tag(c::tag_table_adjustments, |rbml_w| { - rbml_w.id(id); - rbml_w.emit_auto_adjustment(ecx, adjustment); + ecx.tag(c::tag_table_adjustments, |ecx| { + ecx.id(id); + ecx.emit_auto_adjustment(adjustment); }) } if let Some(cast_kind) = tcx.cast_kinds.borrow().get(&id) { - rbml_w.tag(c::tag_table_cast_kinds, |rbml_w| { - rbml_w.id(id); - encode_cast_kind(rbml_w, *cast_kind) + ecx.tag(c::tag_table_cast_kinds, |ecx| { + ecx.id(id); + cast_kind.encode(ecx).unwrap() }) } if let Some(qualif) = tcx.const_qualif_map.borrow().get(&id) { - rbml_w.tag(c::tag_table_const_qualif, |rbml_w| { - rbml_w.id(id); - qualif.encode(rbml_w).unwrap() + ecx.tag(c::tag_table_const_qualif, |ecx| { + ecx.id(id); + qualif.encode(ecx).unwrap() }) } } diff --git a/src/librustc_metadata/csearch.rs b/src/librustc_metadata/csearch.rs index 21cf3240321b..c37b2de751f9 100644 --- a/src/librustc_metadata/csearch.rs +++ b/src/librustc_metadata/csearch.rs @@ -13,6 +13,7 @@ use common; use decoder; use encoder; use loader; +use rbml; use middle::cstore::{InlinedItem, CrateStore, CrateSource, ChildItem, ExternCrate, DefLike}; use middle::cstore::{NativeLibraryKind, LinkMeta, LinkagePreference}; @@ -707,15 +708,16 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { mir_map: &MirMap<'tcx>, krate: &hir::Crate) -> Vec { + let type_abbrevs = RefCell::new(FnvHashMap()); let ecx = encoder::EncodeContext { - diag: tcx.sess.diagnostic(), + rbml_w: rbml::writer::Encoder::new(), tcx: tcx, reexports: reexports, link_meta: link_meta, cstore: self, reachable: reachable, mir_map: mir_map, - type_abbrevs: RefCell::new(FnvHashMap()), + type_abbrevs: &type_abbrevs, }; encoder::encode_metadata(ecx, krate) diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 624bffb7e036..ecddab0d0609 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -812,10 +812,8 @@ pub fn maybe_get_item_mir<'a, 'tcx>(cdata: Cmd, }; let mut decoder = reader::Decoder::new(mir_doc); - let mut mir = decoder.read_opaque(|opaque_decoder, _| { - tls::enter_decoding_context(&dcx, opaque_decoder, |_, opaque_decoder| { - Decodable::decode(opaque_decoder) - }) + let mut mir = tls::enter_decoding_context(&dcx, |_| { + Decodable::decode(&mut decoder) }).unwrap(); assert!(decoder.position() == mir_doc.end); diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index e228bf743026..4bc8caf037ae 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -21,7 +21,7 @@ use def_key; use tyencode; use index::{self, IndexData}; -use middle::cstore::{InlinedItemRef, LinkMeta, tls}; +use middle::cstore::{InlinedItemRef, LinkMeta}; use rustc::hir::def; use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId}; use middle::dependency_format::Linkage; @@ -38,14 +38,14 @@ use rustc_serialize::Encodable; use std::cell::RefCell; use std::io::prelude::*; use std::io::{Cursor, SeekFrom}; +use std::ops::{Deref, DerefMut}; use std::rc::Rc; use std::u32; use syntax::ast::{self, NodeId, Name, CRATE_NODE_ID, CrateNum}; use syntax::attr; -use errors::Handler; use syntax; use syntax_pos::BytePos; -use rbml::writer::Encoder; +use rbml; use rustc::hir::{self, PatKind}; use rustc::hir::intravisit::Visitor; @@ -55,61 +55,65 @@ use rustc::hir::map::DefKey; use super::index_builder::{FromId, IndexBuilder, ItemContentBuilder, Untracked, XRef}; pub struct EncodeContext<'a, 'tcx: 'a> { - pub diag: &'a Handler, + pub rbml_w: rbml::writer::Encoder, pub tcx: TyCtxt<'a, 'tcx, 'tcx>, pub reexports: &'a def::ExportMap, pub link_meta: &'a LinkMeta, pub cstore: &'a cstore::CStore, - pub type_abbrevs: tyencode::abbrev_map<'tcx>, + pub type_abbrevs: &'a tyencode::abbrev_map<'tcx>, pub reachable: &'a NodeSet, pub mir_map: &'a MirMap<'tcx>, } -impl<'a, 'tcx> EncodeContext<'a,'tcx> { - fn local_id(&self, def_id: DefId) -> NodeId { - self.tcx.map.as_local_node_id(def_id).unwrap() +impl<'a, 'tcx> Deref for EncodeContext<'a, 'tcx> { + type Target = rbml::writer::Encoder; + fn deref(&self) -> &Self::Target { + &self.rbml_w } } -fn encode_name(rbml_w: &mut Encoder, name: Name) { - rbml_w.wr_tagged_str(tag_paths_data_name, &name.as_str()); +impl<'a, 'tcx> DerefMut for EncodeContext<'a, 'tcx> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.rbml_w + } } -fn encode_def_id(rbml_w: &mut Encoder, id: DefId) { - rbml_w.wr_tagged_u64(tag_def_id, def_to_u64(id)); +fn encode_name(ecx: &mut EncodeContext, name: Name) { + ecx.wr_tagged_str(tag_paths_data_name, &name.as_str()); } -fn encode_def_key(rbml_w: &mut Encoder, key: DefKey) { +fn encode_def_id(ecx: &mut EncodeContext, id: DefId) { + ecx.wr_tagged_u64(tag_def_id, def_to_u64(id)); +} + +fn encode_def_key(ecx: &mut EncodeContext, key: DefKey) { let simple_key = def_key::simplify_def_key(key); - rbml_w.start_tag(tag_def_key); - simple_key.encode(rbml_w); - rbml_w.end_tag(); + ecx.start_tag(tag_def_key); + simple_key.encode(ecx); + ecx.end_tag(); } /// For every DefId that we create a metadata item for, we include a /// serialized copy of its DefKey, which allows us to recreate a path. -fn encode_def_id_and_key(ecx: &EncodeContext, - rbml_w: &mut Encoder, - def_id: DefId) -{ - encode_def_id(rbml_w, def_id); +fn encode_def_id_and_key(ecx: &mut EncodeContext, def_id: DefId) { + encode_def_id(ecx, def_id); let def_key = ecx.tcx.map.def_key(def_id); - encode_def_key(rbml_w, def_key); + encode_def_key(ecx, def_key); } -fn encode_trait_ref<'a, 'tcx>(rbml_w: &mut Encoder, - ecx: &EncodeContext<'a, 'tcx>, +fn encode_trait_ref<'a, 'tcx>(ecx: &mut EncodeContext<'a, 'tcx>, trait_ref: ty::TraitRef<'tcx>, tag: usize) { - rbml_w.start_tag(tag); - tyencode::enc_trait_ref(rbml_w.writer, &ecx.ty_str_ctxt(), trait_ref); - rbml_w.mark_stable_position(); - rbml_w.end_tag(); + let cx = ecx.ty_str_ctxt(); + ecx.start_tag(tag); + tyencode::enc_trait_ref(&mut ecx.writer, &cx, trait_ref); + ecx.mark_stable_position(); + ecx.end_tag(); } // Item info table encoding -fn encode_family(rbml_w: &mut Encoder, c: char) { - rbml_w.wr_tagged_u8(tag_items_data_item_family, c as u8); +fn encode_family(ecx: &mut EncodeContext, c: char) { + ecx.wr_tagged_u8(tag_items_data_item_family, c as u8); } pub fn def_to_u64(did: DefId) -> u64 { @@ -121,21 +125,18 @@ pub fn def_to_string(_tcx: TyCtxt, did: DefId) -> String { format!("{}:{}", did.krate, did.index.as_usize()) } -fn encode_item_variances(rbml_w: &mut Encoder, - ecx: &EncodeContext, - id: NodeId) { +fn encode_item_variances(ecx: &mut EncodeContext, id: NodeId) { let v = ecx.tcx.item_variances(ecx.tcx.map.local_def_id(id)); - rbml_w.start_tag(tag_item_variances); - v.encode(rbml_w); - rbml_w.end_tag(); + ecx.start_tag(tag_item_variances); + v.encode(ecx); + ecx.end_tag(); } -impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> { - fn encode_bounds_and_type_for_item(&mut self, - id: NodeId) { - let ecx = self.ecx(); - self.encode_bounds_and_type(&ecx.tcx.lookup_item_type(ecx.tcx.map.local_def_id(id)), - &ecx.tcx.lookup_predicates(ecx.tcx.map.local_def_id(id))); +impl<'a, 'b, 'tcx> ItemContentBuilder<'a, 'b, 'tcx> { + fn encode_bounds_and_type_for_item(&mut self, def_id: DefId) { + let tcx = self.tcx; + self.encode_bounds_and_type(&tcx.lookup_item_type(def_id), + &tcx.lookup_predicates(def_id)); } fn encode_bounds_and_type(&mut self, @@ -146,61 +147,58 @@ impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> { } } -fn encode_variant_id(rbml_w: &mut Encoder, vid: DefId) { +fn encode_variant_id(ecx: &mut EncodeContext, vid: DefId) { let id = def_to_u64(vid); - rbml_w.wr_tagged_u64(tag_items_data_item_variant, id); - rbml_w.wr_tagged_u64(tag_mod_child, id); + ecx.wr_tagged_u64(tag_items_data_item_variant, id); + ecx.wr_tagged_u64(tag_mod_child, id); } -fn write_closure_type<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, - rbml_w: &mut Encoder, - closure_type: &ty::ClosureTy<'tcx>) { - tyencode::enc_closure_ty(rbml_w.writer, &ecx.ty_str_ctxt(), closure_type); - rbml_w.mark_stable_position(); +fn write_closure_type<'a, 'tcx>(ecx: &mut EncodeContext<'a, 'tcx>, + closure_type: &ty::ClosureTy<'tcx>) { + let cx = ecx.ty_str_ctxt(); + tyencode::enc_closure_ty(&mut ecx.writer, &cx, closure_type); + ecx.mark_stable_position(); } -impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> { - fn encode_type(&mut self, - typ: Ty<'tcx>) { - let ecx = self.ecx; - self.rbml_w.start_tag(tag_items_data_item_type); - tyencode::enc_ty(self.rbml_w.writer, &ecx.ty_str_ctxt(), typ); - self.rbml_w.mark_stable_position(); - self.rbml_w.end_tag(); +impl<'a, 'b, 'tcx> ItemContentBuilder<'a, 'b, 'tcx> { + fn encode_type(&mut self, typ: Ty<'tcx>) { + let cx = self.ty_str_ctxt(); + self.start_tag(tag_items_data_item_type); + tyencode::enc_ty(&mut self.writer, &cx, typ); + self.mark_stable_position(); + self.end_tag(); } fn encode_disr_val(&mut self, disr_val: ty::Disr) { // convert to u64 so just the number is printed, without any type info - self.rbml_w.wr_tagged_str(tag_disr_val, &disr_val.to_u64_unchecked().to_string()); + self.wr_tagged_str(tag_disr_val, &disr_val.to_u64_unchecked().to_string()); } fn encode_parent_item(&mut self, id: DefId) { - self.rbml_w.wr_tagged_u64(tag_items_data_parent_item, def_to_u64(id)); + self.wr_tagged_u64(tag_items_data_parent_item, def_to_u64(id)); } fn encode_struct_fields(&mut self, variant: ty::VariantDef) { for f in &variant.fields { if variant.kind == ty::VariantKind::Tuple { - self.rbml_w.start_tag(tag_item_unnamed_field); + self.start_tag(tag_item_unnamed_field); } else { - self.rbml_w.start_tag(tag_item_field); - encode_name(self.rbml_w, f.name); + self.start_tag(tag_item_field); + encode_name(self, f.name); } self.encode_struct_field_family(f.vis); - encode_def_id(self.rbml_w, f.did); - self.rbml_w.end_tag(); + encode_def_id(self, f.did); + self.end_tag(); } } } -impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> { - fn encode_enum_variant_infos(&mut self, - enum_did: DefId) { +impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { + fn encode_enum_variant_infos(&mut self, enum_did: DefId) { debug!("encode_enum_variant_info(enum_did={:?})", enum_did); - let ecx = self.ecx(); - let def = ecx.tcx.lookup_adt_def(enum_did); + let def = self.tcx.lookup_adt_def(enum_did); self.encode_fields(enum_did); for (i, variant) in def.variants.iter().enumerate() { self.record(variant.did, @@ -210,7 +208,7 @@ impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> { } } -impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> { +impl<'a, 'b, 'tcx> ItemContentBuilder<'a, 'b, 'tcx> { /// Encode data for the given variant of the given ADT. The /// index of the variant is untracked: this is ok because we /// will have to lookup the adt-def by its id, and that gives us @@ -219,42 +217,39 @@ impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> { fn encode_enum_variant_info(&mut self, (enum_did, Untracked(index)): (DefId, Untracked)) { - let ecx = self.ecx; - let def = ecx.tcx.lookup_adt_def(enum_did); + let tcx = self.tcx; + let def = tcx.lookup_adt_def(enum_did); let variant = &def.variants[index]; let vid = variant.did; - let variant_node_id = ecx.local_id(vid); - encode_def_id_and_key(ecx, self.rbml_w, vid); - encode_family(self.rbml_w, match variant.kind { + encode_def_id_and_key(self, vid); + encode_family(self, match variant.kind { ty::VariantKind::Struct => 'V', ty::VariantKind::Tuple => 'v', ty::VariantKind::Unit => 'w', }); - encode_name(self.rbml_w, variant.name); + encode_name(self, variant.name); self.encode_parent_item(enum_did); - let enum_id = ecx.tcx.map.as_local_node_id(enum_did).unwrap(); - let enum_vis = &ecx.tcx.map.expect_item(enum_id).vis; + let enum_id = tcx.map.as_local_node_id(enum_did).unwrap(); + let enum_vis = &tcx.map.expect_item(enum_id).vis; self.encode_visibility(enum_vis); - let attrs = ecx.tcx.get_attrs(vid); - encode_attributes(self.rbml_w, &attrs); + let attrs = tcx.get_attrs(vid); + encode_attributes(self, &attrs); self.encode_repr_attrs(&attrs); - let stab = ecx.tcx.lookup_stability(vid); - let depr = ecx.tcx.lookup_deprecation(vid); - encode_stability(self.rbml_w, stab); - encode_deprecation(self.rbml_w, depr); + let stab = tcx.lookup_stability(vid); + let depr = tcx.lookup_deprecation(vid); + encode_stability(self, stab); + encode_deprecation(self, depr); self.encode_struct_fields(variant); self.encode_disr_val(variant.disr_val); - self.encode_bounds_and_type_for_item(variant_node_id); + self.encode_bounds_and_type_for_item(vid); } } -fn encode_reexports(ecx: &EncodeContext, - rbml_w: &mut Encoder, - id: NodeId) { +fn encode_reexports(ecx: &mut EncodeContext, id: NodeId) { debug!("(encoding info for module) encoding reexports for {}", id); match ecx.reexports.get(&id) { Some(exports) => { @@ -265,58 +260,58 @@ fn encode_reexports(ecx: &EncodeContext, exp.name, exp.def_id, id); - rbml_w.start_tag(tag_items_data_item_reexport); - rbml_w.wr_tagged_u64(tag_items_data_item_reexport_def_id, - def_to_u64(exp.def_id)); - rbml_w.wr_tagged_str(tag_items_data_item_reexport_name, - &exp.name.as_str()); - rbml_w.end_tag(); + ecx.start_tag(tag_items_data_item_reexport); + ecx.wr_tagged_u64(tag_items_data_item_reexport_def_id, + def_to_u64(exp.def_id)); + ecx.wr_tagged_str(tag_items_data_item_reexport_name, + &exp.name.as_str()); + ecx.end_tag(); } }, None => debug!("(encoding info for module) found no reexports for {}", id), } } -impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> { +impl<'a, 'b, 'tcx> ItemContentBuilder<'a, 'b, 'tcx> { fn encode_info_for_mod(&mut self, FromId(id, (md, attrs, name, vis)): FromId<(&hir::Mod, &[ast::Attribute], Name, &hir::Visibility)>) { - let ecx = self.ecx(); + let tcx = self.tcx; - encode_def_id_and_key(ecx, self.rbml_w, ecx.tcx.map.local_def_id(id)); - encode_family(self.rbml_w, 'm'); - encode_name(self.rbml_w, name); + encode_def_id_and_key(self, tcx.map.local_def_id(id)); + encode_family(self, 'm'); + encode_name(self, name); debug!("(encoding info for module) encoding info for module ID {}", id); // Encode info about all the module children. for item_id in &md.item_ids { - self.rbml_w.wr_tagged_u64(tag_mod_child, - def_to_u64(ecx.tcx.map.local_def_id(item_id.id))); + self.wr_tagged_u64(tag_mod_child, + def_to_u64(tcx.map.local_def_id(item_id.id))); } self.encode_visibility(vis); - let stab = ecx.tcx.lookup_stability(ecx.tcx.map.local_def_id(id)); - let depr = ecx.tcx.lookup_deprecation(ecx.tcx.map.local_def_id(id)); - encode_stability(self.rbml_w, stab); - encode_deprecation(self.rbml_w, depr); + let stab = tcx.lookup_stability(tcx.map.local_def_id(id)); + let depr = tcx.lookup_deprecation(tcx.map.local_def_id(id)); + encode_stability(self, stab); + encode_deprecation(self, depr); // Encode the reexports of this module, if this module is public. if *vis == hir::Public { debug!("(encoding info for module) encoding reexports for {}", id); - encode_reexports(ecx, self.rbml_w, id); + encode_reexports(self, id); } - encode_attributes(self.rbml_w, attrs); + encode_attributes(self, attrs); } fn encode_struct_field_family(&mut self, visibility: ty::Visibility) { - encode_family(self.rbml_w, if visibility.is_public() { 'g' } else { 'N' }); + encode_family(self, if visibility.is_public() { 'g' } else { 'N' }); } fn encode_visibility(&mut self, visibility: T) { let ch = if visibility.is_public() { 'y' } else { 'i' }; - self.rbml_w.wr_tagged_u8(tag_items_data_item_visibility, ch as u8); + self.wr_tagged_u8(tag_items_data_item_visibility, ch as u8); } } @@ -336,43 +331,43 @@ impl HasVisibility for ty::Visibility { } } -fn encode_constness(rbml_w: &mut Encoder, constness: hir::Constness) { - rbml_w.start_tag(tag_items_data_item_constness); +fn encode_constness(ecx: &mut EncodeContext, constness: hir::Constness) { + ecx.start_tag(tag_items_data_item_constness); let ch = match constness { hir::Constness::Const => 'c', hir::Constness::NotConst => 'n', }; - rbml_w.wr_str(&ch.to_string()); - rbml_w.end_tag(); + ecx.wr_str(&ch.to_string()); + ecx.end_tag(); } -fn encode_defaultness(rbml_w: &mut Encoder, defaultness: hir::Defaultness) { +fn encode_defaultness(ecx: &mut EncodeContext, defaultness: hir::Defaultness) { let ch = match defaultness { hir::Defaultness::Default => 'd', hir::Defaultness::Final => 'f', }; - rbml_w.wr_tagged_u8(tag_items_data_item_defaultness, ch as u8); + ecx.wr_tagged_u8(tag_items_data_item_defaultness, ch as u8); } -fn encode_explicit_self(rbml_w: &mut Encoder, +fn encode_explicit_self(ecx: &mut EncodeContext, explicit_self: &ty::ExplicitSelfCategory) { let tag = tag_item_trait_method_explicit_self; // Encode the base self type. match *explicit_self { ty::ExplicitSelfCategory::Static => { - rbml_w.wr_tagged_bytes(tag, &['s' as u8]); + ecx.wr_tagged_bytes(tag, &['s' as u8]); } ty::ExplicitSelfCategory::ByValue => { - rbml_w.wr_tagged_bytes(tag, &['v' as u8]); + ecx.wr_tagged_bytes(tag, &['v' as u8]); } ty::ExplicitSelfCategory::ByBox => { - rbml_w.wr_tagged_bytes(tag, &['~' as u8]); + ecx.wr_tagged_bytes(tag, &['~' as u8]); } ty::ExplicitSelfCategory::ByReference(_, m) => { // FIXME(#4846) encode custom lifetime let ch = encode_mutability(m); - rbml_w.wr_tagged_bytes(tag, &['&' as u8, ch]); + ecx.wr_tagged_bytes(tag, &['&' as u8, ch]); } } @@ -384,14 +379,14 @@ fn encode_explicit_self(rbml_w: &mut Encoder, } } -fn encode_item_sort(rbml_w: &mut Encoder, sort: char) { - rbml_w.wr_tagged_u8(tag_item_trait_item_sort, sort as u8); +fn encode_item_sort(ecx: &mut EncodeContext, sort: char) { + ecx.wr_tagged_u8(tag_item_trait_item_sort, sort as u8); } -impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> { +impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { fn encode_fields(&mut self, adt_def_id: DefId) { - let def = self.ecx().tcx.lookup_adt_def(adt_def_id); + let def = self.tcx.lookup_adt_def(adt_def_id); for (variant_index, variant) in def.variants.iter().enumerate() { for (field_index, field) in variant.fields.iter().enumerate() { self.record(field.did, @@ -402,7 +397,7 @@ impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> { } } -impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> { +impl<'a, 'b, 'tcx> ItemContentBuilder<'a, 'b, 'tcx> { /// Encode data for the given field of the given variant of the /// given ADT. The indices of the variant/field are untracked: /// this is ok because we will have to lookup the adt-def by its @@ -412,131 +407,120 @@ impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> { fn encode_field(&mut self, (adt_def_id, Untracked((variant_index, field_index))): (DefId, Untracked<(usize, usize)>)) { - let ecx = self.ecx(); - let def = ecx.tcx.lookup_adt_def(adt_def_id); + let tcx = self.tcx; + let def = tcx.lookup_adt_def(adt_def_id); let variant = &def.variants[variant_index]; let field = &variant.fields[field_index]; let nm = field.name; - let id = ecx.local_id(field.did); - debug!("encode_field: encoding {} {}", nm, id); + debug!("encode_field: encoding {} {:?}", nm, field.did); self.encode_struct_field_family(field.vis); - encode_name(self.rbml_w, nm); - self.encode_bounds_and_type_for_item(id); - encode_def_id_and_key(ecx, self.rbml_w, field.did); + encode_name(self, nm); + self.encode_bounds_and_type_for_item(field.did); + encode_def_id_and_key(self, field.did); - let stab = ecx.tcx.lookup_stability(field.did); - let depr = ecx.tcx.lookup_deprecation(field.did); - encode_stability(self.rbml_w, stab); - encode_deprecation(self.rbml_w, depr); + let stab = tcx.lookup_stability(field.did); + let depr = tcx.lookup_deprecation(field.did); + encode_stability(self, stab); + encode_deprecation(self, depr); } -} -impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> { fn encode_struct_ctor(&mut self, (struct_def_id, struct_node_id, ctor_node_id): (DefId, ast::NodeId, ast::NodeId)) { - let ecx = self.ecx(); - let def = ecx.tcx.lookup_adt_def(struct_def_id); + let tcx = self.tcx; + let def = tcx.lookup_adt_def(struct_def_id); let variant = def.struct_variant(); - let item = ecx.tcx.map.expect_item(struct_node_id); - let ctor_def_id = ecx.tcx.map.local_def_id(ctor_node_id); - encode_def_id_and_key(ecx, self.rbml_w, ctor_def_id); - encode_family(self.rbml_w, match variant.kind { + let item = tcx.map.expect_item(struct_node_id); + let ctor_def_id = tcx.map.local_def_id(ctor_node_id); + encode_def_id_and_key(self, ctor_def_id); + encode_family(self, match variant.kind { ty::VariantKind::Struct => 'S', ty::VariantKind::Tuple => 's', ty::VariantKind::Unit => 'u', }); - self.encode_bounds_and_type_for_item(ctor_node_id); - encode_name(self.rbml_w, item.name); + self.encode_bounds_and_type_for_item(ctor_def_id); + encode_name(self, item.name); self.encode_parent_item(struct_def_id); - let stab = ecx.tcx.lookup_stability(ctor_def_id); - let depr = ecx.tcx.lookup_deprecation(ctor_def_id); - encode_stability(self.rbml_w, stab); - encode_deprecation(self.rbml_w, depr); + let stab = tcx.lookup_stability(ctor_def_id); + let depr = tcx.lookup_deprecation(ctor_def_id); + encode_stability(self, stab); + encode_deprecation(self, depr); // indicate that this is a tuple struct ctor, because // downstream users will normally want the tuple struct // definition, but without this there is no way for them // to tell that they actually have a ctor rather than a // normal function - self.rbml_w.wr_tagged_bytes(tag_items_data_item_is_tuple_struct_ctor, &[]); + self.wr_tagged_bytes(tag_items_data_item_is_tuple_struct_ctor, &[]); } -} -impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> { fn encode_generics(&mut self, generics: &ty::Generics<'tcx>, predicates: &ty::GenericPredicates<'tcx>) { - let ecx = self.ecx(); - self.rbml_w.start_tag(tag_item_generics); - tyencode::enc_generics(self.rbml_w.writer, &ecx.ty_str_ctxt(), generics); - self.rbml_w.mark_stable_position(); - self.rbml_w.end_tag(); + let cx = self.ty_str_ctxt(); + self.start_tag(tag_item_generics); + tyencode::enc_generics(&mut self.writer, &cx, generics); + self.mark_stable_position(); + self.end_tag(); self.encode_predicates(predicates, tag_item_predicates); } fn encode_predicates(&mut self, predicates: &ty::GenericPredicates<'tcx>, tag: usize) { - self.rbml_w.start_tag(tag); + self.start_tag(tag); if let Some(def_id) = predicates.parent { - self.rbml_w.wr_tagged_u64(tag_items_data_parent_item, def_to_u64(def_id)); + self.wr_tagged_u64(tag_items_data_parent_item, def_to_u64(def_id)); } for predicate in &predicates.predicates { let xref = self.add_xref(XRef::Predicate(predicate.clone())); - self.rbml_w.wr_tagged_u32(tag_predicate, xref); + self.wr_tagged_u32(tag_predicate, xref); } - self.rbml_w.end_tag(); + self.end_tag(); } - fn encode_method_ty_fields(&mut self, - method_ty: &ty::Method<'tcx>) { - let ecx = self.ecx(); - encode_def_id_and_key(ecx, self.rbml_w, method_ty.def_id); - encode_name(self.rbml_w, method_ty.name); + fn encode_method_ty_fields(&mut self, method_ty: &ty::Method<'tcx>) { + encode_def_id_and_key(self, method_ty.def_id); + encode_name(self, method_ty.name); self.encode_generics(&method_ty.generics, &method_ty.predicates); self.encode_visibility(method_ty.vis); - encode_explicit_self(self.rbml_w, &method_ty.explicit_self); + encode_explicit_self(self, &method_ty.explicit_self); match method_ty.explicit_self { ty::ExplicitSelfCategory::Static => { - encode_family(self.rbml_w, STATIC_METHOD_FAMILY); + encode_family(self, STATIC_METHOD_FAMILY); } - _ => encode_family(self.rbml_w, METHOD_FAMILY) + _ => encode_family(self, METHOD_FAMILY) } } -} -impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> { fn encode_info_for_trait_item(&mut self, (trait_def_id, item_def_id, trait_item): (DefId, DefId, &hir::TraitItem)) { - let ecx = self.ecx; - let tcx = ecx.tcx; + let tcx = self.tcx; self.encode_parent_item(trait_def_id); let stab = tcx.lookup_stability(item_def_id); let depr = tcx.lookup_deprecation(item_def_id); - encode_stability(self.rbml_w, stab); - encode_deprecation(self.rbml_w, depr); + encode_stability(self, stab); + encode_deprecation(self, depr); let trait_item_type = tcx.impl_or_trait_item(item_def_id); let is_nonstatic_method; match trait_item_type { ty::ConstTraitItem(associated_const) => { - encode_name(self.rbml_w, associated_const.name); - encode_def_id_and_key(ecx, self.rbml_w, associated_const.def_id); + encode_name(self, associated_const.name); + encode_def_id_and_key(self, associated_const.def_id); self.encode_visibility(associated_const.vis); - encode_family(self.rbml_w, 'C'); + encode_family(self, 'C'); - self.encode_bounds_and_type_for_item( - ecx.local_id(associated_const.def_id)); + self.encode_bounds_and_type_for_item(associated_const.def_id); is_nonstatic_method = false; } @@ -547,24 +531,22 @@ impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> { match method_ty.explicit_self { ty::ExplicitSelfCategory::Static => { - encode_family(self.rbml_w, - STATIC_METHOD_FAMILY); + encode_family(self, STATIC_METHOD_FAMILY); } _ => { - encode_family(self.rbml_w, - METHOD_FAMILY); + encode_family(self, METHOD_FAMILY); } } - self.encode_bounds_and_type_for_item(ecx.local_id(method_def_id)); + self.encode_bounds_and_type_for_item(method_def_id); is_nonstatic_method = method_ty.explicit_self != ty::ExplicitSelfCategory::Static; } ty::TypeTraitItem(associated_type) => { - encode_name(self.rbml_w, associated_type.name); - encode_def_id_and_key(ecx, self.rbml_w, associated_type.def_id); - encode_item_sort(self.rbml_w, 't'); - encode_family(self.rbml_w, 'y'); + encode_name(self, associated_type.name); + encode_def_id_and_key(self, associated_type.def_id); + encode_item_sort(self, 't'); + encode_family(self, 'y'); if let Some(ty) = associated_type.ty { self.encode_type(ty); @@ -574,32 +556,31 @@ impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> { } } - encode_attributes(self.rbml_w, &trait_item.attrs); + encode_attributes(self, &trait_item.attrs); match trait_item.node { hir::ConstTraitItem(_, ref default) => { if default.is_some() { - encode_item_sort(self.rbml_w, 'C'); + encode_item_sort(self, 'C'); } else { - encode_item_sort(self.rbml_w, 'c'); + encode_item_sort(self, 'c'); } - encode_inlined_item(ecx, self.rbml_w, + encode_inlined_item(self, InlinedItemRef::TraitItem(trait_def_id, trait_item)); - self.encode_mir(trait_item.id); + self.encode_mir(item_def_id); } hir::MethodTraitItem(ref sig, ref body) => { // If this is a static method, we've already // encoded self. if is_nonstatic_method { - self.encode_bounds_and_type_for_item( - ecx.local_id(item_def_id)); + self.encode_bounds_and_type_for_item(item_def_id); } if body.is_some() { - encode_item_sort(self.rbml_w, 'p'); - self.encode_mir(trait_item.id); + encode_item_sort(self, 'p'); + self.encode_mir(item_def_id); } else { - encode_item_sort(self.rbml_w, 'r'); + encode_item_sort(self, 'r'); } self.encode_method_argument_names(&sig.decl); } @@ -611,7 +592,7 @@ impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> { fn encode_info_for_impl_item(&mut self, (impl_id, impl_item_def_id, ast_item): (NodeId, DefId, Option<&hir::ImplItem>)) { - match self.ecx.tcx.impl_or_trait_item(impl_item_def_id) { + match self.tcx.impl_or_trait_item(impl_item_def_id) { ty::ConstTraitItem(ref associated_const) => { self.encode_info_for_associated_const(&associated_const, impl_id, @@ -635,34 +616,33 @@ impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> { associated_const: &ty::AssociatedConst, parent_id: NodeId, impl_item_opt: Option<&hir::ImplItem>) { - let ecx = self.ecx(); + let tcx = self.tcx; debug!("encode_info_for_associated_const({:?},{:?})", associated_const.def_id, associated_const.name); - encode_def_id_and_key(ecx, self.rbml_w, associated_const.def_id); - encode_name(self.rbml_w, associated_const.name); + encode_def_id_and_key(self, associated_const.def_id); + encode_name(self, associated_const.name); self.encode_visibility(associated_const.vis); - encode_family(self.rbml_w, 'C'); + encode_family(self, 'C'); - self.encode_parent_item(ecx.tcx.map.local_def_id(parent_id)); - encode_item_sort(self.rbml_w, 'C'); + self.encode_parent_item(tcx.map.local_def_id(parent_id)); + encode_item_sort(self, 'C'); - self.encode_bounds_and_type_for_item(ecx.local_id(associated_const.def_id)); + self.encode_bounds_and_type_for_item(associated_const.def_id); - let stab = ecx.tcx.lookup_stability(associated_const.def_id); - let depr = ecx.tcx.lookup_deprecation(associated_const.def_id); - encode_stability(self.rbml_w, stab); - encode_deprecation(self.rbml_w, depr); + let stab = tcx.lookup_stability(associated_const.def_id); + let depr = tcx.lookup_deprecation(associated_const.def_id); + encode_stability(self, stab); + encode_deprecation(self, depr); if let Some(ii) = impl_item_opt { - encode_attributes(self.rbml_w, &ii.attrs); - encode_defaultness(self.rbml_w, ii.defaultness); - encode_inlined_item(ecx, - self.rbml_w, - InlinedItemRef::ImplItem(ecx.tcx.map.local_def_id(parent_id), + encode_attributes(self, &ii.attrs); + encode_defaultness(self, ii.defaultness); + encode_inlined_item(self, + InlinedItemRef::ImplItem(tcx.map.local_def_id(parent_id), ii)); - self.encode_mir(ii.id); + self.encode_mir(associated_const.def_id); } } @@ -671,41 +651,39 @@ impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> { is_default_impl: bool, parent_id: NodeId, impl_item_opt: Option<&hir::ImplItem>) { - let ecx = self.ecx(); + let tcx = self.tcx; debug!("encode_info_for_method: {:?} {:?}", m.def_id, m.name); self.encode_method_ty_fields(m); - self.encode_parent_item(ecx.tcx.map.local_def_id(parent_id)); - encode_item_sort(self.rbml_w, 'r'); + self.encode_parent_item(tcx.map.local_def_id(parent_id)); + encode_item_sort(self, 'r'); - let stab = ecx.tcx.lookup_stability(m.def_id); - let depr = ecx.tcx.lookup_deprecation(m.def_id); - encode_stability(self.rbml_w, stab); - encode_deprecation(self.rbml_w, depr); + let stab = tcx.lookup_stability(m.def_id); + let depr = tcx.lookup_deprecation(m.def_id); + encode_stability(self, stab); + encode_deprecation(self, depr); - let m_node_id = ecx.local_id(m.def_id); - self.encode_bounds_and_type_for_item(m_node_id); + self.encode_bounds_and_type_for_item(m.def_id); if let Some(impl_item) = impl_item_opt { if let hir::ImplItemKind::Method(ref sig, _) = impl_item.node { - encode_attributes(self.rbml_w, &impl_item.attrs); - let generics = ecx.tcx.lookup_generics(m.def_id); + encode_attributes(self, &impl_item.attrs); + let generics = tcx.lookup_generics(m.def_id); let types = generics.parent_types as usize + generics.types.len(); let needs_inline = types > 0 || is_default_impl || attr::requests_inline(&impl_item.attrs); if sig.constness == hir::Constness::Const { encode_inlined_item( - ecx, - self.rbml_w, - InlinedItemRef::ImplItem(ecx.tcx.map.local_def_id(parent_id), + self, + InlinedItemRef::ImplItem(tcx.map.local_def_id(parent_id), impl_item)); } if needs_inline || sig.constness == hir::Constness::Const { - self.encode_mir(impl_item.id); + self.encode_mir(m.def_id); } - encode_constness(self.rbml_w, sig.constness); - encode_defaultness(self.rbml_w, impl_item.defaultness); + encode_constness(self, sig.constness); + encode_defaultness(self, impl_item.defaultness); self.encode_method_argument_names(&sig.decl); } } @@ -715,74 +693,65 @@ impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> { associated_type: &ty::AssociatedType<'tcx>, parent_id: NodeId, impl_item_opt: Option<&hir::ImplItem>) { - let ecx = self.ecx(); + let tcx = self.tcx; debug!("encode_info_for_associated_type({:?},{:?})", associated_type.def_id, associated_type.name); - encode_def_id_and_key(ecx, self.rbml_w, associated_type.def_id); - encode_name(self.rbml_w, associated_type.name); + encode_def_id_and_key(self, associated_type.def_id); + encode_name(self, associated_type.name); self.encode_visibility(associated_type.vis); - encode_family(self.rbml_w, 'y'); - self.encode_parent_item(ecx.tcx.map.local_def_id(parent_id)); - encode_item_sort(self.rbml_w, 't'); + encode_family(self, 'y'); + self.encode_parent_item(tcx.map.local_def_id(parent_id)); + encode_item_sort(self, 't'); - let stab = ecx.tcx.lookup_stability(associated_type.def_id); - let depr = ecx.tcx.lookup_deprecation(associated_type.def_id); - encode_stability(self.rbml_w, stab); - encode_deprecation(self.rbml_w, depr); + let stab = tcx.lookup_stability(associated_type.def_id); + let depr = tcx.lookup_deprecation(associated_type.def_id); + encode_stability(self, stab); + encode_deprecation(self, depr); if let Some(ii) = impl_item_opt { - encode_attributes(self.rbml_w, &ii.attrs); - encode_defaultness(self.rbml_w, ii.defaultness); + encode_attributes(self, &ii.attrs); + encode_defaultness(self, ii.defaultness); } if let Some(ty) = associated_type.ty { self.encode_type(ty); } } -} -impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> { fn encode_method_argument_names(&mut self, decl: &hir::FnDecl) { - self.rbml_w.start_tag(tag_method_argument_names); + self.start_tag(tag_method_argument_names); for arg in &decl.inputs { let tag = tag_method_argument_name; if let PatKind::Binding(_, ref path1, _) = arg.pat.node { let name = path1.node.as_str(); - self.rbml_w.wr_tagged_bytes(tag, name.as_bytes()); + self.wr_tagged_bytes(tag, name.as_bytes()); } else { - self.rbml_w.wr_tagged_bytes(tag, &[]); + self.wr_tagged_bytes(tag, &[]); } } - self.rbml_w.end_tag(); + self.end_tag(); } fn encode_repr_attrs(&mut self, attrs: &[ast::Attribute]) { - let ecx = self.ecx(); let mut repr_attrs = Vec::new(); for attr in attrs { - repr_attrs.extend(attr::find_repr_attrs(ecx.tcx.sess.diagnostic(), + repr_attrs.extend(attr::find_repr_attrs(self.tcx.sess.diagnostic(), attr)); } - self.rbml_w.start_tag(tag_items_data_item_repr); - repr_attrs.encode(self.rbml_w); - self.rbml_w.end_tag(); + self.start_tag(tag_items_data_item_repr); + repr_attrs.encode(self.ecx); + self.end_tag(); } - fn encode_mir(&mut self, node_id: NodeId) { - let ecx = self.ecx(); - let def_id = ecx.tcx.map.local_def_id(node_id); - if let Some(mir) = ecx.mir_map.map.get(&def_id) { - self.rbml_w.start_tag(tag_mir as usize); - self.rbml_w.emit_opaque(|opaque_encoder| { - tls::enter_encoding_context(ecx, opaque_encoder, |_, opaque_encoder| { - Encodable::encode(mir, opaque_encoder) - }) - }).unwrap(); - self.rbml_w.end_tag(); + fn encode_mir(&mut self, def_id: DefId) { + if let Some(mir) = self.mir_map.map.get(&def_id) { + self.start_tag(tag_mir as usize); + mir.encode(self.ecx); + self.end_tag(); } } } @@ -792,75 +761,73 @@ const STATIC_METHOD_FAMILY: char = 'F'; const METHOD_FAMILY: char = 'h'; // Encodes the inherent implementations of a structure, enumeration, or trait. -fn encode_inherent_implementations(ecx: &EncodeContext, - rbml_w: &mut Encoder, +fn encode_inherent_implementations(ecx: &mut EncodeContext, def_id: DefId) { match ecx.tcx.inherent_impls.borrow().get(&def_id) { None => {} Some(implementations) => { for &impl_def_id in implementations.iter() { - rbml_w.start_tag(tag_items_data_item_inherent_impl); - encode_def_id(rbml_w, impl_def_id); - rbml_w.end_tag(); + ecx.start_tag(tag_items_data_item_inherent_impl); + encode_def_id(ecx, impl_def_id); + ecx.end_tag(); } } } } -fn encode_stability(rbml_w: &mut Encoder, stab_opt: Option<&attr::Stability>) { +fn encode_stability(ecx: &mut EncodeContext, stab_opt: Option<&attr::Stability>) { stab_opt.map(|stab| { - rbml_w.start_tag(tag_items_data_item_stability); - stab.encode(rbml_w).unwrap(); - rbml_w.end_tag(); + ecx.start_tag(tag_items_data_item_stability); + stab.encode(ecx).unwrap(); + ecx.end_tag(); }); } -fn encode_deprecation(rbml_w: &mut Encoder, depr_opt: Option) { +fn encode_deprecation(ecx: &mut EncodeContext, depr_opt: Option) { depr_opt.map(|depr| { - rbml_w.start_tag(tag_items_data_item_deprecation); - depr.encode(rbml_w).unwrap(); - rbml_w.end_tag(); + ecx.start_tag(tag_items_data_item_deprecation); + depr.encode(ecx).unwrap(); + ecx.end_tag(); }); } -fn encode_parent_impl(rbml_w: &mut Encoder, parent_opt: Option) { +fn encode_parent_impl(ecx: &mut EncodeContext, parent_opt: Option) { parent_opt.map(|parent| { - rbml_w.wr_tagged_u64(tag_items_data_parent_impl, def_to_u64(parent)); + ecx.wr_tagged_u64(tag_items_data_parent_impl, def_to_u64(parent)); }); } -fn encode_xrefs<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, - rbml_w: &mut Encoder, +fn encode_xrefs<'a, 'tcx>(ecx: &mut EncodeContext<'a, 'tcx>, xrefs: FnvHashMap, u32>) { let mut xref_positions = vec![0; xrefs.len()]; + let cx = ecx.ty_str_ctxt(); // Encode XRefs sorted by their ID let mut sorted_xrefs: Vec<_> = xrefs.into_iter().collect(); sorted_xrefs.sort_by_key(|&(_, id)| id); - rbml_w.start_tag(tag_xref_data); + ecx.start_tag(tag_xref_data); for (xref, id) in sorted_xrefs.into_iter() { - xref_positions[id as usize] = rbml_w.mark_stable_position() as u32; + xref_positions[id as usize] = ecx.mark_stable_position() as u32; match xref { XRef::Predicate(p) => { - tyencode::enc_predicate(rbml_w.writer, &ecx.ty_str_ctxt(), &p) + tyencode::enc_predicate(&mut ecx.writer, &cx, &p) } } } - rbml_w.mark_stable_position(); - rbml_w.end_tag(); + ecx.mark_stable_position(); + ecx.end_tag(); - rbml_w.start_tag(tag_xref_index); - index::write_dense_index(xref_positions, rbml_w.writer); - rbml_w.end_tag(); + ecx.start_tag(tag_xref_index); + index::write_dense_index(xref_positions, &mut ecx.writer); + ecx.end_tag(); } -impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> { +impl<'a, 'b, 'tcx> ItemContentBuilder<'a, 'b, 'tcx> { fn encode_info_for_item(&mut self, (def_id, item): (DefId, &hir::Item)) { - let ecx = self.ecx(); - let tcx = ecx.tcx; + let tcx = self.tcx; debug!("encoding info for item at {}", tcx.sess.codemap().span_to_string(item.span)); @@ -868,122 +835,122 @@ impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> { let vis = &item.vis; let (stab, depr) = tcx.dep_graph.with_task(DepNode::MetaData(def_id), || { - (tcx.lookup_stability(ecx.tcx.map.local_def_id(item.id)), - tcx.lookup_deprecation(ecx.tcx.map.local_def_id(item.id))) + (tcx.lookup_stability(tcx.map.local_def_id(item.id)), + tcx.lookup_deprecation(tcx.map.local_def_id(item.id))) }); match item.node { hir::ItemStatic(_, m, _) => { - encode_def_id_and_key(ecx, self.rbml_w, def_id); + encode_def_id_and_key(self, def_id); if m == hir::MutMutable { - encode_family(self.rbml_w, 'b'); + encode_family(self, 'b'); } else { - encode_family(self.rbml_w, 'c'); + encode_family(self, 'c'); } - self.encode_bounds_and_type_for_item(item.id); - encode_name(self.rbml_w, item.name); + self.encode_bounds_and_type_for_item(def_id); + encode_name(self, item.name); self.encode_visibility(vis); - encode_stability(self.rbml_w, stab); - encode_deprecation(self.rbml_w, depr); - encode_attributes(self.rbml_w, &item.attrs); + encode_stability(self, stab); + encode_deprecation(self, depr); + encode_attributes(self, &item.attrs); } hir::ItemConst(..) => { - encode_def_id_and_key(ecx, self.rbml_w, def_id); - encode_family(self.rbml_w, 'C'); - self.encode_bounds_and_type_for_item(item.id); - encode_name(self.rbml_w, item.name); - encode_attributes(self.rbml_w, &item.attrs); - encode_inlined_item(ecx, self.rbml_w, InlinedItemRef::Item(def_id, item)); - self.encode_mir(item.id); + encode_def_id_and_key(self, def_id); + encode_family(self, 'C'); + self.encode_bounds_and_type_for_item(def_id); + encode_name(self, item.name); + encode_attributes(self, &item.attrs); + encode_inlined_item(self, InlinedItemRef::Item(def_id, item)); + self.encode_mir(def_id); self.encode_visibility(vis); - encode_stability(self.rbml_w, stab); - encode_deprecation(self.rbml_w, depr); + encode_stability(self, stab); + encode_deprecation(self, depr); } hir::ItemFn(ref decl, _, constness, _, ref generics, _) => { - encode_def_id_and_key(ecx, self.rbml_w, def_id); - encode_family(self.rbml_w, FN_FAMILY); + encode_def_id_and_key(self, def_id); + encode_family(self, FN_FAMILY); let tps_len = generics.ty_params.len(); - self.encode_bounds_and_type_for_item(item.id); - encode_name(self.rbml_w, item.name); - encode_attributes(self.rbml_w, &item.attrs); + self.encode_bounds_and_type_for_item(def_id); + encode_name(self, item.name); + encode_attributes(self, &item.attrs); let needs_inline = tps_len > 0 || attr::requests_inline(&item.attrs); if constness == hir::Constness::Const { - encode_inlined_item(ecx, self.rbml_w, InlinedItemRef::Item(def_id, item)); + encode_inlined_item(self, InlinedItemRef::Item(def_id, item)); } if needs_inline || constness == hir::Constness::Const { - self.encode_mir(item.id); + self.encode_mir(def_id); } - encode_constness(self.rbml_w, constness); + encode_constness(self, constness); self.encode_visibility(vis); - encode_stability(self.rbml_w, stab); - encode_deprecation(self.rbml_w, depr); + encode_stability(self, stab); + encode_deprecation(self, depr); self.encode_method_argument_names(&decl); } hir::ItemMod(ref m) => { self.encode_info_for_mod(FromId(item.id, (m, &item.attrs, item.name, &item.vis))); } hir::ItemForeignMod(ref fm) => { - encode_def_id_and_key(ecx, self.rbml_w, def_id); - encode_family(self.rbml_w, 'n'); - encode_name(self.rbml_w, item.name); + encode_def_id_and_key(self, def_id); + encode_family(self, 'n'); + encode_name(self, item.name); // Encode all the items in self module. for foreign_item in &fm.items { - self.rbml_w.wr_tagged_u64( + self.wr_tagged_u64( tag_mod_child, - def_to_u64(ecx.tcx.map.local_def_id(foreign_item.id))); + def_to_u64(tcx.map.local_def_id(foreign_item.id))); } self.encode_visibility(vis); - encode_stability(self.rbml_w, stab); - encode_deprecation(self.rbml_w, depr); + encode_stability(self, stab); + encode_deprecation(self, depr); } hir::ItemTy(..) => { - encode_def_id_and_key(ecx, self.rbml_w, def_id); - encode_family(self.rbml_w, 'y'); - self.encode_bounds_and_type_for_item(item.id); - encode_name(self.rbml_w, item.name); + encode_def_id_and_key(self, def_id); + encode_family(self, 'y'); + self.encode_bounds_and_type_for_item(def_id); + encode_name(self, item.name); self.encode_visibility(vis); - encode_stability(self.rbml_w, stab); - encode_deprecation(self.rbml_w, depr); + encode_stability(self, stab); + encode_deprecation(self, depr); } hir::ItemEnum(ref enum_definition, _) => { - encode_def_id_and_key(ecx, self.rbml_w, def_id); - encode_family(self.rbml_w, 't'); - encode_item_variances(self.rbml_w, ecx, item.id); - self.encode_bounds_and_type_for_item(item.id); - encode_name(self.rbml_w, item.name); - encode_attributes(self.rbml_w, &item.attrs); + encode_def_id_and_key(self, def_id); + encode_family(self, 't'); + encode_item_variances(self, item.id); + self.encode_bounds_and_type_for_item(def_id); + encode_name(self, item.name); + encode_attributes(self, &item.attrs); self.encode_repr_attrs(&item.attrs); for v in &enum_definition.variants { - encode_variant_id(self.rbml_w, ecx.tcx.map.local_def_id(v.node.data.id())); + encode_variant_id(self, tcx.map.local_def_id(v.node.data.id())); } // Encode inherent implementations for self enumeration. - encode_inherent_implementations(ecx, self.rbml_w, def_id); + encode_inherent_implementations(self, def_id); self.encode_visibility(vis); - encode_stability(self.rbml_w, stab); - encode_deprecation(self.rbml_w, depr); + encode_stability(self, stab); + encode_deprecation(self, depr); } hir::ItemStruct(ref struct_def, _) => { /* Index the class*/ - let def = ecx.tcx.lookup_adt_def(def_id); + let def = tcx.lookup_adt_def(def_id); let variant = def.struct_variant(); /* Now, make an item for the class itself */ - encode_def_id_and_key(ecx, self.rbml_w, def_id); - encode_family(self.rbml_w, match *struct_def { + encode_def_id_and_key(self, def_id); + encode_family(self, match *struct_def { hir::VariantData::Struct(..) => 'S', hir::VariantData::Tuple(..) => 's', hir::VariantData::Unit(..) => 'u', }); - self.encode_bounds_and_type_for_item(item.id); + self.encode_bounds_and_type_for_item(def_id); - encode_item_variances(self.rbml_w, ecx, item.id); - encode_name(self.rbml_w, item.name); - encode_attributes(self.rbml_w, &item.attrs); - encode_stability(self.rbml_w, stab); - encode_deprecation(self.rbml_w, depr); + encode_item_variances(self, item.id); + encode_name(self, item.name); + encode_attributes(self, &item.attrs); + encode_stability(self, stab); + encode_deprecation(self, depr); self.encode_visibility(vis); self.encode_repr_attrs(&item.attrs); @@ -993,27 +960,27 @@ impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> { self.encode_struct_fields(variant); // Encode inherent implementations for self structure. - encode_inherent_implementations(ecx, self.rbml_w, def_id); + encode_inherent_implementations(self, def_id); if !struct_def.is_struct() { - let ctor_did = ecx.tcx.map.local_def_id(struct_def.id()); - self.rbml_w.wr_tagged_u64(tag_items_data_item_struct_ctor, - def_to_u64(ctor_did)); + let ctor_did = tcx.map.local_def_id(struct_def.id()); + self.wr_tagged_u64(tag_items_data_item_struct_ctor, + def_to_u64(ctor_did)); } } hir::ItemUnion(..) => { - let def = ecx.tcx.lookup_adt_def(def_id); + let def = self.tcx.lookup_adt_def(def_id); let variant = def.struct_variant(); - encode_def_id_and_key(ecx, self.rbml_w, def_id); - encode_family(self.rbml_w, 'U'); - self.encode_bounds_and_type_for_item(item.id); + encode_def_id_and_key(self, def_id); + encode_family(self, 'U'); + self.encode_bounds_and_type_for_item(def_id); - encode_item_variances(self.rbml_w, ecx, item.id); - encode_name(self.rbml_w, item.name); - encode_attributes(self.rbml_w, &item.attrs); - encode_stability(self.rbml_w, stab); - encode_deprecation(self.rbml_w, depr); + encode_item_variances(self, item.id); + encode_name(self, item.name); + encode_attributes(self, &item.attrs); + encode_stability(self, stab); + encode_deprecation(self, depr); self.encode_visibility(vis); self.encode_repr_attrs(&item.attrs); @@ -1022,20 +989,20 @@ impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> { needs to know*/ self.encode_struct_fields(variant); - encode_inlined_item(ecx, self.rbml_w, InlinedItemRef::Item(def_id, item)); - self.encode_mir(item.id); + encode_inlined_item(self, InlinedItemRef::Item(def_id, item)); + self.encode_mir(def_id); // Encode inherent implementations for self union. - encode_inherent_implementations(ecx, self.rbml_w, def_id); + encode_inherent_implementations(self, def_id); } hir::ItemDefaultImpl(unsafety, _) => { - encode_def_id_and_key(ecx, self.rbml_w, def_id); - encode_family(self.rbml_w, 'd'); - encode_name(self.rbml_w, item.name); - encode_unsafety(self.rbml_w, unsafety); + encode_def_id_and_key(self, def_id); + encode_family(self, 'd'); + encode_name(self, item.name); + encode_unsafety(self, unsafety); - let trait_ref = tcx.impl_trait_ref(ecx.tcx.map.local_def_id(item.id)).unwrap(); - encode_trait_ref(self.rbml_w, ecx, trait_ref, tag_item_trait_ref); + let trait_ref = tcx.impl_trait_ref(tcx.map.local_def_id(item.id)).unwrap(); + encode_trait_ref(self, trait_ref, tag_item_trait_ref); } hir::ItemImpl(unsafety, polarity, ..) => { // We need to encode information about the default methods we @@ -1043,49 +1010,49 @@ impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> { let impl_items = tcx.impl_items.borrow(); let items = &impl_items[&def_id]; - encode_def_id_and_key(ecx, self.rbml_w, def_id); - encode_family(self.rbml_w, 'i'); - self.encode_bounds_and_type_for_item(item.id); - encode_name(self.rbml_w, item.name); - encode_attributes(self.rbml_w, &item.attrs); - encode_unsafety(self.rbml_w, unsafety); - encode_polarity(self.rbml_w, polarity); + encode_def_id_and_key(self, def_id); + encode_family(self, 'i'); + self.encode_bounds_and_type_for_item(def_id); + encode_name(self, item.name); + encode_attributes(self, &item.attrs); + encode_unsafety(self, unsafety); + encode_polarity(self, polarity); match tcx.custom_coerce_unsized_kinds .borrow() - .get(&ecx.tcx.map.local_def_id(item.id)) + .get(&tcx.map.local_def_id(item.id)) { Some(&kind) => { - self.rbml_w.start_tag(tag_impl_coerce_unsized_kind); - kind.encode(self.rbml_w); - self.rbml_w.end_tag(); + self.start_tag(tag_impl_coerce_unsized_kind); + kind.encode(self.ecx); + self.end_tag(); } None => {} } for &item_def_id in items { - self.rbml_w.start_tag(tag_item_impl_item); + self.start_tag(tag_item_impl_item); match item_def_id { ty::ConstTraitItemId(item_def_id) => { - encode_def_id(self.rbml_w, item_def_id); - encode_item_sort(self.rbml_w, 'C'); + encode_def_id(self, item_def_id); + encode_item_sort(self, 'C'); } ty::MethodTraitItemId(item_def_id) => { - encode_def_id(self.rbml_w, item_def_id); - encode_item_sort(self.rbml_w, 'r'); + encode_def_id(self, item_def_id); + encode_item_sort(self, 'r'); } ty::TypeTraitItemId(item_def_id) => { - encode_def_id(self.rbml_w, item_def_id); - encode_item_sort(self.rbml_w, 't'); + encode_def_id(self, item_def_id); + encode_item_sort(self, 't'); } } - self.rbml_w.end_tag(); + self.end_tag(); } - let did = ecx.tcx.map.local_def_id(item.id); + let did = tcx.map.local_def_id(item.id); if let Some(trait_ref) = tcx.impl_trait_ref(did) { - encode_trait_ref(self.rbml_w, ecx, trait_ref, tag_item_trait_ref); + encode_trait_ref(self, trait_ref, tag_item_trait_ref); let trait_def = tcx.lookup_trait_def(trait_ref.def_id); let parent = trait_def.ancestors(did) @@ -1096,54 +1063,54 @@ impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> { Some(parent), _ => None, }); - encode_parent_impl(self.rbml_w, parent); + encode_parent_impl(self, parent); } - encode_stability(self.rbml_w, stab); - encode_deprecation(self.rbml_w, depr); + encode_stability(self, stab); + encode_deprecation(self, depr); } hir::ItemTrait(..) => { - encode_def_id_and_key(ecx, self.rbml_w, def_id); - encode_family(self.rbml_w, 'I'); - encode_item_variances(self.rbml_w, ecx, item.id); + encode_def_id_and_key(self, def_id); + encode_family(self, 'I'); + encode_item_variances(self, item.id); let trait_def = tcx.lookup_trait_def(def_id); let trait_predicates = tcx.lookup_predicates(def_id); - encode_unsafety(self.rbml_w, trait_def.unsafety); - encode_paren_sugar(self.rbml_w, trait_def.paren_sugar); - encode_defaulted(self.rbml_w, tcx.trait_has_default_impl(def_id)); - encode_associated_type_names(self.rbml_w, &trait_def.associated_type_names); + encode_unsafety(self, trait_def.unsafety); + encode_paren_sugar(self, trait_def.paren_sugar); + encode_defaulted(self, tcx.trait_has_default_impl(def_id)); + encode_associated_type_names(self, &trait_def.associated_type_names); self.encode_generics(&trait_def.generics, &trait_predicates); self.encode_predicates(&tcx.lookup_super_predicates(def_id), tag_item_super_predicates); - encode_trait_ref(self.rbml_w, ecx, trait_def.trait_ref, tag_item_trait_ref); - encode_name(self.rbml_w, item.name); - encode_attributes(self.rbml_w, &item.attrs); + encode_trait_ref(self, trait_def.trait_ref, tag_item_trait_ref); + encode_name(self, item.name); + encode_attributes(self, &item.attrs); self.encode_visibility(vis); - encode_stability(self.rbml_w, stab); - encode_deprecation(self.rbml_w, depr); + encode_stability(self, stab); + encode_deprecation(self, depr); for &method_def_id in tcx.trait_item_def_ids(def_id).iter() { - self.rbml_w.start_tag(tag_item_trait_item); + self.start_tag(tag_item_trait_item); match method_def_id { ty::ConstTraitItemId(const_def_id) => { - encode_def_id(self.rbml_w, const_def_id); - encode_item_sort(self.rbml_w, 'C'); + encode_def_id(self, const_def_id); + encode_item_sort(self, 'C'); } ty::MethodTraitItemId(method_def_id) => { - encode_def_id(self.rbml_w, method_def_id); - encode_item_sort(self.rbml_w, 'r'); + encode_def_id(self, method_def_id); + encode_item_sort(self, 'r'); } ty::TypeTraitItemId(type_def_id) => { - encode_def_id(self.rbml_w, type_def_id); - encode_item_sort(self.rbml_w, 't'); + encode_def_id(self, type_def_id); + encode_item_sort(self, 't'); } } - self.rbml_w.end_tag(); + self.end_tag(); - self.rbml_w.wr_tagged_u64(tag_mod_child, - def_to_u64(method_def_id.def_id())); + self.wr_tagged_u64(tag_mod_child, + def_to_u64(method_def_id.def_id())); } // Encode inherent implementations for self trait. - encode_inherent_implementations(ecx, self.rbml_w, def_id); + encode_inherent_implementations(self, def_id); } hir::ItemExternCrate(_) | hir::ItemUse(_) => { bug!("cannot encode info for item {:?}", item) @@ -1152,14 +1119,14 @@ impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> { } } -impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> { +impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { /// In some cases, along with the item itself, we also /// encode some sub-items. Usually we want some info from the item /// so it's easier to do that here then to wait until we would encounter /// normally in the visitor walk. fn encode_addl_info_for_item(&mut self, item: &hir::Item) { - let def_id = self.ecx().tcx.map.local_def_id(item.id); + let def_id = self.tcx.map.local_def_id(item.id); match item.node { hir::ItemStatic(..) | hir::ItemConst(..) | @@ -1194,8 +1161,7 @@ impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> { def_id: DefId, struct_node_id: ast::NodeId, item: &hir::Item) { - let ecx = self.ecx(); - let def = ecx.tcx.lookup_adt_def(def_id); + let def = self.tcx.lookup_adt_def(def_id); let variant = def.struct_variant(); self.encode_fields(def_id); @@ -1208,7 +1174,7 @@ impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> { ty::VariantKind::Tuple | ty::VariantKind::Unit => { // there is a value for structs like `struct // Foo()` and `struct Foo` - let ctor_def_id = ecx.tcx.map.local_def_id(struct_node_id); + let ctor_def_id = self.tcx.map.local_def_id(struct_node_id); self.record(ctor_def_id, ItemContentBuilder::encode_struct_ctor, (def_id, item.id, struct_node_id)); @@ -1224,8 +1190,7 @@ impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> { def_id: DefId, impl_id: ast::NodeId, ast_items: &[hir::ImplItem]) { - let ecx = self.ecx(); - let impl_items = ecx.tcx.impl_items.borrow(); + let impl_items = self.tcx.impl_items.borrow(); let items = &impl_items[&def_id]; // Iterate down the trait items, emitting them. We rely on the @@ -1251,7 +1216,7 @@ impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> { def_id: DefId, trait_items: &[hir::TraitItem]) { // Now output the trait item info for each trait item. - let tcx = self.ecx().tcx; + let tcx = self.tcx; let r = tcx.trait_item_def_ids(def_id); for (item_def_id, trait_item) in r.iter().zip(trait_items) { let item_def_id = item_def_id.def_id(); @@ -1263,59 +1228,59 @@ impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> { } } -impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> { +impl<'a, 'b, 'tcx> ItemContentBuilder<'a, 'b, 'tcx> { fn encode_info_for_foreign_item(&mut self, (def_id, nitem): (DefId, &hir::ForeignItem)) { - let ecx = self.ecx(); + let tcx = self.tcx; - debug!("writing foreign item {}", ecx.tcx.node_path_str(nitem.id)); + debug!("writing foreign item {}", tcx.node_path_str(nitem.id)); - encode_def_id_and_key(ecx, self.rbml_w, def_id); - let parent_id = ecx.tcx.map.get_parent(nitem.id); - self.encode_parent_item(ecx.tcx.map.local_def_id(parent_id)); + encode_def_id_and_key(self, def_id); + let parent_id = tcx.map.get_parent(nitem.id); + self.encode_parent_item(tcx.map.local_def_id(parent_id)); self.encode_visibility(&nitem.vis); match nitem.node { hir::ForeignItemFn(ref fndecl, _) => { - encode_family(self.rbml_w, FN_FAMILY); - self.encode_bounds_and_type_for_item(nitem.id); - encode_name(self.rbml_w, nitem.name); - encode_attributes(self.rbml_w, &nitem.attrs); - let stab = ecx.tcx.lookup_stability(ecx.tcx.map.local_def_id(nitem.id)); - let depr = ecx.tcx.lookup_deprecation(ecx.tcx.map.local_def_id(nitem.id)); - encode_stability(self.rbml_w, stab); - encode_deprecation(self.rbml_w, depr); + encode_family(self, FN_FAMILY); + self.encode_bounds_and_type_for_item(def_id); + encode_name(self, nitem.name); + encode_attributes(self, &nitem.attrs); + let stab = tcx.lookup_stability(tcx.map.local_def_id(nitem.id)); + let depr = tcx.lookup_deprecation(tcx.map.local_def_id(nitem.id)); + encode_stability(self, stab); + encode_deprecation(self, depr); self.encode_method_argument_names(&fndecl); } hir::ForeignItemStatic(_, mutbl) => { if mutbl { - encode_family(self.rbml_w, 'b'); + encode_family(self, 'b'); } else { - encode_family(self.rbml_w, 'c'); + encode_family(self, 'c'); } - self.encode_bounds_and_type_for_item(nitem.id); - encode_attributes(self.rbml_w, &nitem.attrs); - let stab = ecx.tcx.lookup_stability(ecx.tcx.map.local_def_id(nitem.id)); - let depr = ecx.tcx.lookup_deprecation(ecx.tcx.map.local_def_id(nitem.id)); - encode_stability(self.rbml_w, stab); - encode_deprecation(self.rbml_w, depr); - encode_name(self.rbml_w, nitem.name); + self.encode_bounds_and_type_for_item(def_id); + encode_attributes(self, &nitem.attrs); + let stab = tcx.lookup_stability(tcx.map.local_def_id(nitem.id)); + let depr = tcx.lookup_deprecation(tcx.map.local_def_id(nitem.id)); + encode_stability(self, stab); + encode_deprecation(self, depr); + encode_name(self, nitem.name); } } } } -struct EncodeVisitor<'a, 'ecx: 'a, 'tcx: 'ecx, 'encoder: 'ecx> { - index: &'a mut IndexBuilder<'ecx, 'tcx, 'encoder>, +struct EncodeVisitor<'a, 'b: 'a, 'tcx: 'b> { + index: IndexBuilder<'a, 'b, 'tcx>, } -impl<'a, 'ecx, 'tcx, 'encoder> Visitor<'tcx> for EncodeVisitor<'a, 'ecx, 'tcx, 'encoder> { +impl<'a, 'b, 'tcx> Visitor<'tcx> for EncodeVisitor<'a, 'b, 'tcx> { fn visit_expr(&mut self, ex: &'tcx hir::Expr) { intravisit::walk_expr(self, ex); self.index.encode_info_for_expr(ex); } fn visit_item(&mut self, item: &'tcx hir::Item) { intravisit::walk_item(self, item); - let def_id = self.index.ecx().tcx.map.local_def_id(item.id); + let def_id = self.index.tcx.map.local_def_id(item.id); match item.node { hir::ItemExternCrate(_) | hir::ItemUse(_) => (), // ignore these _ => self.index.record(def_id, @@ -1326,7 +1291,7 @@ impl<'a, 'ecx, 'tcx, 'encoder> Visitor<'tcx> for EncodeVisitor<'a, 'ecx, 'tcx, ' } fn visit_foreign_item(&mut self, ni: &'tcx hir::ForeignItem) { intravisit::walk_foreign_item(self, ni); - let def_id = self.index.ecx().tcx.map.local_def_id(ni.id); + let def_id = self.index.tcx.map.local_def_id(ni.id); self.index.record(def_id, ItemContentBuilder::encode_info_for_foreign_item, (def_id, ni)); @@ -1337,135 +1302,130 @@ impl<'a, 'ecx, 'tcx, 'encoder> Visitor<'tcx> for EncodeVisitor<'a, 'ecx, 'tcx, ' } } -impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> { +impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { fn encode_info_for_ty(&mut self, ty: &hir::Ty) { - let ecx = self.ecx(); if let hir::TyImplTrait(_) = ty.node { - let def_id = ecx.tcx.map.local_def_id(ty.id); + let def_id = self.tcx.map.local_def_id(ty.id); self.record(def_id, ItemContentBuilder::encode_info_for_anon_ty, - (def_id, ty.id)); + def_id); } } fn encode_info_for_expr(&mut self, expr: &hir::Expr) { - let ecx = self.ecx(); - match expr.node { hir::ExprClosure(..) => { - let def_id = ecx.tcx.map.local_def_id(expr.id); + let def_id = self.tcx.map.local_def_id(expr.id); self.record(def_id, ItemContentBuilder::encode_info_for_closure, - (def_id, expr.id)); + def_id); } _ => { } } } } -impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> { - fn encode_info_for_anon_ty(&mut self, (def_id, ty_id): (DefId, NodeId)) { - let ecx = self.ecx; - encode_def_id_and_key(ecx, self.rbml_w, def_id); - encode_family(self.rbml_w, 'y'); - self.encode_bounds_and_type_for_item(ty_id); +impl<'a, 'b, 'tcx> ItemContentBuilder<'a, 'b, 'tcx> { + fn encode_info_for_anon_ty(&mut self, def_id: DefId) { + encode_def_id_and_key(self, def_id); + encode_family(self, 'y'); + self.encode_bounds_and_type_for_item(def_id); } - fn encode_info_for_closure(&mut self, (def_id, expr_id): (DefId, NodeId)) { - let ecx = self.ecx; - encode_def_id_and_key(ecx, self.rbml_w, def_id); - encode_name(self.rbml_w, syntax::parse::token::intern("")); + fn encode_info_for_closure(&mut self, def_id: DefId) { + let tcx = self.tcx; + encode_def_id_and_key(self, def_id); + encode_name(self, syntax::parse::token::intern("")); - self.rbml_w.start_tag(tag_items_closure_ty); - write_closure_type(ecx, - self.rbml_w, - &ecx.tcx.tables.borrow().closure_tys[&def_id]); - self.rbml_w.end_tag(); + self.start_tag(tag_items_closure_ty); + write_closure_type(self, + &tcx.tables.borrow().closure_tys[&def_id]); + self.end_tag(); - self.rbml_w.start_tag(tag_items_closure_kind); - ecx.tcx.closure_kind(def_id).encode(self.rbml_w).unwrap(); - self.rbml_w.end_tag(); + self.start_tag(tag_items_closure_kind); + tcx.closure_kind(def_id).encode(self.ecx).unwrap(); + self.end_tag(); - assert!(ecx.mir_map.map.contains_key(&def_id)); - self.encode_mir(expr_id); + assert!(self.mir_map.map.contains_key(&def_id)); + self.encode_mir(def_id); } } -fn encode_info_for_items<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>, - rbml_w: &mut Encoder) +fn encode_info_for_items<'a, 'tcx>(ecx: &mut EncodeContext<'a, 'tcx>) -> (IndexData, FnvHashMap, u32>) { let krate = ecx.tcx.map.krate(); - rbml_w.start_tag(tag_items_data); + ecx.start_tag(tag_items_data); let fields = { - let mut index = IndexBuilder::new(ecx, rbml_w); + let mut index = IndexBuilder::new(ecx); index.record(DefId::local(CRATE_DEF_INDEX), ItemContentBuilder::encode_info_for_mod, FromId(CRATE_NODE_ID, (&krate.module, &[], syntax::parse::token::intern(&ecx.link_meta.crate_name), &hir::Public))); - krate.visit_all_items(&mut EncodeVisitor { - index: &mut index, - }); - index.into_fields() + let mut visitor = EncodeVisitor { + index: index, + }; + krate.visit_all_items(&mut visitor); + visitor.index.into_fields() }; - rbml_w.end_tag(); + ecx.end_tag(); fields } -fn encode_item_index(rbml_w: &mut Encoder, index: IndexData) { - rbml_w.start_tag(tag_index); - index.write_index(rbml_w.writer); - rbml_w.end_tag(); +fn encode_item_index(ecx: &mut EncodeContext, index: IndexData) { + ecx.start_tag(tag_index); + index.write_index(&mut ecx.writer); + ecx.end_tag(); } -fn encode_attributes(rbml_w: &mut Encoder, attrs: &[ast::Attribute]) { - rbml_w.start_tag(tag_attributes); - rbml_w.emit_opaque(|opaque_encoder| { +fn encode_attributes(ecx: &mut EncodeContext, attrs: &[ast::Attribute]) { + ecx.start_tag(tag_attributes); + ecx.emit_opaque(|opaque_encoder| { attrs.encode(opaque_encoder) }).unwrap(); - rbml_w.end_tag(); + ecx.end_tag(); } -fn encode_unsafety(rbml_w: &mut Encoder, unsafety: hir::Unsafety) { +fn encode_unsafety(ecx: &mut EncodeContext, unsafety: hir::Unsafety) { let byte: u8 = match unsafety { hir::Unsafety::Normal => 0, hir::Unsafety::Unsafe => 1, }; - rbml_w.wr_tagged_u8(tag_unsafety, byte); + ecx.wr_tagged_u8(tag_unsafety, byte); } -fn encode_paren_sugar(rbml_w: &mut Encoder, paren_sugar: bool) { +fn encode_paren_sugar(ecx: &mut EncodeContext, paren_sugar: bool) { let byte: u8 = if paren_sugar {1} else {0}; - rbml_w.wr_tagged_u8(tag_paren_sugar, byte); + ecx.wr_tagged_u8(tag_paren_sugar, byte); } -fn encode_defaulted(rbml_w: &mut Encoder, is_defaulted: bool) { +fn encode_defaulted(ecx: &mut EncodeContext, is_defaulted: bool) { let byte: u8 = if is_defaulted {1} else {0}; - rbml_w.wr_tagged_u8(tag_defaulted_trait, byte); + ecx.wr_tagged_u8(tag_defaulted_trait, byte); } -fn encode_associated_type_names(rbml_w: &mut Encoder, names: &[Name]) { - rbml_w.start_tag(tag_associated_type_names); +fn encode_associated_type_names(ecx: &mut EncodeContext, names: &[Name]) { + ecx.start_tag(tag_associated_type_names); for &name in names { - rbml_w.wr_tagged_str(tag_associated_type_name, &name.as_str()); + ecx.wr_tagged_str(tag_associated_type_name, &name.as_str()); } - rbml_w.end_tag(); + ecx.end_tag(); } -fn encode_polarity(rbml_w: &mut Encoder, polarity: hir::ImplPolarity) { +fn encode_polarity(ecx: &mut EncodeContext, polarity: hir::ImplPolarity) { let byte: u8 = match polarity { hir::ImplPolarity::Positive => 0, hir::ImplPolarity::Negative => 1, }; - rbml_w.wr_tagged_u8(tag_polarity, byte); + ecx.wr_tagged_u8(tag_polarity, byte); } -fn encode_crate_deps(rbml_w: &mut Encoder, cstore: &cstore::CStore) { +fn encode_crate_deps(ecx: &mut EncodeContext, cstore: &cstore::CStore) { fn get_ordered_deps(cstore: &cstore::CStore) -> Vec<(CrateNum, Rc)> { // Pull the cnums and name,vers,hash out of cstore @@ -1491,64 +1451,64 @@ fn encode_crate_deps(rbml_w: &mut Encoder, cstore: &cstore::CStore) { // the assumption that they are numbered 1 to n. // FIXME (#2166): This is not nearly enough to support correct versioning // but is enough to get transitive crate dependencies working. - rbml_w.start_tag(tag_crate_deps); + ecx.start_tag(tag_crate_deps); for (_cnum, dep) in get_ordered_deps(cstore) { - encode_crate_dep(rbml_w, &dep); + encode_crate_dep(ecx, &dep); } - rbml_w.end_tag(); + ecx.end_tag(); } -fn encode_lang_items(ecx: &EncodeContext, rbml_w: &mut Encoder) { - rbml_w.start_tag(tag_lang_items); +fn encode_lang_items(ecx: &mut EncodeContext) { + ecx.start_tag(tag_lang_items); for (i, &opt_def_id) in ecx.tcx.lang_items.items().iter().enumerate() { if let Some(def_id) = opt_def_id { if def_id.is_local() { - rbml_w.start_tag(tag_lang_items_item); - rbml_w.wr_tagged_u32(tag_lang_items_item_id, i as u32); - rbml_w.wr_tagged_u32(tag_lang_items_item_index, def_id.index.as_u32()); - rbml_w.end_tag(); + ecx.start_tag(tag_lang_items_item); + ecx.wr_tagged_u32(tag_lang_items_item_id, i as u32); + ecx.wr_tagged_u32(tag_lang_items_item_index, def_id.index.as_u32()); + ecx.end_tag(); } } } for i in &ecx.tcx.lang_items.missing { - rbml_w.wr_tagged_u32(tag_lang_items_missing, *i as u32); + ecx.wr_tagged_u32(tag_lang_items_missing, *i as u32); } - rbml_w.end_tag(); // tag_lang_items + ecx.end_tag(); // tag_lang_items } -fn encode_native_libraries(ecx: &EncodeContext, rbml_w: &mut Encoder) { - rbml_w.start_tag(tag_native_libraries); +fn encode_native_libraries(ecx: &mut EncodeContext) { + ecx.start_tag(tag_native_libraries); for &(ref lib, kind) in ecx.tcx.sess.cstore.used_libraries().iter() { match kind { cstore::NativeStatic => {} // these libraries are not propagated cstore::NativeFramework | cstore::NativeUnknown => { - rbml_w.start_tag(tag_native_libraries_lib); - rbml_w.wr_tagged_u32(tag_native_libraries_kind, kind as u32); - rbml_w.wr_tagged_str(tag_native_libraries_name, lib); - rbml_w.end_tag(); + ecx.start_tag(tag_native_libraries_lib); + ecx.wr_tagged_u32(tag_native_libraries_kind, kind as u32); + ecx.wr_tagged_str(tag_native_libraries_name, lib); + ecx.end_tag(); } } } - rbml_w.end_tag(); + ecx.end_tag(); } -fn encode_plugin_registrar_fn(ecx: &EncodeContext, rbml_w: &mut Encoder) { +fn encode_plugin_registrar_fn(ecx: &mut EncodeContext) { match ecx.tcx.sess.plugin_registrar_fn.get() { Some(id) => { let def_id = ecx.tcx.map.local_def_id(id); - rbml_w.wr_tagged_u32(tag_plugin_registrar_fn, def_id.index.as_u32()); + ecx.wr_tagged_u32(tag_plugin_registrar_fn, def_id.index.as_u32()); } None => {} } } -fn encode_codemap(ecx: &EncodeContext, rbml_w: &mut Encoder) { - rbml_w.start_tag(tag_codemap); +fn encode_codemap(ecx: &mut EncodeContext) { + ecx.start_tag(tag_codemap); let codemap = ecx.tcx.sess.codemap(); for filemap in &codemap.files.borrow()[..] { @@ -1561,66 +1521,62 @@ fn encode_codemap(ecx: &EncodeContext, rbml_w: &mut Encoder) { continue; } - rbml_w.start_tag(tag_codemap_filemap); - rbml_w.emit_opaque(|opaque_encoder| { + ecx.start_tag(tag_codemap_filemap); + ecx.emit_opaque(|opaque_encoder| { filemap.encode(opaque_encoder) }).unwrap(); - rbml_w.end_tag(); + ecx.end_tag(); } - rbml_w.end_tag(); + ecx.end_tag(); } /// Serialize the text of the exported macros -fn encode_macro_defs(rbml_w: &mut Encoder, - krate: &hir::Crate, - tcx: TyCtxt) { - rbml_w.start_tag(tag_macro_defs); +fn encode_macro_defs(ecx: &mut EncodeContext, + krate: &hir::Crate) { + ecx.start_tag(tag_macro_defs); for def in &krate.exported_macros { - rbml_w.start_tag(tag_macro_def); + ecx.start_tag(tag_macro_def); - encode_name(rbml_w, def.name); - encode_attributes(rbml_w, &def.attrs); + encode_name(ecx, def.name); + encode_attributes(ecx, &def.attrs); let &BytePos(lo) = &def.span.lo; let &BytePos(hi) = &def.span.hi; - rbml_w.wr_tagged_u32(tag_macro_def_span_lo, lo); - rbml_w.wr_tagged_u32(tag_macro_def_span_hi, hi); + ecx.wr_tagged_u32(tag_macro_def_span_lo, lo); + ecx.wr_tagged_u32(tag_macro_def_span_hi, hi); - rbml_w.wr_tagged_str(tag_macro_def_body, - &::syntax::print::pprust::tts_to_string(&def.body)); + ecx.wr_tagged_str(tag_macro_def_body, + &::syntax::print::pprust::tts_to_string(&def.body)); - rbml_w.end_tag(); + ecx.end_tag(); } - rbml_w.end_tag(); + ecx.end_tag(); - if tcx.sess.crate_types.borrow().contains(&CrateTypeRustcMacro) { - let id = tcx.sess.derive_registrar_fn.get().unwrap(); - let did = tcx.map.local_def_id(id); - rbml_w.wr_tagged_u32(tag_macro_derive_registrar, did.index.as_u32()); + if ecx.tcx.sess.crate_types.borrow().contains(&CrateTypeRustcMacro) { + let id = ecx.tcx.sess.derive_registrar_fn.get().unwrap(); + let did = ecx.tcx.map.local_def_id(id); + ecx.wr_tagged_u32(tag_macro_derive_registrar, did.index.as_u32()); } } -fn encode_struct_field_attrs(ecx: &EncodeContext, - rbml_w: &mut Encoder, - krate: &hir::Crate) { - struct StructFieldVisitor<'a, 'b:'a, 'c:'a, 'tcx:'b> { - ecx: &'a EncodeContext<'b, 'tcx>, - rbml_w: &'a mut Encoder<'c>, +fn encode_struct_field_attrs(ecx: &mut EncodeContext, krate: &hir::Crate) { + struct StructFieldVisitor<'a, 'b:'a, 'tcx:'b> { + ecx: &'a mut EncodeContext<'b, 'tcx> } - impl<'a, 'b, 'c, 'tcx, 'v> Visitor<'v> for StructFieldVisitor<'a, 'b, 'c, 'tcx> { + impl<'a, 'b, 'tcx, 'v> Visitor<'v> for StructFieldVisitor<'a, 'b, 'tcx> { fn visit_struct_field(&mut self, field: &hir::StructField) { - self.rbml_w.start_tag(tag_struct_field); + self.ecx.start_tag(tag_struct_field); let def_id = self.ecx.tcx.map.local_def_id(field.id); - encode_def_id(self.rbml_w, def_id); - encode_attributes(self.rbml_w, &field.attrs); - self.rbml_w.end_tag(); + encode_def_id(self.ecx, def_id); + encode_attributes(self.ecx, &field.attrs); + self.ecx.end_tag(); } } - rbml_w.start_tag(tag_struct_fields); - krate.visit_all_items(&mut StructFieldVisitor { ecx: ecx, rbml_w: rbml_w }); - rbml_w.end_tag(); + ecx.start_tag(tag_struct_fields); + krate.visit_all_items(&mut StructFieldVisitor { ecx: ecx }); + ecx.end_tag(); } @@ -1644,25 +1600,23 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ImplVisitor<'a, 'tcx> { } /// Encodes an index, mapping each trait to its (local) implementations. -fn encode_impls<'a>(ecx: &'a EncodeContext, - krate: &hir::Crate, - rbml_w: &'a mut Encoder) { +fn encode_impls(ecx: &mut EncodeContext, krate: &hir::Crate) { let mut visitor = ImplVisitor { tcx: ecx.tcx, impls: FnvHashMap() }; krate.visit_all_items(&mut visitor); - rbml_w.start_tag(tag_impls); + ecx.start_tag(tag_impls); for (trait_, trait_impls) in visitor.impls { - rbml_w.start_tag(tag_impls_trait); - encode_def_id(rbml_w, trait_); + ecx.start_tag(tag_impls_trait); + encode_def_id(ecx, trait_); for impl_ in trait_impls { - rbml_w.wr_tagged_u64(tag_impls_trait_impl, def_to_u64(impl_)); + ecx.wr_tagged_u64(tag_impls_trait_impl, def_to_u64(impl_)); } - rbml_w.end_tag(); + ecx.end_tag(); } - rbml_w.end_tag(); + ecx.end_tag(); } // Encodes all reachable symbols in this crate into the metadata. @@ -1671,47 +1625,47 @@ fn encode_impls<'a>(ecx: &'a EncodeContext, // middle::reachable module but filters out items that either don't have a // symbol associated with them (they weren't translated) or if they're an FFI // definition (as that's not defined in this crate). -fn encode_reachable(ecx: &EncodeContext, rbml_w: &mut Encoder) { - rbml_w.start_tag(tag_reachable_ids); +fn encode_reachable(ecx: &mut EncodeContext) { + ecx.start_tag(tag_reachable_ids); for &id in ecx.reachable { let def_id = ecx.tcx.map.local_def_id(id); - rbml_w.wr_tagged_u32(tag_reachable_id, def_id.index.as_u32()); + ecx.wr_tagged_u32(tag_reachable_id, def_id.index.as_u32()); } - rbml_w.end_tag(); + ecx.end_tag(); } -fn encode_crate_dep(rbml_w: &mut Encoder, +fn encode_crate_dep(ecx: &mut EncodeContext, dep: &cstore::CrateMetadata) { - rbml_w.start_tag(tag_crate_dep); - rbml_w.wr_tagged_str(tag_crate_dep_crate_name, &dep.name()); + ecx.start_tag(tag_crate_dep); + ecx.wr_tagged_str(tag_crate_dep_crate_name, &dep.name()); let hash = decoder::get_crate_hash(dep.data()); - rbml_w.wr_tagged_u64(tag_crate_dep_hash, hash.as_u64()); - rbml_w.wr_tagged_u8(tag_crate_dep_explicitly_linked, - dep.explicitly_linked.get() as u8); - rbml_w.end_tag(); + ecx.wr_tagged_u64(tag_crate_dep_hash, hash.as_u64()); + ecx.wr_tagged_u8(tag_crate_dep_explicitly_linked, + dep.explicitly_linked.get() as u8); + ecx.end_tag(); } -fn encode_hash(rbml_w: &mut Encoder, hash: &Svh) { - rbml_w.wr_tagged_u64(tag_crate_hash, hash.as_u64()); +fn encode_hash(ecx: &mut EncodeContext, hash: &Svh) { + ecx.wr_tagged_u64(tag_crate_hash, hash.as_u64()); } -fn encode_rustc_version(rbml_w: &mut Encoder) { - rbml_w.wr_tagged_str(tag_rustc_version, &rustc_version()); +fn encode_rustc_version(ecx: &mut EncodeContext) { + ecx.wr_tagged_str(tag_rustc_version, &rustc_version()); } -fn encode_crate_name(rbml_w: &mut Encoder, crate_name: &str) { - rbml_w.wr_tagged_str(tag_crate_crate_name, crate_name); +fn encode_crate_name(ecx: &mut EncodeContext, crate_name: &str) { + ecx.wr_tagged_str(tag_crate_crate_name, crate_name); } -fn encode_crate_disambiguator(rbml_w: &mut Encoder, crate_disambiguator: &str) { - rbml_w.wr_tagged_str(tag_crate_disambiguator, crate_disambiguator); +fn encode_crate_disambiguator(ecx: &mut EncodeContext, crate_disambiguator: &str) { + ecx.wr_tagged_str(tag_crate_disambiguator, crate_disambiguator); } -fn encode_crate_triple(rbml_w: &mut Encoder, triple: &str) { - rbml_w.wr_tagged_str(tag_crate_triple, triple); +fn encode_crate_triple(ecx: &mut EncodeContext, triple: &str) { + ecx.wr_tagged_str(tag_crate_triple, triple); } -fn encode_dylib_dependency_formats(rbml_w: &mut Encoder, ecx: &EncodeContext) { +fn encode_dylib_dependency_formats(ecx: &mut EncodeContext) { let tag = tag_dylib_dependency_formats; match ecx.tcx.sess.dependency_formats.borrow().get(&config::CrateTypeDylib) { Some(arr) => { @@ -1724,37 +1678,32 @@ fn encode_dylib_dependency_formats(rbml_w: &mut Encoder, ecx: &EncodeContext) { }; Some(format!("{}:{}", i + 1, kind)) }).collect::>(); - rbml_w.wr_tagged_str(tag, &s.join(",")); + ecx.wr_tagged_str(tag, &s.join(",")); } None => { - rbml_w.wr_tagged_str(tag, ""); + ecx.wr_tagged_str(tag, ""); } } } -fn encode_panic_strategy(rbml_w: &mut Encoder, ecx: &EncodeContext) { +fn encode_panic_strategy(ecx: &mut EncodeContext) { match ecx.tcx.sess.opts.cg.panic { PanicStrategy::Unwind => { - rbml_w.wr_tagged_u8(tag_panic_strategy, b'U'); + ecx.wr_tagged_u8(tag_panic_strategy, b'U'); } PanicStrategy::Abort => { - rbml_w.wr_tagged_u8(tag_panic_strategy, b'A'); + ecx.wr_tagged_u8(tag_panic_strategy, b'A'); } } } -pub fn encode_metadata(ecx: EncodeContext, krate: &hir::Crate) -> Vec { - let mut wr = Cursor::new(Vec::new()); - - { - let mut rbml_w = Encoder::new(&mut wr); - encode_metadata_inner(&mut rbml_w, &ecx, krate) - } +pub fn encode_metadata(mut ecx: EncodeContext, krate: &hir::Crate) -> Vec { + encode_metadata_inner(&mut ecx, krate); // RBML compacts the encoded bytes whenever appropriate, // so there are some garbages left after the end of the data. - let metalen = wr.seek(SeekFrom::Current(0)).unwrap() as usize; - let mut v = wr.into_inner(); + let metalen = ecx.rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() as usize; + let mut v = ecx.rbml_w.writer.into_inner(); v.truncate(metalen); assert_eq!(v.len(), metalen); @@ -1797,9 +1746,7 @@ pub fn encode_metadata(ecx: EncodeContext, krate: &hir::Crate) -> Vec { result } -fn encode_metadata_inner(rbml_w: &mut Encoder, - ecx: &EncodeContext, - krate: &hir::Crate) { +fn encode_metadata_inner(ecx: &mut EncodeContext, krate: &hir::Crate) { struct Stats { attr_bytes: u64, dep_bytes: u64, @@ -1833,78 +1780,81 @@ fn encode_metadata_inner(rbml_w: &mut Encoder, total_bytes: 0, }; - encode_rustc_version(rbml_w); - encode_crate_name(rbml_w, &ecx.link_meta.crate_name); - encode_crate_triple(rbml_w, &ecx.tcx.sess.opts.target_triple); - encode_hash(rbml_w, &ecx.link_meta.crate_hash); - encode_crate_disambiguator(rbml_w, &ecx.tcx.sess.local_crate_disambiguator()); - encode_dylib_dependency_formats(rbml_w, &ecx); - encode_panic_strategy(rbml_w, &ecx); + encode_rustc_version(ecx); - let mut i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap(); - encode_attributes(rbml_w, &krate.attrs); - stats.attr_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i; + let tcx = ecx.tcx; + let link_meta = ecx.link_meta; + encode_crate_name(ecx, &link_meta.crate_name); + encode_crate_triple(ecx, &tcx.sess.opts.target_triple); + encode_hash(ecx, &link_meta.crate_hash); + encode_crate_disambiguator(ecx, &tcx.sess.local_crate_disambiguator()); + encode_dylib_dependency_formats(ecx); + encode_panic_strategy(ecx); - i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap(); - encode_crate_deps(rbml_w, ecx.cstore); - stats.dep_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i; + let mut i = ecx.writer.seek(SeekFrom::Current(0)).unwrap(); + encode_attributes(ecx, &krate.attrs); + stats.attr_bytes = ecx.writer.seek(SeekFrom::Current(0)).unwrap() - i; + + i = ecx.writer.seek(SeekFrom::Current(0)).unwrap(); + encode_crate_deps(ecx, ecx.cstore); + stats.dep_bytes = ecx.writer.seek(SeekFrom::Current(0)).unwrap() - i; // Encode the language items. - i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap(); - encode_lang_items(&ecx, rbml_w); - stats.lang_item_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i; + i = ecx.writer.seek(SeekFrom::Current(0)).unwrap(); + encode_lang_items(ecx); + stats.lang_item_bytes = ecx.writer.seek(SeekFrom::Current(0)).unwrap() - i; // Encode the native libraries used - i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap(); - encode_native_libraries(&ecx, rbml_w); - stats.native_lib_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i; + i = ecx.writer.seek(SeekFrom::Current(0)).unwrap(); + encode_native_libraries(ecx); + stats.native_lib_bytes = ecx.writer.seek(SeekFrom::Current(0)).unwrap() - i; // Encode the plugin registrar function - i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap(); - encode_plugin_registrar_fn(&ecx, rbml_w); - stats.plugin_registrar_fn_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i; + i = ecx.writer.seek(SeekFrom::Current(0)).unwrap(); + encode_plugin_registrar_fn(ecx); + stats.plugin_registrar_fn_bytes = ecx.writer.seek(SeekFrom::Current(0)).unwrap() - i; // Encode codemap - i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap(); - encode_codemap(&ecx, rbml_w); - stats.codemap_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i; + i = ecx.writer.seek(SeekFrom::Current(0)).unwrap(); + encode_codemap(ecx); + stats.codemap_bytes = ecx.writer.seek(SeekFrom::Current(0)).unwrap() - i; // Encode macro definitions - i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap(); - encode_macro_defs(rbml_w, krate, ecx.tcx); - stats.macro_defs_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i; + i = ecx.writer.seek(SeekFrom::Current(0)).unwrap(); + encode_macro_defs(ecx, krate); + stats.macro_defs_bytes = ecx.writer.seek(SeekFrom::Current(0)).unwrap() - i; // Encode the def IDs of impls, for coherence checking. - i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap(); - encode_impls(&ecx, krate, rbml_w); - stats.impl_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i; + i = ecx.writer.seek(SeekFrom::Current(0)).unwrap(); + encode_impls(ecx, krate); + stats.impl_bytes = ecx.writer.seek(SeekFrom::Current(0)).unwrap() - i; // Encode reachability info. - i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap(); - encode_reachable(&ecx, rbml_w); - stats.reachable_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i; + i = ecx.writer.seek(SeekFrom::Current(0)).unwrap(); + encode_reachable(ecx); + stats.reachable_bytes = ecx.writer.seek(SeekFrom::Current(0)).unwrap() - i; // Encode and index the items. - rbml_w.start_tag(tag_items); - i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap(); - let (items, xrefs) = encode_info_for_items(&ecx, rbml_w); - stats.item_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i; - rbml_w.end_tag(); + ecx.start_tag(tag_items); + i = ecx.writer.seek(SeekFrom::Current(0)).unwrap(); + let (items, xrefs) = encode_info_for_items(ecx); + stats.item_bytes = ecx.writer.seek(SeekFrom::Current(0)).unwrap() - i; + ecx.end_tag(); - i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap(); - encode_item_index(rbml_w, items); - stats.index_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i; + i = ecx.writer.seek(SeekFrom::Current(0)).unwrap(); + encode_item_index(ecx, items); + stats.index_bytes = ecx.writer.seek(SeekFrom::Current(0)).unwrap() - i; - i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap(); - encode_xrefs(&ecx, rbml_w, xrefs); - stats.xref_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i; + i = ecx.writer.seek(SeekFrom::Current(0)).unwrap(); + encode_xrefs(ecx, xrefs); + stats.xref_bytes = ecx.writer.seek(SeekFrom::Current(0)).unwrap() - i; - encode_struct_field_attrs(&ecx, rbml_w, krate); + encode_struct_field_attrs(ecx, krate); - stats.total_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap(); + stats.total_bytes = ecx.writer.seek(SeekFrom::Current(0)).unwrap(); if ecx.tcx.sess.meta_stats() { - for e in rbml_w.writer.get_ref() { + for e in ecx.writer.get_ref() { if *e == 0 { stats.zero_bytes += 1; } @@ -1935,7 +1885,6 @@ pub fn encoded_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, -> Vec { let mut wr = Cursor::new(Vec::new()); tyencode::enc_ty(&mut wr, &tyencode::ctxt { - diag: tcx.sess.diagnostic(), ds: def_id_to_string, tcx: tcx, abbrevs: &RefCell::new(FnvHashMap()) diff --git a/src/librustc_metadata/index_builder.rs b/src/librustc_metadata/index_builder.rs index 1d3d09d6bc2d..de2f1c4fb0c8 100644 --- a/src/librustc_metadata/index_builder.rs +++ b/src/librustc_metadata/index_builder.rs @@ -65,7 +65,6 @@ use common::tag_items_data_item; use encoder::EncodeContext; use index::IndexData; -use rbml::writer::Encoder; use rustc::dep_graph::DepNode; use rustc::hir; use rustc::hir::def_id::DefId; @@ -73,43 +72,63 @@ use rustc::ty::{self, TyCtxt}; use rustc_data_structures::fnv::FnvHashMap; use syntax::ast; +use std::ops::{Deref, DerefMut}; + /// Builder that can encode new items, adding them into the index. /// Item encoding cannot be nested. -pub struct IndexBuilder<'a, 'tcx: 'a, 'encoder: 'a> { +pub struct IndexBuilder<'a, 'b: 'a, 'tcx: 'b> { items: IndexData, - builder: ItemContentBuilder<'a, 'tcx, 'encoder>, + builder: ItemContentBuilder<'a, 'b, 'tcx>, } /// Builder that can encode the content of items, but can't start a /// new item itself. Most code is attached to here. -pub struct ItemContentBuilder<'a, 'tcx: 'a, 'encoder: 'a> { +pub struct ItemContentBuilder<'a, 'b: 'a, 'tcx: 'b> { xrefs: FnvHashMap, u32>, // sequentially-assigned - pub ecx: &'a EncodeContext<'a, 'tcx>, - pub rbml_w: &'a mut Encoder<'encoder>, + pub ecx: &'a mut EncodeContext<'b, 'tcx>, +} + +impl<'a, 'b, 'tcx> Deref for IndexBuilder<'a, 'b, 'tcx> { + type Target = EncodeContext<'b, 'tcx>; + fn deref(&self) -> &Self::Target { + self.builder.ecx + } +} + +impl<'a, 'b, 'tcx> DerefMut for IndexBuilder<'a, 'b, 'tcx> { + fn deref_mut(&mut self) -> &mut Self::Target { + self.builder.ecx + } +} + +impl<'a, 'b, 'tcx> Deref for ItemContentBuilder<'a, 'b, 'tcx> { + type Target = EncodeContext<'b, 'tcx>; + fn deref(&self) -> &Self::Target { + self.ecx + } +} + +impl<'a, 'b, 'tcx> DerefMut for ItemContentBuilder<'a, 'b, 'tcx> { + fn deref_mut(&mut self) -> &mut Self::Target { + self.ecx + } } /// "interned" entries referenced by id #[derive(PartialEq, Eq, Hash)] pub enum XRef<'tcx> { Predicate(ty::Predicate<'tcx>) } -impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> { - pub fn new(ecx: &'a EncodeContext<'a, 'tcx>, - rbml_w: &'a mut Encoder<'encoder>) - -> Self { +impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { + pub fn new(ecx: &'a mut EncodeContext<'b, 'tcx>) -> Self { IndexBuilder { items: IndexData::new(ecx.tcx.map.num_local_def_ids()), builder: ItemContentBuilder { ecx: ecx, xrefs: FnvHashMap(), - rbml_w: rbml_w, }, } } - pub fn ecx(&self) -> &'a EncodeContext<'a, 'tcx> { - self.builder.ecx() - } - /// Emit the data for a def-id to the metadata. The function to /// emit the data is `op`, and it will be given `data` as /// arguments. This `record` function will start/end an RBML tag @@ -129,17 +148,17 @@ impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> { /// content system. pub fn record(&mut self, id: DefId, - op: fn(&mut ItemContentBuilder<'a, 'tcx, 'encoder>, DATA), + op: fn(&mut ItemContentBuilder<'a, 'b, 'tcx>, DATA), data: DATA) where DATA: DepGraphRead { - let position = self.builder.rbml_w.mark_stable_position(); + let position = self.builder.ecx.mark_stable_position(); self.items.record(id, position); - let _task = self.ecx().tcx.dep_graph.in_task(DepNode::MetaData(id)); - self.builder.rbml_w.start_tag(tag_items_data_item).unwrap(); - data.read(self.ecx().tcx); + let _task = self.tcx.dep_graph.in_task(DepNode::MetaData(id)); + self.builder.ecx.start_tag(tag_items_data_item).unwrap(); + data.read(self.tcx); op(&mut self.builder, data); - self.builder.rbml_w.end_tag().unwrap(); + self.builder.ecx.end_tag().unwrap(); } pub fn into_fields(self) -> (IndexData, FnvHashMap, u32>) { @@ -147,11 +166,7 @@ impl<'a, 'tcx, 'encoder> IndexBuilder<'a, 'tcx, 'encoder> { } } -impl<'a, 'tcx, 'encoder> ItemContentBuilder<'a, 'tcx, 'encoder> { - pub fn ecx(&self) -> &'a EncodeContext<'a, 'tcx> { - self.ecx - } - +impl<'a, 'b, 'tcx> ItemContentBuilder<'a, 'b, 'tcx> { pub fn add_xref(&mut self, xref: XRef<'tcx>) -> u32 { let old_len = self.xrefs.len() as u32; *self.xrefs.entry(xref).or_insert(old_len) diff --git a/src/librustc_metadata/rbml/writer.rs b/src/librustc_metadata/rbml/writer.rs index 17b3c392edb3..b49686e2379d 100644 --- a/src/librustc_metadata/rbml/writer.rs +++ b/src/librustc_metadata/rbml/writer.rs @@ -21,8 +21,8 @@ use rustc_serialize as serialize; pub type EncodeResult = io::Result<()>; // rbml writing -pub struct Encoder<'a> { - pub writer: &'a mut Cursor>, +pub struct Encoder { + pub writer: Cursor>, size_positions: Vec, relax_limit: u64, // do not move encoded bytes before this position } @@ -65,10 +65,10 @@ pub fn write_vuint(w: &mut W, n: usize) -> EncodeResult { Err(io::Error::new(io::ErrorKind::Other, &format!("isize too big: {}", n)[..])) } -impl<'a> Encoder<'a> { - pub fn new(w: &'a mut Cursor>) -> Encoder<'a> { +impl Encoder { + pub fn new() -> Encoder { Encoder { - writer: w, + writer: Cursor::new(vec![]), size_positions: vec![], relax_limit: 0, } @@ -79,7 +79,7 @@ impl<'a> Encoder<'a> { assert!(tag_id >= NUM_IMPLICIT_TAGS); // Write the enum ID: - write_tag(self.writer, tag_id)?; + write_tag(&mut self.writer, tag_id)?; // Write a placeholder four-byte size. let cur_pos = self.writer.seek(SeekFrom::Current(0))?; @@ -107,11 +107,11 @@ impl<'a> Encoder<'a> { } // overwrite the size and data and continue - write_vuint(self.writer, size)?; + write_vuint(&mut self.writer, size)?; self.writer.write_all(&buf[..size])?; } else { // overwrite the size with an overlong encoding and skip past the data - write_sized_vuint(self.writer, size, 4)?; + write_sized_vuint(&mut self.writer, size, 4)?; self.writer.seek(SeekFrom::Start(cur_pos))?; } @@ -129,8 +129,8 @@ impl<'a> Encoder<'a> { pub fn wr_tagged_bytes(&mut self, tag_id: usize, b: &[u8]) -> EncodeResult { assert!(tag_id >= NUM_IMPLICIT_TAGS); - write_tag(self.writer, tag_id)?; - write_vuint(self.writer, b.len())?; + write_tag(&mut self.writer, tag_id)?; + write_vuint(&mut self.writer, b.len())?; self.writer.write_all(b) } @@ -183,7 +183,7 @@ impl<'a> Encoder<'a> { // for auto-serialization fn wr_tagged_raw_bytes(&mut self, tag_id: usize, b: &[u8]) -> EncodeResult { - write_tag(self.writer, tag_id)?; + write_tag(&mut self.writer, tag_id)?; self.writer.write_all(b) } @@ -243,7 +243,7 @@ impl<'a> Encoder<'a> { } } -impl<'a> Encoder<'a> { +impl Encoder { // used internally to emit things like the vector length and so on fn _emit_tagged_sub(&mut self, v: usize) -> EncodeResult { if v as u8 as usize == v { @@ -262,7 +262,7 @@ impl<'a> Encoder<'a> { self.start_tag(EsOpaque as usize)?; { - let mut opaque_encoder = opaque::Encoder::new(self.writer); + let mut opaque_encoder = opaque::Encoder::new(&mut self.writer); f(&mut opaque_encoder)?; } @@ -271,7 +271,7 @@ impl<'a> Encoder<'a> { } } -impl<'a> serialize::Encoder for Encoder<'a> { +impl<'a, 'tcx> serialize::Encoder for ::encoder::EncodeContext<'a, 'tcx> { type Error = io::Error; fn emit_nil(&mut self) -> EncodeResult { @@ -355,7 +355,7 @@ impl<'a> serialize::Encoder for Encoder<'a> { } fn emit_enum(&mut self, _name: &str, f: F) -> EncodeResult - where F: FnOnce(&mut Encoder<'a>) -> EncodeResult + where F: FnOnce(&mut Self) -> EncodeResult { self.start_tag(EsEnum as usize)?; f(self)?; @@ -363,14 +363,14 @@ impl<'a> serialize::Encoder for Encoder<'a> { } fn emit_enum_variant(&mut self, _: &str, v_id: usize, _: usize, f: F) -> EncodeResult - where F: FnOnce(&mut Encoder<'a>) -> EncodeResult + where F: FnOnce(&mut Self) -> EncodeResult { self._emit_tagged_sub(v_id)?; f(self) } fn emit_enum_variant_arg(&mut self, _: usize, f: F) -> EncodeResult - where F: FnOnce(&mut Encoder<'a>) -> EncodeResult + where F: FnOnce(&mut Self) -> EncodeResult { f(self) } @@ -381,53 +381,53 @@ impl<'a> serialize::Encoder for Encoder<'a> { cnt: usize, f: F) -> EncodeResult - where F: FnOnce(&mut Encoder<'a>) -> EncodeResult + where F: FnOnce(&mut Self) -> EncodeResult { self.emit_enum_variant(v_name, v_id, cnt, f) } fn emit_enum_struct_variant_field(&mut self, _: &str, idx: usize, f: F) -> EncodeResult - where F: FnOnce(&mut Encoder<'a>) -> EncodeResult + where F: FnOnce(&mut Self) -> EncodeResult { self.emit_enum_variant_arg(idx, f) } fn emit_struct(&mut self, _: &str, _len: usize, f: F) -> EncodeResult - where F: FnOnce(&mut Encoder<'a>) -> EncodeResult + where F: FnOnce(&mut Self) -> EncodeResult { f(self) } fn emit_struct_field(&mut self, _name: &str, _: usize, f: F) -> EncodeResult - where F: FnOnce(&mut Encoder<'a>) -> EncodeResult + where F: FnOnce(&mut Self) -> EncodeResult { f(self) } fn emit_tuple(&mut self, len: usize, f: F) -> EncodeResult - where F: FnOnce(&mut Encoder<'a>) -> EncodeResult + where F: FnOnce(&mut Self) -> EncodeResult { self.emit_seq(len, f) } fn emit_tuple_arg(&mut self, idx: usize, f: F) -> EncodeResult - where F: FnOnce(&mut Encoder<'a>) -> EncodeResult + where F: FnOnce(&mut Self) -> EncodeResult { self.emit_seq_elt(idx, f) } fn emit_tuple_struct(&mut self, _: &str, len: usize, f: F) -> EncodeResult - where F: FnOnce(&mut Encoder<'a>) -> EncodeResult + where F: FnOnce(&mut Self) -> EncodeResult { self.emit_seq(len, f) } fn emit_tuple_struct_arg(&mut self, idx: usize, f: F) -> EncodeResult - where F: FnOnce(&mut Encoder<'a>) -> EncodeResult + where F: FnOnce(&mut Self) -> EncodeResult { self.emit_seq_elt(idx, f) } fn emit_option(&mut self, f: F) -> EncodeResult - where F: FnOnce(&mut Encoder<'a>) -> EncodeResult + where F: FnOnce(&mut Self) -> EncodeResult { self.emit_enum("Option", f) } @@ -435,14 +435,14 @@ impl<'a> serialize::Encoder for Encoder<'a> { self.emit_enum_variant("None", 0, 0, |_| Ok(())) } fn emit_option_some(&mut self, f: F) -> EncodeResult - where F: FnOnce(&mut Encoder<'a>) -> EncodeResult + where F: FnOnce(&mut Self) -> EncodeResult { self.emit_enum_variant("Some", 1, 1, f) } fn emit_seq(&mut self, len: usize, f: F) -> EncodeResult - where F: FnOnce(&mut Encoder<'a>) -> EncodeResult + where F: FnOnce(&mut Self) -> EncodeResult { if len == 0 { // empty vector optimization @@ -456,7 +456,7 @@ impl<'a> serialize::Encoder for Encoder<'a> { } fn emit_seq_elt(&mut self, _idx: usize, f: F) -> EncodeResult - where F: FnOnce(&mut Encoder<'a>) -> EncodeResult + where F: FnOnce(&mut Self) -> EncodeResult { self.start_tag(EsVecElt as usize)?; @@ -465,7 +465,7 @@ impl<'a> serialize::Encoder for Encoder<'a> { } fn emit_map(&mut self, len: usize, f: F) -> EncodeResult - where F: FnOnce(&mut Encoder<'a>) -> EncodeResult + where F: FnOnce(&mut Self) -> EncodeResult { if len == 0 { // empty map optimization @@ -479,7 +479,7 @@ impl<'a> serialize::Encoder for Encoder<'a> { } fn emit_map_elt_key(&mut self, _idx: usize, f: F) -> EncodeResult - where F: FnOnce(&mut Encoder<'a>) -> EncodeResult + where F: FnOnce(&mut Self) -> EncodeResult { self.start_tag(EsMapKey as usize)?; @@ -488,7 +488,7 @@ impl<'a> serialize::Encoder for Encoder<'a> { } fn emit_map_elt_val(&mut self, _idx: usize, f: F) -> EncodeResult - where F: FnOnce(&mut Encoder<'a>) -> EncodeResult + where F: FnOnce(&mut Self) -> EncodeResult { self.start_tag(EsMapVal as usize)?; f(self)?; diff --git a/src/librustc_metadata/tyencode.rs b/src/librustc_metadata/tyencode.rs index dbefd3eacc24..73996518a156 100644 --- a/src/librustc_metadata/tyencode.rs +++ b/src/librustc_metadata/tyencode.rs @@ -27,13 +27,11 @@ use rustc::hir; use syntax::abi::Abi; use syntax::ast; -use errors::Handler; use rbml::leb128; use encoder; pub struct ctxt<'a, 'tcx: 'a> { - pub diag: &'a Handler, // Def -> str Callback: pub ds: for<'b> fn(TyCtxt<'b, 'tcx, 'tcx>, DefId) -> String, // The type context. @@ -42,12 +40,11 @@ pub struct ctxt<'a, 'tcx: 'a> { } impl<'a, 'tcx> encoder::EncodeContext<'a, 'tcx> { - pub fn ty_str_ctxt<'b>(&'b self) -> ctxt<'b, 'tcx> { + pub fn ty_str_ctxt(&self) -> ctxt<'a, 'tcx> { ctxt { - diag: self.tcx.sess.diagnostic(), ds: encoder::def_to_string, tcx: self.tcx, - abbrevs: &self.type_abbrevs + abbrevs: self.type_abbrevs } } } From d47fd9eb5a6cb18ab1e11febcef04b0a919e8bcb Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Mon, 19 Sep 2016 23:46:31 +0300 Subject: [PATCH 407/443] rustc_metadata: use specialization for {en,de}coding Ty and Substs. --- src/librustc/middle/cstore.rs | 120 ++++----------------------- src/librustc/ty/mod.rs | 23 +---- src/librustc/ty/sty.rs | 4 +- src/librustc/ty/subst.rs | 24 +----- src/librustc_metadata/encoder.rs | 45 +++++++++- src/librustc_metadata/lib.rs | 1 + src/librustc_metadata/tls_context.rs | 22 +---- 7 files changed, 71 insertions(+), 168 deletions(-) diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index b2c293a290ab..9dacb9062c1c 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -509,85 +509,20 @@ pub trait MacroLoader { /// Note, however, that this only works for RBML-based encoding and decoding at /// the moment. pub mod tls { - use rbml::opaque::Encoder as OpaqueEncoder; use rbml::opaque::Decoder as OpaqueDecoder; - use serialize; use std::cell::Cell; - use std::mem; - use ty::{self, Ty, TyCtxt}; + use ty::{Ty, TyCtxt}; use ty::subst::Substs; use hir::def_id::DefId; - pub trait EncodingContext<'tcx> { - fn tcx<'a>(&'a self) -> TyCtxt<'a, 'tcx, 'tcx>; - fn encode_ty(&self, encoder: &mut OpaqueEncoder, t: Ty<'tcx>); - fn encode_substs(&self, encoder: &mut OpaqueEncoder, substs: &Substs<'tcx>); - } - /// Marker type used for the TLS slot. /// The type context cannot be used directly because the TLS /// in libstd doesn't allow types generic over lifetimes. struct TlsPayload; - thread_local! { - static TLS_ENCODING: Cell> = Cell::new(None) - } - - /// Execute f after pushing the given EncodingContext onto the TLS stack. - pub fn enter_encoding_context<'tcx, F, R>(ecx: &EncodingContext<'tcx>, - encoder: &mut OpaqueEncoder, - f: F) -> R - where F: FnOnce(&EncodingContext<'tcx>, &mut OpaqueEncoder) -> R - { - let tls_payload = (ecx as *const _, encoder as *mut _); - let tls_ptr = &tls_payload as *const _ as *const TlsPayload; - TLS_ENCODING.with(|tls| { - let prev = tls.get(); - tls.set(Some(tls_ptr)); - let ret = f(ecx, encoder); - tls.set(prev); - return ret - }) - } - - /// Execute f with access to the thread-local encoding context and - /// rbml encoder. This function will panic if the encoder passed in and the - /// context encoder are not the same. - /// - /// Note that this method is 'practically' safe due to its checking that the - /// encoder passed in is the same as the one in TLS, but it would still be - /// possible to construct cases where the EncodingContext is exchanged - /// while the same encoder is used, thus working with a wrong context. - pub fn with_encoding_context<'tcx, E, F, R>(encoder: &mut E, f: F) -> R - where F: FnOnce(&EncodingContext<'tcx>, &mut OpaqueEncoder) -> R, - E: serialize::Encoder - { - unsafe { - unsafe_with_encoding_context(|ecx, tls_encoder| { - assert!(encoder as *mut _ as usize == tls_encoder as *mut _ as usize); - - let ecx: &EncodingContext<'tcx> = mem::transmute(ecx); - - f(ecx, tls_encoder) - }) - } - } - - /// Execute f with access to the thread-local encoding context and - /// rbml encoder. - pub unsafe fn unsafe_with_encoding_context(f: F) -> R - where F: FnOnce(&EncodingContext, &mut OpaqueEncoder) -> R - { - TLS_ENCODING.with(|tls| { - let tls = tls.get().unwrap(); - let tls_payload = tls as *mut (&EncodingContext, &mut OpaqueEncoder); - f((*tls_payload).0, (*tls_payload).1) - }) - } - pub trait DecodingContext<'tcx> { fn tcx<'a>(&'a self) -> TyCtxt<'a, 'tcx, 'tcx>; - fn decode_ty(&self, decoder: &mut OpaqueDecoder) -> ty::Ty<'tcx>; + fn decode_ty(&self, decoder: &mut OpaqueDecoder) -> Ty<'tcx>; fn decode_substs(&self, decoder: &mut OpaqueDecoder) -> &'tcx Substs<'tcx>; fn translate_def_id(&self, def_id: DefId) -> DefId; } @@ -597,56 +532,31 @@ pub mod tls { } /// Execute f after pushing the given DecodingContext onto the TLS stack. - pub fn enter_decoding_context<'tcx, F, R>(dcx: &DecodingContext<'tcx>, - decoder: &mut OpaqueDecoder, - f: F) -> R - where F: FnOnce(&DecodingContext<'tcx>, &mut OpaqueDecoder) -> R + pub fn enter_decoding_context<'tcx, F, R>(dcx: &DecodingContext<'tcx>, f: F) -> R + where F: FnOnce(&DecodingContext<'tcx>) -> R { - let tls_payload = (dcx as *const _, decoder as *mut _); + let tls_payload = dcx as *const _; let tls_ptr = &tls_payload as *const _ as *const TlsPayload; TLS_DECODING.with(|tls| { let prev = tls.get(); tls.set(Some(tls_ptr)); - let ret = f(dcx, decoder); + let ret = f(dcx); tls.set(prev); - return ret + ret }) } - /// Execute f with access to the thread-local decoding context and - /// rbml decoder. This function will panic if the decoder passed in and the - /// context decoder are not the same. - /// - /// Note that this method is 'practically' safe due to its checking that the - /// decoder passed in is the same as the one in TLS, but it would still be - /// possible to construct cases where the DecodingContext is exchanged - /// while the same decoder is used, thus working with a wrong context. - pub fn with_decoding_context<'decoder, 'tcx, D, F, R>(d: &'decoder mut D, f: F) -> R - where D: serialize::Decoder, - F: FnOnce(&DecodingContext<'tcx>, - &mut OpaqueDecoder) -> R, - 'tcx: 'decoder + /// Execute f with access to the thread-local decoding context. + /// FIXME(eddyb) This is horribly unsound as it allows the + /// caler to pick any lifetime for 'tcx, including 'static. + pub fn with_decoding_context<'tcx, F, R>(f: F) -> R + where F: FnOnce(&DecodingContext<'tcx>) -> R, { unsafe { - unsafe_with_decoding_context(|dcx, decoder| { - assert!((d as *mut _ as usize) == (decoder as *mut _ as usize)); - - let dcx: &DecodingContext<'tcx> = mem::transmute(dcx); - - f(dcx, decoder) + TLS_DECODING.with(|tls| { + let tls = tls.get().unwrap(); + f(*(tls as *mut &DecodingContext)) }) } } - - /// Execute f with access to the thread-local decoding context and - /// rbml decoder. - pub unsafe fn unsafe_with_decoding_context(f: F) -> R - where F: FnOnce(&DecodingContext, &mut OpaqueDecoder) -> R - { - TLS_DECODING.with(|tls| { - let tls = tls.get().unwrap(); - let tls_payload = tls as *mut (&DecodingContext, &mut OpaqueDecoder); - f((*tls_payload).0, (*tls_payload).1) - }) - } } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 14eb2fb7914c..716b4672ec72 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -34,7 +34,7 @@ use util::common::MemoizationMap; use util::nodemap::NodeSet; use util::nodemap::FnvHashMap; -use serialize::{Encodable, Encoder, Decodable, Decoder}; +use serialize::{self, Encodable, Encoder, Decodable, Decoder}; use std::borrow::Cow; use std::cell::Cell; use std::hash::{Hash, Hasher}; @@ -567,23 +567,8 @@ impl<'tcx> Hash for TyS<'tcx> { pub type Ty<'tcx> = &'tcx TyS<'tcx>; -impl<'tcx> Encodable for Ty<'tcx> { - fn encode(&self, s: &mut S) -> Result<(), S::Error> { - cstore::tls::with_encoding_context(s, |ecx, rbml_w| { - ecx.encode_ty(rbml_w, *self); - Ok(()) - }) - } -} - -impl<'tcx> Decodable for Ty<'tcx> { - fn decode(d: &mut D) -> Result, D::Error> { - cstore::tls::with_decoding_context(d, |dcx, rbml_r| { - Ok(dcx.decode_ty(rbml_r)) - }) - } -} - +impl<'tcx> serialize::UseSpecializedEncodable for Ty<'tcx> {} +impl<'tcx> serialize::UseSpecializedDecodable for Ty<'tcx> {} /// Upvars do not get their own node-id. Instead, we use the pair of /// the original var id (that is, the root variable that is referenced @@ -1506,7 +1491,7 @@ impl<'tcx> Decodable for AdtDef<'tcx> { fn decode(d: &mut D) -> Result, D::Error> { let def_id: DefId = Decodable::decode(d)?; - cstore::tls::with_decoding_context(d, |dcx, _| { + cstore::tls::with_decoding_context(|dcx| { let def_id = dcx.translate_def_id(def_id); Ok(dcx.tcx().lookup_adt_def(def_id)) }) diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 5fdc7abc0af5..5f02b1be44a8 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -275,7 +275,7 @@ impl<'tcx> Encodable for ClosureSubsts<'tcx> { impl<'tcx> Decodable for ClosureSubsts<'tcx> { fn decode(d: &mut D) -> Result, D::Error> { let (func_substs, upvar_tys) = Decodable::decode(d)?; - cstore::tls::with_decoding_context(d, |dcx, _| { + cstore::tls::with_decoding_context(|dcx| { Ok(ClosureSubsts { func_substs: func_substs, upvar_tys: dcx.tcx().mk_type_list(upvar_tys) @@ -666,7 +666,7 @@ pub enum Region { impl<'tcx> Decodable for &'tcx Region { fn decode(d: &mut D) -> Result<&'tcx Region, D::Error> { let r = Decodable::decode(d)?; - cstore::tls::with_decoding_context(d, |dcx, _| { + cstore::tls::with_decoding_context(|dcx| { Ok(dcx.tcx().mk_region(r)) }) } diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs index 0ccfea233099..6b493118bcfd 100644 --- a/src/librustc/ty/subst.rs +++ b/src/librustc/ty/subst.rs @@ -10,12 +10,11 @@ // Type substitutions. -use middle::cstore; use hir::def_id::DefId; use ty::{self, Ty, TyCtxt}; use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; -use serialize::{Encodable, Encoder, Decodable, Decoder}; +use serialize; use syntax_pos::{Span, DUMMY_SP}; use core::nonzero::NonZero; @@ -298,25 +297,8 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx Substs<'tcx> { } } -impl<'tcx> Encodable for &'tcx Substs<'tcx> { - fn encode(&self, s: &mut S) -> Result<(), S::Error> { - cstore::tls::with_encoding_context(s, |ecx, rbml_w| { - ecx.encode_substs(rbml_w, self); - Ok(()) - }) - } -} - -impl<'tcx> Decodable for &'tcx Substs<'tcx> { - fn decode(d: &mut D) -> Result<&'tcx Substs<'tcx>, D::Error> { - let substs = cstore::tls::with_decoding_context(d, |dcx, rbml_r| { - dcx.decode_substs(rbml_r) - }); - - Ok(substs) - } -} - +impl<'tcx> serialize::UseSpecializedEncodable for &'tcx Substs<'tcx> {} +impl<'tcx> serialize::UseSpecializedDecodable for &'tcx Substs<'tcx> {} /////////////////////////////////////////////////////////////////////////// // Public trait `Subst` diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 4bc8caf037ae..3b6984a8c462 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -28,13 +28,14 @@ use middle::dependency_format::Linkage; use rustc::dep_graph::DepNode; use rustc::traits::specialization_graph; use rustc::ty::{self, Ty, TyCtxt}; +use rustc::ty::subst::Substs; use rustc::hir::svh::Svh; use rustc::mir::mir_map::MirMap; use rustc::session::config::{self, PanicStrategy, CrateTypeRustcMacro}; use rustc::util::nodemap::{FnvHashMap, NodeSet}; -use rustc_serialize::Encodable; +use rustc_serialize::{Encodable, SpecializedEncoder, SpecializedDecoder}; use std::cell::RefCell; use std::io::prelude::*; use std::io::{Cursor, SeekFrom}; @@ -78,6 +79,48 @@ impl<'a, 'tcx> DerefMut for EncodeContext<'a, 'tcx> { } } +impl<'a, 'tcx> SpecializedEncoder> for EncodeContext<'a, 'tcx> { + fn specialized_encode(&mut self, ty: &Ty<'tcx>) -> Result<(), Self::Error> { + let cx = self.ty_str_ctxt(); + self.emit_opaque(|opaque_encoder| { + Ok(tyencode::enc_ty(opaque_encoder.cursor, &cx, ty)) + }) + } +} + +impl<'a, 'tcx> SpecializedEncoder<&'tcx Substs<'tcx>> for EncodeContext<'a, 'tcx> { + fn specialized_encode(&mut self, substs: &&'tcx Substs<'tcx>) -> Result<(), Self::Error> { + let cx = self.ty_str_ctxt(); + self.emit_opaque(|opaque_encoder| { + Ok(tyencode::enc_substs(opaque_encoder.cursor, &cx, substs)) + }) + } +} + +/// FIXME(#31844) This is horribly unsound as it allows the +/// caller to pick any lifetime for 'tcx, including 'static. +impl<'a, 'tcx> SpecializedDecoder> for ::rbml::reader::Decoder<'a> { + fn specialized_decode(&mut self) -> Result, Self::Error> { + self.read_opaque(|opaque_decoder, _| { + ::middle::cstore::tls::with_decoding_context(|dcx| { + Ok(dcx.decode_ty(opaque_decoder)) + }) + }) + } +} + +/// FIXME(#31844) This is horribly unsound as it allows the +/// caller to pick any lifetime for 'tcx, including 'static. +impl<'a, 'tcx> SpecializedDecoder<&'tcx Substs<'tcx>> for ::rbml::reader::Decoder<'a> { + fn specialized_decode(&mut self) -> Result<&'tcx Substs<'tcx>, Self::Error> { + self.read_opaque(|opaque_decoder, _| { + ::middle::cstore::tls::with_decoding_context(|dcx| { + Ok(dcx.decode_substs(opaque_decoder)) + }) + }) + } +} + fn encode_name(ecx: &mut EncodeContext, name: Name) { ecx.wr_tagged_str(tag_paths_data_name, &name.as_str()); } diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs index d0d3d822f860..d9d103beaf0f 100644 --- a/src/librustc_metadata/lib.rs +++ b/src/librustc_metadata/lib.rs @@ -26,6 +26,7 @@ #![feature(rustc_macro_lib)] #![feature(rustc_macro_internals)] #![feature(rustc_private)] +#![feature(specialization)] #![feature(staged_api)] #![cfg_attr(test, feature(test))] diff --git a/src/librustc_metadata/tls_context.rs b/src/librustc_metadata/tls_context.rs index 6e78cbcd28e7..da6d04fc0ef3 100644 --- a/src/librustc_metadata/tls_context.rs +++ b/src/librustc_metadata/tls_context.rs @@ -11,32 +11,14 @@ // This module provides implementations for the thread-local encoding and // decoding context traits in rustc::middle::cstore::tls. -use rbml::opaque::Encoder as OpaqueEncoder; use rbml::opaque::Decoder as OpaqueDecoder; use rustc::middle::cstore::tls; use rustc::hir::def_id::DefId; use rustc::ty::subst::Substs; -use rustc::ty::{self, TyCtxt}; +use rustc::ty::{Ty, TyCtxt}; use decoder::{self, Cmd}; -use encoder; use tydecode::TyDecoder; -use tyencode; - -impl<'a, 'tcx: 'a> tls::EncodingContext<'tcx> for encoder::EncodeContext<'a, 'tcx> { - - fn tcx<'s>(&'s self) -> TyCtxt<'s, 'tcx, 'tcx> { - self.tcx - } - - fn encode_ty(&self, encoder: &mut OpaqueEncoder, t: ty::Ty<'tcx>) { - tyencode::enc_ty(encoder.cursor, &self.ty_str_ctxt(), t); - } - - fn encode_substs(&self, encoder: &mut OpaqueEncoder, substs: &Substs<'tcx>) { - tyencode::enc_substs(encoder.cursor, &self.ty_str_ctxt(), substs); - } -} pub struct DecodingContext<'a, 'tcx: 'a> { pub crate_metadata: Cmd<'a>, @@ -49,7 +31,7 @@ impl<'a, 'tcx: 'a> tls::DecodingContext<'tcx> for DecodingContext<'a, 'tcx> { self.tcx } - fn decode_ty(&self, decoder: &mut OpaqueDecoder) -> ty::Ty<'tcx> { + fn decode_ty(&self, decoder: &mut OpaqueDecoder) -> Ty<'tcx> { let def_id_convert = &mut |did| { decoder::translate_def_id(self.crate_metadata, did) }; From 3cbe4b8bce0fafb7b11895bb8b93ff6803fa8c03 Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Tue, 30 Aug 2016 08:14:12 +0300 Subject: [PATCH 408/443] rustc_metadata: sign-extend when decoding signed integers. --- src/librustc_metadata/rbml/reader.rs | 67 +++++++++++++++++++++------- 1 file changed, 50 insertions(+), 17 deletions(-) diff --git a/src/librustc_metadata/rbml/reader.rs b/src/librustc_metadata/rbml/reader.rs index 0950372477e4..d4ac97ce5e03 100644 --- a/src/librustc_metadata/rbml/reader.rs +++ b/src/librustc_metadata/rbml/reader.rs @@ -595,11 +595,9 @@ impl<'doc> Decoder<'doc> { } // variable-length unsigned integer with different tags. - // `first_tag` should be a tag for u8 or i8. - // `last_tag` should be the largest allowed integer tag with the matching signedness. + // `last_tag` should be the largest allowed unsigned integer tag. // all tags between them should be valid, in the order of u8, u16, u32 and u64. - fn _next_int(&mut self, - first_tag: EbmlEncoderTag, + fn next_uint(&mut self, last_tag: EbmlEncoderTag) -> DecodeResult { if self.pos >= self.parent.end { @@ -607,8 +605,8 @@ impl<'doc> Decoder<'doc> { } let TaggedDoc { tag: r_tag, doc: r_doc } = doc_at(self.parent.data, self.pos)?; - let r = if first_tag as usize <= r_tag && r_tag <= last_tag as usize { - match r_tag - first_tag as usize { + let r = if EsU8 as usize <= r_tag && r_tag <= last_tag as usize { + match r_tag - EsU8 as usize { 0 => doc_as_u8(r_doc) as u64, 1 => doc_as_u16(r_doc) as u64, 2 => doc_as_u32(r_doc) as u64, @@ -616,9 +614,8 @@ impl<'doc> Decoder<'doc> { _ => unreachable!(), } } else { - return Err(Expected(format!("expected EBML doc with tag {:?} through {:?} but \ + return Err(Expected(format!("expected EBML doc with tag EsU8 through {:?} but \ found tag {:?}", - first_tag, last_tag, r_tag))); }; @@ -629,7 +626,43 @@ impl<'doc> Decoder<'doc> { self.parent.end))); } self.pos = r_doc.end; - debug!("_next_int({:?}, {:?}) result={:?}", first_tag, last_tag, r); + debug!("next_uint({:?}) result={:?}", last_tag, r); + Ok(r) + } + + // variable-length signed integer with different tags. + // `last_tag` should be the largest allowed signed integer tag. + // all tags between them should be valid, in the order of i8, i16, i32 and i64. + fn next_int(&mut self, + last_tag: EbmlEncoderTag) + -> DecodeResult { + if self.pos >= self.parent.end { + return Err(Expected(format!("no more documents in current node!"))); + } + + let TaggedDoc { tag: r_tag, doc: r_doc } = doc_at(self.parent.data, self.pos)?; + let r = if EsI8 as usize <= r_tag && r_tag <= last_tag as usize { + match r_tag - EsI8 as usize { + 0 => doc_as_i8(r_doc) as i64, + 1 => doc_as_i16(r_doc) as i64, + 2 => doc_as_i32(r_doc) as i64, + 3 => doc_as_i64(r_doc), + _ => unreachable!(), + } + } else { + return Err(Expected(format!("expected EBML doc with tag EsI8 through {:?} but \ + found tag {:?}", + last_tag, + r_tag))); + }; + if r_doc.end > self.parent.end { + return Err(Expected(format!("invalid EBML, child extends to {:#x}, parent to \ + {:#x}", + r_doc.end, + self.parent.end))); + } + self.pos = r_doc.end; + debug!("next_int({:?}) result={:?}", last_tag, r); Ok(r) } @@ -662,19 +695,19 @@ impl<'doc> serialize::Decoder for Decoder<'doc> { } fn read_u64(&mut self) -> DecodeResult { - self._next_int(EsU8, EsU64) + self.next_uint(EsU64) } fn read_u32(&mut self) -> DecodeResult { - Ok(self._next_int(EsU8, EsU32)? as u32) + Ok(self.next_uint(EsU32)? as u32) } fn read_u16(&mut self) -> DecodeResult { - Ok(self._next_int(EsU8, EsU16)? as u16) + Ok(self.next_uint(EsU16)? as u16) } fn read_u8(&mut self) -> DecodeResult { Ok(doc_as_u8(self.next_doc(EsU8)?)) } fn read_usize(&mut self) -> DecodeResult { - let v = self._next_int(EsU8, EsU64)?; + let v = self.read_u64()?; if v > (::std::usize::MAX as u64) { Err(IntTooBig(v as usize)) } else { @@ -683,19 +716,19 @@ impl<'doc> serialize::Decoder for Decoder<'doc> { } fn read_i64(&mut self) -> DecodeResult { - Ok(self._next_int(EsI8, EsI64)? as i64) + Ok(self.next_int(EsI64)? as i64) } fn read_i32(&mut self) -> DecodeResult { - Ok(self._next_int(EsI8, EsI32)? as i32) + Ok(self.next_int(EsI32)? as i32) } fn read_i16(&mut self) -> DecodeResult { - Ok(self._next_int(EsI8, EsI16)? as i16) + Ok(self.next_int(EsI16)? as i16) } fn read_i8(&mut self) -> DecodeResult { Ok(doc_as_u8(self.next_doc(EsI8)?) as i8) } fn read_isize(&mut self) -> DecodeResult { - let v = self._next_int(EsI8, EsI64)? as i64; + let v = self.next_int(EsI64)? as i64; if v > (isize::MAX as i64) || v < (isize::MIN as i64) { debug!("FIXME \\#6122: Removing this makes this function miscompile"); Err(IntTooBig(v as usize)) From 97864d41a65d034fae21de35025e10151d765fef Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Tue, 30 Aug 2016 09:00:04 +0300 Subject: [PATCH 409/443] rustc_metadata: encode miscellaneous information opaquely. --- src/librustc_metadata/decoder.rs | 45 ++++++++-------------------- src/librustc_metadata/encoder.rs | 22 ++++++-------- src/librustc_metadata/rbml/reader.rs | 11 ++++--- src/librustc_metadata/rbml/writer.rs | 13 ++++---- 4 files changed, 32 insertions(+), 59 deletions(-) diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index ecddab0d0609..b808aad14368 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -553,16 +553,14 @@ pub fn get_type<'a, 'tcx>(cdata: Cmd, id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>) pub fn get_stability(cdata: Cmd, id: DefIndex) -> Option { let item = cdata.lookup_item(id); reader::maybe_get_doc(item, tag_items_data_item_stability).map(|doc| { - let mut decoder = reader::Decoder::new(doc); - Decodable::decode(&mut decoder).unwrap() + Decodable::decode(&mut doc.opaque()).unwrap() }) } pub fn get_deprecation(cdata: Cmd, id: DefIndex) -> Option { let item = cdata.lookup_item(id); reader::maybe_get_doc(item, tag_items_data_item_deprecation).map(|doc| { - let mut decoder = reader::Decoder::new(doc); - Decodable::decode(&mut decoder).unwrap() + Decodable::decode(&mut doc.opaque()).unwrap() }) } @@ -579,19 +577,12 @@ pub fn get_parent_impl(cdata: Cmd, id: DefIndex) -> Option { pub fn get_repr_attrs(cdata: Cmd, id: DefIndex) -> Vec { let item = cdata.lookup_item(id); - match reader::maybe_get_doc(item, tag_items_data_item_repr).map(|doc| { - let mut decoder = reader::Decoder::new(doc); - Decodable::decode(&mut decoder).unwrap() - }) { - Some(attrs) => attrs, - None => Vec::new(), - } + reader::maybe_get_doc(item, tag_items_data_item_repr).map_or(vec![], |doc| { + Decodable::decode(&mut doc.opaque()).unwrap() + }) } -pub fn get_impl_polarity<'tcx>(cdata: Cmd, - id: DefIndex) - -> Option -{ +pub fn get_impl_polarity(cdata: Cmd, id: DefIndex) -> Option { let item_doc = cdata.lookup_item(id); let fam = item_family(item_doc); match fam { @@ -602,15 +593,14 @@ pub fn get_impl_polarity<'tcx>(cdata: Cmd, } } -pub fn get_custom_coerce_unsized_kind<'tcx>( +pub fn get_custom_coerce_unsized_kind( cdata: Cmd, id: DefIndex) -> Option { let item_doc = cdata.lookup_item(id); reader::maybe_get_doc(item_doc, tag_impl_coerce_unsized_kind).map(|kind_doc| { - let mut decoder = reader::Decoder::new(kind_doc); - Decodable::decode(&mut decoder).unwrap() + Decodable::decode(&mut kind_doc.opaque()).unwrap() }) } @@ -989,8 +979,7 @@ pub fn get_trait_item_def_ids(cdata: Cmd, id: DefIndex) pub fn get_item_variances(cdata: Cmd, id: DefIndex) -> Vec { let item_doc = cdata.lookup_item(id); let variance_doc = reader::get_doc(item_doc, tag_item_variances); - let mut decoder = reader::Decoder::new(variance_doc); - Decodable::decode(&mut decoder).unwrap() + Decodable::decode(&mut variance_doc.opaque()).unwrap() } pub fn get_provided_trait_methods<'a, 'tcx>(cdata: Cmd, @@ -1109,10 +1098,7 @@ pub fn get_struct_field_names(cdata: Cmd, id: DefIndex) -> Vec { fn get_attributes(md: rbml::Doc) -> Vec { reader::maybe_get_doc(md, tag_attributes).map_or(vec![], |attrs_doc| { - let mut decoder = reader::Decoder::new(attrs_doc); - let mut attrs: Vec = decoder.read_opaque(|opaque_decoder, _| { - Decodable::decode(opaque_decoder) - }).unwrap(); + let mut attrs = Vec::::decode(&mut attrs_doc.opaque()).unwrap(); // Need new unique IDs: old thread-local IDs won't map to new threads. for attr in attrs.iter_mut() { @@ -1575,18 +1561,14 @@ pub fn get_imported_filemaps(metadata: &[u8]) -> Vec { let cm_doc = reader::get_doc(crate_doc, tag_codemap); reader::tagged_docs(cm_doc, tag_codemap_filemap).map(|filemap_doc| { - let mut decoder = reader::Decoder::new(filemap_doc); - decoder.read_opaque(|opaque_decoder, _| { - Decodable::decode(opaque_decoder) - }).unwrap() + Decodable::decode(&mut filemap_doc.opaque()).unwrap() }).collect() } pub fn closure_kind(cdata: Cmd, closure_id: DefIndex) -> ty::ClosureKind { let closure_doc = cdata.lookup_item(closure_id); let closure_kind_doc = reader::get_doc(closure_doc, tag_items_closure_kind); - let mut decoder = reader::Decoder::new(closure_kind_doc); - ty::ClosureKind::decode(&mut decoder).unwrap() + ty::ClosureKind::decode(&mut closure_kind_doc.opaque()).unwrap() } pub fn closure_ty<'a, 'tcx>(cdata: Cmd, closure_id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>) @@ -1606,8 +1588,7 @@ pub fn def_key(cdata: Cmd, id: DefIndex) -> hir_map::DefKey { fn item_def_key(item_doc: rbml::Doc) -> hir_map::DefKey { match reader::maybe_get_doc(item_doc, tag_def_key) { Some(def_key_doc) => { - let mut decoder = reader::Decoder::new(def_key_doc); - let simple_key = def_key::DefKey::decode(&mut decoder).unwrap(); + let simple_key = def_key::DefKey::decode(&mut def_key_doc.opaque()).unwrap(); let name = reader::maybe_get_doc(item_doc, tag_paths_data_name).map(|name| { token::intern(name.as_str()).as_str() }); diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 3b6984a8c462..3197d52e14d0 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -132,7 +132,7 @@ fn encode_def_id(ecx: &mut EncodeContext, id: DefId) { fn encode_def_key(ecx: &mut EncodeContext, key: DefKey) { let simple_key = def_key::simplify_def_key(key); ecx.start_tag(tag_def_key); - simple_key.encode(ecx); + simple_key.encode(&mut ecx.opaque()); ecx.end_tag(); } @@ -171,7 +171,7 @@ pub fn def_to_string(_tcx: TyCtxt, did: DefId) -> String { fn encode_item_variances(ecx: &mut EncodeContext, id: NodeId) { let v = ecx.tcx.item_variances(ecx.tcx.map.local_def_id(id)); ecx.start_tag(tag_item_variances); - v.encode(ecx); + v.encode(&mut ecx.opaque()); ecx.end_tag(); } @@ -786,7 +786,7 @@ impl<'a, 'b, 'tcx> ItemContentBuilder<'a, 'b, 'tcx> { attr)); } self.start_tag(tag_items_data_item_repr); - repr_attrs.encode(self.ecx); + repr_attrs.encode(&mut self.opaque()); self.end_tag(); } @@ -821,7 +821,7 @@ fn encode_inherent_implementations(ecx: &mut EncodeContext, fn encode_stability(ecx: &mut EncodeContext, stab_opt: Option<&attr::Stability>) { stab_opt.map(|stab| { ecx.start_tag(tag_items_data_item_stability); - stab.encode(ecx).unwrap(); + stab.encode(&mut ecx.opaque()).unwrap(); ecx.end_tag(); }); } @@ -829,7 +829,7 @@ fn encode_stability(ecx: &mut EncodeContext, stab_opt: Option<&attr::Stability>) fn encode_deprecation(ecx: &mut EncodeContext, depr_opt: Option) { depr_opt.map(|depr| { ecx.start_tag(tag_items_data_item_deprecation); - depr.encode(ecx).unwrap(); + depr.encode(&mut ecx.opaque()).unwrap(); ecx.end_tag(); }); } @@ -1068,7 +1068,7 @@ impl<'a, 'b, 'tcx> ItemContentBuilder<'a, 'b, 'tcx> { { Some(&kind) => { self.start_tag(tag_impl_coerce_unsized_kind); - kind.encode(self.ecx); + kind.encode(&mut self.opaque()); self.end_tag(); } None => {} @@ -1386,7 +1386,7 @@ impl<'a, 'b, 'tcx> ItemContentBuilder<'a, 'b, 'tcx> { self.end_tag(); self.start_tag(tag_items_closure_kind); - tcx.closure_kind(def_id).encode(self.ecx).unwrap(); + tcx.closure_kind(def_id).encode(&mut self.opaque()).unwrap(); self.end_tag(); assert!(self.mir_map.map.contains_key(&def_id)); @@ -1428,9 +1428,7 @@ fn encode_item_index(ecx: &mut EncodeContext, index: IndexData) { fn encode_attributes(ecx: &mut EncodeContext, attrs: &[ast::Attribute]) { ecx.start_tag(tag_attributes); - ecx.emit_opaque(|opaque_encoder| { - attrs.encode(opaque_encoder) - }).unwrap(); + attrs.encode(&mut ecx.opaque()).unwrap(); ecx.end_tag(); } @@ -1565,9 +1563,7 @@ fn encode_codemap(ecx: &mut EncodeContext) { } ecx.start_tag(tag_codemap_filemap); - ecx.emit_opaque(|opaque_encoder| { - filemap.encode(opaque_encoder) - }).unwrap(); + filemap.encode(&mut ecx.opaque()).unwrap(); ecx.end_tag(); } diff --git a/src/librustc_metadata/rbml/reader.rs b/src/librustc_metadata/rbml/reader.rs index d4ac97ce5e03..7878d8af9895 100644 --- a/src/librustc_metadata/rbml/reader.rs +++ b/src/librustc_metadata/rbml/reader.rs @@ -158,6 +158,10 @@ impl<'doc> Doc<'doc> { pub fn to_string(&self) -> String { self.as_str().to_string() } + + pub fn opaque(&self) -> opaque::Decoder<'doc> { + opaque::Decoder::new(self.data, self.start) + } } pub struct TaggedDoc<'a> { @@ -670,12 +674,7 @@ impl<'doc> Decoder<'doc> { where F: FnOnce(&mut opaque::Decoder, Doc) -> DecodeResult { let doc = self.next_doc(EsOpaque)?; - - let result = { - let mut opaque_decoder = opaque::Decoder::new(doc.data, doc.start); - op(&mut opaque_decoder, doc)? - }; - + let result = op(&mut doc.opaque(), doc)?; Ok(result) } diff --git a/src/librustc_metadata/rbml/writer.rs b/src/librustc_metadata/rbml/writer.rs index b49686e2379d..db3a51187c60 100644 --- a/src/librustc_metadata/rbml/writer.rs +++ b/src/librustc_metadata/rbml/writer.rs @@ -241,9 +241,7 @@ impl Encoder { } pos } -} -impl Encoder { // used internally to emit things like the vector length and so on fn _emit_tagged_sub(&mut self, v: usize) -> EncodeResult { if v as u8 as usize == v { @@ -256,16 +254,15 @@ impl Encoder { } } + pub fn opaque(&mut self) -> opaque::Encoder { + opaque::Encoder::new(&mut self.writer) + } + pub fn emit_opaque(&mut self, f: F) -> EncodeResult where F: FnOnce(&mut opaque::Encoder) -> EncodeResult { self.start_tag(EsOpaque as usize)?; - - { - let mut opaque_encoder = opaque::Encoder::new(&mut self.writer); - f(&mut opaque_encoder)?; - } - + f(&mut self.opaque())?; self.mark_stable_position(); self.end_tag() } From 91e7239db40372027a642bdbda19a6d593155a9f Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Tue, 30 Aug 2016 14:24:14 +0300 Subject: [PATCH 410/443] rustc_metadata: combine DecodeContext and rbml::reader::Decoder. --- src/librustc/middle/cstore.rs | 66 +--- src/librustc/middle/region.rs | 17 - src/librustc/ty/mod.rs | 16 +- src/librustc/ty/sty.rs | 32 +- src/librustc_metadata/astencode.rs | 478 +++++++-------------------- src/librustc_metadata/common.rs | 47 ++- src/librustc_metadata/decoder.rs | 122 ++++++- src/librustc_metadata/encoder.rs | 26 +- src/librustc_metadata/lib.rs | 4 - src/librustc_metadata/macros.rs | 46 --- src/librustc_metadata/rbml/reader.rs | 81 ++--- src/librustc_metadata/tls_context.rs | 84 ----- 12 files changed, 306 insertions(+), 713 deletions(-) delete mode 100644 src/librustc_metadata/macros.rs delete mode 100644 src/librustc_metadata/tls_context.rs diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 9dacb9062c1c..c201c47ef5c4 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -495,68 +495,4 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { pub trait MacroLoader { fn load_crate(&mut self, extern_crate: &ast::Item, allows_macros: bool) -> Vec; -} - -/// Metadata encoding and decoding can make use of thread-local encoding and -/// decoding contexts. These allow implementers of serialize::Encodable and -/// Decodable to access information and datastructures that would otherwise not -/// be available to them. For example, we can automatically translate def-id and -/// span information during decoding because the decoding context knows which -/// crate the data is decoded from. Or it allows to make ty::Ty decodable -/// because the context has access to the TyCtxt that is needed for creating -/// ty::Ty instances. -/// -/// Note, however, that this only works for RBML-based encoding and decoding at -/// the moment. -pub mod tls { - use rbml::opaque::Decoder as OpaqueDecoder; - use std::cell::Cell; - use ty::{Ty, TyCtxt}; - use ty::subst::Substs; - use hir::def_id::DefId; - - /// Marker type used for the TLS slot. - /// The type context cannot be used directly because the TLS - /// in libstd doesn't allow types generic over lifetimes. - struct TlsPayload; - - pub trait DecodingContext<'tcx> { - fn tcx<'a>(&'a self) -> TyCtxt<'a, 'tcx, 'tcx>; - fn decode_ty(&self, decoder: &mut OpaqueDecoder) -> Ty<'tcx>; - fn decode_substs(&self, decoder: &mut OpaqueDecoder) -> &'tcx Substs<'tcx>; - fn translate_def_id(&self, def_id: DefId) -> DefId; - } - - thread_local! { - static TLS_DECODING: Cell> = Cell::new(None) - } - - /// Execute f after pushing the given DecodingContext onto the TLS stack. - pub fn enter_decoding_context<'tcx, F, R>(dcx: &DecodingContext<'tcx>, f: F) -> R - where F: FnOnce(&DecodingContext<'tcx>) -> R - { - let tls_payload = dcx as *const _; - let tls_ptr = &tls_payload as *const _ as *const TlsPayload; - TLS_DECODING.with(|tls| { - let prev = tls.get(); - tls.set(Some(tls_ptr)); - let ret = f(dcx); - tls.set(prev); - ret - }) - } - - /// Execute f with access to the thread-local decoding context. - /// FIXME(eddyb) This is horribly unsound as it allows the - /// caler to pick any lifetime for 'tcx, including 'static. - pub fn with_decoding_context<'tcx, F, R>(f: F) -> R - where F: FnOnce(&DecodingContext<'tcx>) -> R, - { - unsafe { - TLS_DECODING.with(|tls| { - let tls = tls.get().unwrap(); - f(*(tls as *mut &DecodingContext)) - }) - } - } -} +} \ No newline at end of file diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index fb99820f7c85..33110c61e8f8 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -20,7 +20,6 @@ use dep_graph::DepNode; use hir::map as ast_map; use session::Session; use util::nodemap::{FnvHashMap, NodeMap, NodeSet}; -use middle::cstore::InlinedItem; use ty; use std::cell::RefCell; @@ -1256,19 +1255,3 @@ pub fn resolve_crate(sess: &Session, map: &ast_map::Map) -> RegionMaps { } return maps; } - -pub fn resolve_inlined_item(sess: &Session, - region_maps: &RegionMaps, - item: &InlinedItem) { - let mut visitor = RegionResolutionVisitor { - sess: sess, - region_maps: region_maps, - cx: Context { - root_id: None, - parent: ROOT_CODE_EXTENT, - var_parent: ROOT_CODE_EXTENT - }, - terminating_scopes: NodeSet() - }; - item.visit(&mut visitor); -} diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 716b4672ec72..c49094cb6881 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -21,7 +21,7 @@ pub use self::fold::TypeFoldable; use dep_graph::{self, DepNode}; use hir::map as ast_map; use middle; -use middle::cstore::{self, LOCAL_CRATE}; +use middle::cstore::LOCAL_CRATE; use hir::def::{Def, PathResolution, ExportMap}; use hir::def_id::DefId; use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem}; @@ -34,7 +34,7 @@ use util::common::MemoizationMap; use util::nodemap::NodeSet; use util::nodemap::FnvHashMap; -use serialize::{self, Encodable, Encoder, Decodable, Decoder}; +use serialize::{self, Encodable, Encoder}; use std::borrow::Cow; use std::cell::Cell; use std::hash::{Hash, Hasher}; @@ -1487,17 +1487,7 @@ impl<'tcx> Encodable for AdtDef<'tcx> { } } -impl<'tcx> Decodable for AdtDef<'tcx> { - fn decode(d: &mut D) -> Result, D::Error> { - let def_id: DefId = Decodable::decode(d)?; - - cstore::tls::with_decoding_context(|dcx| { - let def_id = dcx.translate_def_id(def_id); - Ok(dcx.tcx().lookup_adt_def(def_id)) - }) - } -} - +impl<'tcx> serialize::UseSpecializedDecodable for AdtDef<'tcx> {} #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub enum AdtKind { Struct, Union, Enum } diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 5f02b1be44a8..5176fb665fbf 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -10,7 +10,6 @@ //! This module contains TypeVariants and its major components -use middle::cstore; use hir::def_id::DefId; use middle::region; use ty::subst::Substs; @@ -25,7 +24,7 @@ use syntax::abi; use syntax::ast::{self, Name}; use syntax::parse::token::{keywords, InternedString}; -use serialize::{Decodable, Decoder, Encodable, Encoder}; +use serialize; use hir; @@ -253,7 +252,7 @@ pub enum TypeVariants<'tcx> { /// closure C wind up influencing the decisions we ought to make for /// closure C (which would then require fixed point iteration to /// handle). Plus it fixes an ICE. :P -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable)] pub struct ClosureSubsts<'tcx> { /// Lifetime and type parameters from the enclosing function. /// These are separated out because trans wants to pass them around @@ -266,23 +265,7 @@ pub struct ClosureSubsts<'tcx> { pub upvar_tys: &'tcx [Ty<'tcx>] } -impl<'tcx> Encodable for ClosureSubsts<'tcx> { - fn encode(&self, s: &mut S) -> Result<(), S::Error> { - (self.func_substs, self.upvar_tys).encode(s) - } -} - -impl<'tcx> Decodable for ClosureSubsts<'tcx> { - fn decode(d: &mut D) -> Result, D::Error> { - let (func_substs, upvar_tys) = Decodable::decode(d)?; - cstore::tls::with_decoding_context(|dcx| { - Ok(ClosureSubsts { - func_substs: func_substs, - upvar_tys: dcx.tcx().mk_type_list(upvar_tys) - }) - }) - } -} +impl<'tcx> serialize::UseSpecializedDecodable for ClosureSubsts<'tcx> {} #[derive(Clone, PartialEq, Eq, Hash)] pub struct TraitObject<'tcx> { @@ -663,14 +646,7 @@ pub enum Region { ReErased, } -impl<'tcx> Decodable for &'tcx Region { - fn decode(d: &mut D) -> Result<&'tcx Region, D::Error> { - let r = Decodable::decode(d)?; - cstore::tls::with_decoding_context(|dcx| { - Ok(dcx.tcx().mk_region(r)) - }) - } -} +impl<'tcx> serialize::UseSpecializedDecodable for &'tcx Region {} #[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug)] pub struct EarlyBoundRegion { diff --git a/src/librustc_metadata/astencode.rs b/src/librustc_metadata/astencode.rs index 3fd4d0cf2727..673a31c55abe 100644 --- a/src/librustc_metadata/astencode.rs +++ b/src/librustc_metadata/astencode.rs @@ -13,7 +13,6 @@ #![allow(unused_must_use)] use rustc::hir::map as ast_map; -use rustc::session::Session; use rustc::hir; use rustc::hir::fold; @@ -23,9 +22,9 @@ use rustc::hir::intravisit::{Visitor, IdRangeComputingVisitor, IdRange}; use common as c; use cstore; use decoder; -use encoder as e; -use tydecode; -use tyencode; + +use decoder::DecodeContext; +use encoder::EncodeContext; use middle::cstore::{InlinedItem, InlinedItemRef}; use rustc::ty::adjustment; @@ -33,15 +32,12 @@ use rustc::ty::cast; use middle::const_qualif::ConstQualif; use rustc::hir::def::{self, Def}; use rustc::hir::def_id::DefId; -use middle::region; -use rustc::ty::subst::Substs; use rustc::ty::{self, Ty, TyCtxt}; use syntax::ast; use syntax::ptr::P; use syntax_pos; -use std::cell::Cell; use std::io::SeekFrom; use std::io::prelude::*; @@ -50,15 +46,6 @@ use rbml; use rustc_serialize::{Decodable, Decoder, DecoderHelpers}; use rustc_serialize::{Encodable, EncoderHelpers}; -struct DecodeContext<'a, 'tcx: 'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, - cdata: &'a cstore::CrateMetadata, - from_id_range: IdRange, - to_id_range: IdRange, - // Cache the last used filemap for translating spans as an optimization. - last_filemap_index: Cell, -} - trait tr { fn tr(&self, dcx: &DecodeContext) -> Self; } @@ -66,7 +53,7 @@ trait tr { // ______________________________________________________________________ // Top-level methods. -pub fn encode_inlined_item(ecx: &mut e::EncodeContext, ii: InlinedItemRef) { +pub fn encode_inlined_item(ecx: &mut EncodeContext, ii: InlinedItemRef) { let id = match ii { InlinedItemRef::Item(_, i) => i.id, InlinedItemRef::TraitItem(_, ti) => ti.id, @@ -81,11 +68,16 @@ pub fn encode_inlined_item(ecx: &mut e::EncodeContext, ii: InlinedItemRef) { let id_range = inlined_item_id_range(&ii); assert_eq!(expected_id_range, id_range); - ecx.start_tag(c::tag_ast as usize); - id_range.encode(ecx); - ecx.start_tag(c::tag_tree as usize); - ecx.emit_opaque(|this| ii.encode(this)); + ecx.start_tag(c::tag_ast); + + ecx.start_tag(c::tag_id_range); + id_range.encode(&mut ecx.opaque()); ecx.end_tag(); + + ecx.start_tag(c::tag_tree); + ii.encode(ecx); + ecx.end_tag(); + encode_side_tables_for_ii(ecx, &ii); ecx.end_tag(); @@ -121,37 +113,27 @@ pub fn decode_inlined_item<'a, 'tcx>(cdata: &cstore::CrateMetadata, orig_did: DefId) -> &'tcx InlinedItem { debug!("> Decoding inlined fn: {:?}", tcx.item_path_str(orig_did)); - let mut ast_dsr = reader::Decoder::new(ast_doc); - let from_id_range = Decodable::decode(&mut ast_dsr).unwrap(); - let to_id_range = reserve_id_range(&tcx.sess, from_id_range); - let dcx = &DecodeContext { - cdata: cdata, - tcx: tcx, - from_id_range: from_id_range, - to_id_range: to_id_range, - last_filemap_index: Cell::new(0) - }; - let ii = ast_map::map_decoded_item(&dcx.tcx.map, + let id_range_doc = ast_doc.get(c::tag_id_range); + let from_id_range = IdRange::decode(&mut id_range_doc.opaque()).unwrap(); + let mut dcx = DecodeContext::new(tcx, cdata, from_id_range, + ast_doc.get(c::tag_tree)); + let ii = InlinedItem::decode(&mut dcx).unwrap(); + + let ii = ast_map::map_decoded_item(&tcx.map, parent_def_path, parent_did, - decode_ast(ast_doc), - dcx); - let name = match *ii { - InlinedItem::Item(_, ref i) => i.name, - InlinedItem::TraitItem(_, ref ti) => ti.name, - InlinedItem::ImplItem(_, ref ii) => ii.name + ii, + &dcx); + + let item_node_id = match ii { + &InlinedItem::Item(_, ref i) => i.id, + &InlinedItem::TraitItem(_, ref ti) => ti.id, + &InlinedItem::ImplItem(_, ref ii) => ii.id }; - debug!("Fn named: {}", name); - debug!("< Decoded inlined fn: {}::{}", - tcx.item_path_str(parent_did), - name); - region::resolve_inlined_item(&tcx.sess, &tcx.region_maps, ii); - decode_side_tables(dcx, ast_doc); - copy_item_types(dcx, ii, orig_did); - if let InlinedItem::Item(_, ref i) = *ii { - debug!(">>> DECODED ITEM >>>\n{}\n<<< DECODED ITEM <<<", - ::rustc::hir::print::item_to_string(&i)); - } + let inlined_did = tcx.map.local_def_id(item_node_id); + tcx.register_item_type(inlined_did, tcx.lookup_item_type(orig_did)); + + decode_side_tables(&mut dcx, ast_doc); ii } @@ -159,16 +141,6 @@ pub fn decode_inlined_item<'a, 'tcx>(cdata: &cstore::CrateMetadata, // ______________________________________________________________________ // Enumerating the IDs which appear in an AST -fn reserve_id_range(sess: &Session, - from_id_range: IdRange) -> IdRange { - // Handle the case of an empty range: - if from_id_range.empty() { return from_id_range; } - let cnt = from_id_range.max - from_id_range.min; - let to_id_min = sess.reserve_node_ids(cnt); - let to_id_max = to_id_min + cnt; - IdRange { min: to_id_min, max: to_id_max } -} - impl<'a, 'tcx> DecodeContext<'a, 'tcx> { /// Translates an internal id, meaning a node id that is known to refer to some part of the /// item currently being inlined, such as a local variable or argument. All naked node-ids @@ -312,20 +284,9 @@ fn simplify_ast(ii: InlinedItemRef) -> (InlinedItem, IdRange) { (ii, fld.id_range) } -fn decode_ast(item_doc: rbml::Doc) -> InlinedItem { - let chi_doc = item_doc.get(c::tag_tree as usize); - let mut rbml_r = reader::Decoder::new(chi_doc); - rbml_r.read_opaque(|decoder, _| Decodable::decode(decoder)).unwrap() -} - // ______________________________________________________________________ // Encoding and decoding of ast::def -fn decode_def(dcx: &DecodeContext, dsr: &mut reader::Decoder) -> Def { - let def: Def = Decodable::decode(dsr).unwrap(); - def.tr(dcx) -} - impl tr for Def { fn tr(&self, dcx: &DecodeContext) -> Def { match *self { @@ -378,11 +339,9 @@ impl tr for Def { // ______________________________________________________________________ // Encoding and decoding of freevar information -impl<'a> reader::Decoder<'a> { - fn read_freevar_entry(&mut self, dcx: &DecodeContext) - -> hir::Freevar { - let fv: hir::Freevar = Decodable::decode(self).unwrap(); - fv.tr(dcx) +impl<'a, 'tcx> DecodeContext<'a, 'tcx> { + fn read_freevar_entry(&mut self) -> hir::Freevar { + hir::Freevar::decode(self).unwrap().tr(self) } } @@ -398,7 +357,7 @@ impl tr for hir::Freevar { // ______________________________________________________________________ // Encoding and decoding of MethodCallee -impl<'a, 'tcx> e::EncodeContext<'a, 'tcx> { +impl<'a, 'tcx> EncodeContext<'a, 'tcx> { fn encode_method_callee(&mut self, autoderef: u32, method: &ty::MethodCallee<'tcx>) { @@ -412,31 +371,29 @@ impl<'a, 'tcx> e::EncodeContext<'a, 'tcx> { method.def_id.encode(this) }); this.emit_struct_field("ty", 2, |this| { - Ok(this.emit_ty(method.ty)) + method.ty.encode(this) }); this.emit_struct_field("substs", 3, |this| { - Ok(this.emit_substs(&method.substs)) + method.substs.encode(this) }) }).unwrap(); } } -impl<'a, 'tcx> reader::Decoder<'a> { - fn read_method_callee<'b>(&mut self, dcx: &DecodeContext<'b, 'tcx>) - -> (u32, ty::MethodCallee<'tcx>) { - +impl<'a, 'tcx> DecodeContext<'a, 'tcx> { + fn read_method_callee(&mut self) -> (u32, ty::MethodCallee<'tcx>) { self.read_struct("MethodCallee", 4, |this| { let autoderef = this.read_struct_field("autoderef", 0, Decodable::decode).unwrap(); Ok((autoderef, ty::MethodCallee { def_id: this.read_struct_field("def_id", 1, |this| { - DefId::decode(this).map(|d| d.tr(dcx)) + DefId::decode(this).map(|d| d.tr(this)) }).unwrap(), ty: this.read_struct_field("ty", 2, |this| { - Ok(this.read_ty(dcx)) + Ty::decode(this) }).unwrap(), substs: this.read_struct_field("substs", 3, |this| { - Ok(this.read_substs(dcx)) + Decodable::decode(this) }).unwrap() })) }).unwrap() @@ -446,21 +403,7 @@ impl<'a, 'tcx> reader::Decoder<'a> { // ______________________________________________________________________ // Encoding and decoding the side tables -impl<'a, 'tcx> e::EncodeContext<'a, 'tcx> { - fn emit_region(&mut self, r: &'tcx ty::Region) { - let cx = self.ty_str_ctxt(); - self.emit_opaque(|this| Ok(tyencode::enc_region(&mut this.cursor, - &cx, - r))); - } - - fn emit_ty(&mut self, ty: Ty<'tcx>) { - let cx = self.ty_str_ctxt(); - self.emit_opaque(|this| Ok(tyencode::enc_ty(&mut this.cursor, - &cx, - ty))); - } - +impl<'a, 'tcx> EncodeContext<'a, 'tcx> { fn emit_upvar_capture(&mut self, capture: &ty::UpvarCapture<'tcx>) { use rustc_serialize::Encoder; @@ -471,23 +414,14 @@ impl<'a, 'tcx> e::EncodeContext<'a, 'tcx> { } ty::UpvarCapture::ByRef(ty::UpvarBorrow { kind, region }) => { this.emit_enum_variant("ByRef", 2, 0, |this| { - this.emit_enum_variant_arg(0, - |this| kind.encode(this)); - this.emit_enum_variant_arg(1, - |this| Ok(this.emit_region(region))) + this.emit_enum_variant_arg(0, |this| kind.encode(this)); + this.emit_enum_variant_arg(1, |this| region.encode(this)) }) } } }).unwrap() } - fn emit_substs(&mut self, substs: &Substs<'tcx>) { - let cx = self.ty_str_ctxt(); - self.emit_opaque(|this| Ok(tyencode::enc_substs(&mut this.cursor, - &cx, - substs))); - } - fn emit_auto_adjustment(&mut self, adj: &adjustment::AutoAdjustment<'tcx>) { use rustc_serialize::Encoder; @@ -518,7 +452,7 @@ impl<'a, 'tcx> e::EncodeContext<'a, 'tcx> { adjustment::AdjustNeverToAny(ref ty) => { this.emit_enum_variant("AdjustNeverToAny", 5, 1, |this| { - this.emit_enum_variant_arg(0, |this| Ok(this.emit_ty(ty))) + this.emit_enum_variant_arg(0, |this| ty.encode(this)) }) } } @@ -532,8 +466,7 @@ impl<'a, 'tcx> e::EncodeContext<'a, 'tcx> { match autoref { &adjustment::AutoPtr(r, m) => { this.emit_enum_variant("AutoPtr", 0, 2, |this| { - this.emit_enum_variant_arg(0, - |this| Ok(this.emit_region(r))); + this.emit_enum_variant_arg(0, |this| r.encode(this)); this.emit_enum_variant_arg(1, |this| m.encode(this)) }) } @@ -562,24 +495,17 @@ impl<'a, 'tcx> e::EncodeContext<'a, 'tcx> { }); this.emit_struct_field("unsize", 2, |this| { - this.emit_option(|this| { - match auto_deref_ref.unsize { - None => this.emit_option_none(), - Some(target) => this.emit_option_some(|this| { - Ok(this.emit_ty(target)) - }) - } - }) + auto_deref_ref.unsize.encode(this) }) }); } fn tag(&mut self, - tag_id: c::astencode_tag, + tag_id: usize, f: F) where F: FnOnce(&mut Self), { - self.start_tag(tag_id as usize); + self.start_tag(tag_id); f(self); self.end_tag(); } @@ -590,7 +516,7 @@ impl<'a, 'tcx> e::EncodeContext<'a, 'tcx> { } struct SideTableEncodingIdVisitor<'a, 'b:'a, 'tcx:'b> { - ecx: &'a mut e::EncodeContext<'b, 'tcx>, + ecx: &'a mut EncodeContext<'b, 'tcx>, } impl<'a, 'b, 'tcx, 'v> Visitor<'v> for SideTableEncodingIdVisitor<'a, 'b, 'tcx> { @@ -599,15 +525,15 @@ impl<'a, 'b, 'tcx, 'v> Visitor<'v> for SideTableEncodingIdVisitor<'a, 'b, 'tcx> } } -fn encode_side_tables_for_ii(ecx: &mut e::EncodeContext, ii: &InlinedItem) { - ecx.start_tag(c::tag_table as usize); +fn encode_side_tables_for_ii(ecx: &mut EncodeContext, ii: &InlinedItem) { + ecx.start_tag(c::tag_table); ii.visit(&mut SideTableEncodingIdVisitor { ecx: ecx }); ecx.end_tag(); } -fn encode_side_tables_for_id(ecx: &mut e::EncodeContext, id: ast::NodeId) { +fn encode_side_tables_for_id(ecx: &mut EncodeContext, id: ast::NodeId) { let tcx = ecx.tcx; debug!("Encoding side tables for id {}", id); @@ -622,14 +548,14 @@ fn encode_side_tables_for_id(ecx: &mut e::EncodeContext, id: ast::NodeId) { if let Some(ty) = tcx.node_types().get(&id) { ecx.tag(c::tag_table_node_type, |ecx| { ecx.id(id); - ecx.emit_ty(*ty); + ty.encode(ecx); }) } if let Some(item_substs) = tcx.tables.borrow().item_substs.get(&id) { ecx.tag(c::tag_table_item_subst, |ecx| { ecx.id(id); - ecx.emit_substs(&item_substs.substs); + item_substs.substs.encode(ecx); }) } @@ -707,47 +633,8 @@ fn encode_side_tables_for_id(ecx: &mut e::EncodeContext, id: ast::NodeId) { } } -impl<'a, 'tcx> reader::Decoder<'a> { - fn read_ty_encoded<'b, F, R>(&mut self, dcx: &DecodeContext<'b, 'tcx>, op: F) -> R - where F: for<'x> FnOnce(&mut tydecode::TyDecoder<'x,'tcx>) -> R - { - return self.read_opaque(|_, doc| { - debug!("read_ty_encoded({})", type_string(doc)); - Ok(op( - &mut tydecode::TyDecoder::with_doc( - dcx.tcx, dcx.cdata.cnum, doc, - &mut |d| convert_def_id(dcx, d)))) - }).unwrap(); - - fn type_string(doc: rbml::Doc) -> String { - let mut str = String::new(); - for i in doc.start..doc.end { - str.push(doc.data[i] as char); - } - str - } - } - fn read_region<'b>(&mut self, dcx: &DecodeContext<'b, 'tcx>) -> &'tcx ty::Region { - // Note: regions types embed local node ids. In principle, we - // should translate these node ids into the new decode - // context. However, we do not bother, because region types - // are not used during trans. This also applies to read_ty. - return self.read_ty_encoded(dcx, |decoder| decoder.parse_region()); - } - fn read_ty<'b>(&mut self, dcx: &DecodeContext<'b, 'tcx>) -> Ty<'tcx> { - return self.read_ty_encoded(dcx, |decoder| decoder.parse_ty()); - } - - fn read_substs<'b>(&mut self, dcx: &DecodeContext<'b, 'tcx>) - -> &'tcx Substs<'tcx> { - self.read_opaque(|_, doc| { - Ok(tydecode::TyDecoder::with_doc(dcx.tcx, dcx.cdata.cnum, doc, - &mut |d| convert_def_id(dcx, d)) - .parse_substs()) - }).unwrap() - } - fn read_upvar_capture<'b>(&mut self, dcx: &DecodeContext<'b, 'tcx>) - -> ty::UpvarCapture<'tcx> { +impl<'a, 'tcx> DecodeContext<'a, 'tcx> { + fn read_upvar_capture(&mut self) -> ty::UpvarCapture<'tcx> { self.read_enum("UpvarCapture", |this| { let variants = ["ByValue", "ByRef"]; this.read_enum_variant(&variants, |this, i| { @@ -757,15 +644,14 @@ impl<'a, 'tcx> reader::Decoder<'a> { kind: this.read_enum_variant_arg(0, |this| Decodable::decode(this)).unwrap(), region: this.read_enum_variant_arg(1, - |this| Ok(this.read_region(dcx))).unwrap() + |this| Decodable::decode(this)).unwrap() }), _ => bug!("bad enum variant for ty::UpvarCapture") }) }) }).unwrap() } - fn read_auto_adjustment<'b>(&mut self, dcx: &DecodeContext<'b, 'tcx>) - -> adjustment::AutoAdjustment<'tcx> { + fn read_auto_adjustment(&mut self) -> adjustment::AutoAdjustment<'tcx> { self.read_enum("AutoAdjustment", |this| { let variants = ["AdjustReifyFnPointer", "AdjustUnsafeFnPointer", "AdjustMutToConstPointer", "AdjustDerefRef", @@ -778,13 +664,13 @@ impl<'a, 'tcx> reader::Decoder<'a> { 4 => { let auto_deref_ref: adjustment::AutoDerefRef = this.read_enum_variant_arg(0, - |this| Ok(this.read_auto_deref_ref(dcx))).unwrap(); + |this| Ok(this.read_auto_deref_ref())).unwrap(); adjustment::AdjustDerefRef(auto_deref_ref) } 5 => { let ty: Ty<'tcx> = this.read_enum_variant_arg(0, |this| { - Ok(this.read_ty(dcx)) + Ty::decode(this) }).unwrap(); adjustment::AdjustNeverToAny(ty) @@ -795,8 +681,7 @@ impl<'a, 'tcx> reader::Decoder<'a> { }).unwrap() } - fn read_auto_deref_ref<'b>(&mut self, dcx: &DecodeContext<'b, 'tcx>) - -> adjustment::AutoDerefRef<'tcx> { + fn read_auto_deref_ref(&mut self) -> adjustment::AutoDerefRef<'tcx> { self.read_struct("AutoDerefRef", 2, |this| { Ok(adjustment::AutoDerefRef { autoderefs: this.read_struct_field("autoderefs", 0, |this| { @@ -805,27 +690,20 @@ impl<'a, 'tcx> reader::Decoder<'a> { autoref: this.read_struct_field("autoref", 1, |this| { this.read_option(|this, b| { if b { - Ok(Some(this.read_autoref(dcx))) + Ok(Some(this.read_autoref())) } else { Ok(None) } }) }).unwrap(), unsize: this.read_struct_field("unsize", 2, |this| { - this.read_option(|this, b| { - if b { - Ok(Some(this.read_ty(dcx))) - } else { - Ok(None) - } - }) + Decodable::decode(this) }).unwrap(), }) }).unwrap() } - fn read_autoref<'b>(&mut self, dcx: &DecodeContext<'b, 'tcx>) - -> adjustment::AutoRef<'tcx> { + fn read_autoref(&mut self) -> adjustment::AutoRef<'tcx> { self.read_enum("AutoRef", |this| { let variants = ["AutoPtr", "AutoUnsafe"]; this.read_enum_variant(&variants, |this, i| { @@ -833,7 +711,7 @@ impl<'a, 'tcx> reader::Decoder<'a> { 0 => { let r: &'tcx ty::Region = this.read_enum_variant_arg(0, |this| { - Ok(this.read_region(dcx)) + Decodable::decode(this) }).unwrap(); let m: hir::Mutability = this.read_enum_variant_arg(1, |this| { @@ -853,133 +731,73 @@ impl<'a, 'tcx> reader::Decoder<'a> { }) }).unwrap() } - - fn read_cast_kind<'b>(&mut self, _dcx: &DecodeContext<'b, 'tcx>) - -> cast::CastKind - { - Decodable::decode(self).unwrap() - } } -// Converts a def-id that appears in a type. The correct -// translation will depend on what kind of def-id this is. -// This is a subtle point: type definitions are not -// inlined into the current crate, so if the def-id names -// a nominal type or type alias, then it should be -// translated to refer to the source crate. -// -// However, *type parameters* are cloned along with the function -// they are attached to. So we should translate those def-ids -// to refer to the new, cloned copy of the type parameter. -// We only see references to free type parameters in the body of -// an inlined function. In such cases, we need the def-id to -// be a local id so that the TypeContents code is able to lookup -// the relevant info in the ty_param_defs table. -// -// *Region parameters*, unfortunately, are another kettle of fish. -// In such cases, def_id's can appear in types to distinguish -// shadowed bound regions and so forth. It doesn't actually -// matter so much what we do to these, since regions are erased -// at trans time, but it's good to keep them consistent just in -// case. We translate them with `tr_def_id()` which will map -// the crate numbers back to the original source crate. -// -// Scopes will end up as being totally bogus. This can actually -// be fixed though. -// -// Unboxed closures are cloned along with the function being -// inlined, and all side tables use interned node IDs, so we -// translate their def IDs accordingly. -// -// It'd be really nice to refactor the type repr to not include -// def-ids so that all these distinctions were unnecessary. -fn convert_def_id(dcx: &DecodeContext, - did: DefId) - -> DefId { - let r = dcx.tr_def_id(did); - debug!("convert_def_id(did={:?})={:?}", did, r); - return r; -} +fn decode_side_tables<'a, 'tcx>(dcx: &mut DecodeContext<'a, 'tcx>, + ast_doc: rbml::Doc<'a>) { + for (tag, entry_doc) in reader::docs(ast_doc.get(c::tag_table)) { + dcx.rbml_r = reader::Decoder::new(entry_doc); -fn decode_side_tables(dcx: &DecodeContext, - ast_doc: rbml::Doc) { - let tbl_doc = ast_doc.get(c::tag_table as usize); - for (tag, entry_doc) in reader::docs(tbl_doc) { - let mut entry_dsr = reader::Decoder::new(entry_doc); - let id0: ast::NodeId = Decodable::decode(&mut entry_dsr).unwrap(); + let id0: ast::NodeId = Decodable::decode(dcx).unwrap(); let id = dcx.tr_id(id0); debug!(">> Side table document with tag 0x{:x} \ found for id {} (orig {})", tag, id, id0); - let tag = tag as u32; - let decoded_tag: Option = c::astencode_tag::from_u32(tag); - match decoded_tag { - None => { - bug!("unknown tag found in side tables: {:x}", tag); - } - Some(value) => { - let val_dsr = &mut entry_dsr; - match value { - c::tag_table_def => { - let def = decode_def(dcx, val_dsr); - dcx.tcx.def_map.borrow_mut().insert(id, def::PathResolution::new(def)); - } - c::tag_table_node_type => { - let ty = val_dsr.read_ty(dcx); - debug!("inserting ty for node {}: {:?}", - id, ty); - dcx.tcx.node_type_insert(id, ty); - } - c::tag_table_item_subst => { - let item_substs = ty::ItemSubsts { - substs: val_dsr.read_substs(dcx) - }; - dcx.tcx.tables.borrow_mut().item_substs.insert( - id, item_substs); - } - c::tag_table_freevars => { - let fv_info = val_dsr.read_to_vec(|val_dsr| { - Ok(val_dsr.read_freevar_entry(dcx)) - }).unwrap().into_iter().collect(); - dcx.tcx.freevars.borrow_mut().insert(id, fv_info); - } - c::tag_table_upvar_capture_map => { - let var_id: ast::NodeId = Decodable::decode(val_dsr).unwrap(); - let upvar_id = ty::UpvarId { - var_id: dcx.tr_id(var_id), - closure_expr_id: id - }; - let ub = val_dsr.read_upvar_capture(dcx); - dcx.tcx.tables.borrow_mut().upvar_capture_map.insert(upvar_id, ub); - } - c::tag_table_method_map => { - let (autoderef, method) = val_dsr.read_method_callee(dcx); - let method_call = ty::MethodCall { - expr_id: id, - autoderef: autoderef - }; - dcx.tcx.tables.borrow_mut().method_map.insert(method_call, method); - } - c::tag_table_adjustments => { - let adj = - val_dsr.read_auto_adjustment(dcx); - dcx.tcx.tables.borrow_mut().adjustments.insert(id, adj); - } - c::tag_table_cast_kinds => { - let cast_kind = - val_dsr.read_cast_kind(dcx); - dcx.tcx.cast_kinds.borrow_mut().insert(id, cast_kind); - } - c::tag_table_const_qualif => { - let qualif: ConstQualif = Decodable::decode(val_dsr).unwrap(); - dcx.tcx.const_qualif_map.borrow_mut().insert(id, qualif); - } - _ => { - bug!("unknown tag found in side tables: {:x}", tag); - } - } + match tag { + c::tag_table_def => { + let def = Def::decode(dcx).unwrap().tr(dcx); + dcx.tcx.def_map.borrow_mut().insert(id, def::PathResolution::new(def)); + } + c::tag_table_node_type => { + let ty = Ty::decode(dcx).unwrap(); + dcx.tcx.node_type_insert(id, ty); + } + c::tag_table_item_subst => { + let item_substs = ty::ItemSubsts { + substs: Decodable::decode(dcx).unwrap() + }; + dcx.tcx.tables.borrow_mut().item_substs.insert( + id, item_substs); + } + c::tag_table_freevars => { + let fv_info = dcx.read_to_vec(|dcx| { + Ok(dcx.read_freevar_entry()) + }).unwrap().into_iter().collect(); + dcx.tcx.freevars.borrow_mut().insert(id, fv_info); + } + c::tag_table_upvar_capture_map => { + let var_id = ast::NodeId::decode(dcx).unwrap(); + let upvar_id = ty::UpvarId { + var_id: dcx.tr_id(var_id), + closure_expr_id: id + }; + let ub = dcx.read_upvar_capture(); + dcx.tcx.tables.borrow_mut().upvar_capture_map.insert(upvar_id, ub); + } + c::tag_table_method_map => { + let (autoderef, method) = dcx.read_method_callee(); + let method_call = ty::MethodCall { + expr_id: id, + autoderef: autoderef + }; + dcx.tcx.tables.borrow_mut().method_map.insert(method_call, method); + } + c::tag_table_adjustments => { + let adj = dcx.read_auto_adjustment(); + dcx.tcx.tables.borrow_mut().adjustments.insert(id, adj); + } + c::tag_table_cast_kinds => { + let cast_kind = cast::CastKind::decode(dcx).unwrap(); + dcx.tcx.cast_kinds.borrow_mut().insert(id, cast_kind); + } + c::tag_table_const_qualif => { + let qualif = ConstQualif::decode(dcx).unwrap(); + dcx.tcx.const_qualif_map.borrow_mut().insert(id, qualif); + } + _ => { + bug!("unknown tag found in side tables: {:x}", tag); } } @@ -987,52 +805,6 @@ fn decode_side_tables(dcx: &DecodeContext, } } -// copy the tcache entries from the original item to the new -// inlined item -fn copy_item_types(dcx: &DecodeContext, ii: &InlinedItem, orig_did: DefId) { - fn copy_item_type(dcx: &DecodeContext, - inlined_id: ast::NodeId, - remote_did: DefId) { - let inlined_did = dcx.tcx.map.local_def_id(inlined_id); - dcx.tcx.register_item_type(inlined_did, - dcx.tcx.lookup_item_type(remote_did)); - - } - // copy the entry for the item itself - let item_node_id = match ii { - &InlinedItem::Item(_, ref i) => i.id, - &InlinedItem::TraitItem(_, ref ti) => ti.id, - &InlinedItem::ImplItem(_, ref ii) => ii.id - }; - copy_item_type(dcx, item_node_id, orig_did); - - // copy the entries of inner items - if let &InlinedItem::Item(_, ref item) = ii { - match item.node { - hir::ItemEnum(ref def, _) => { - let orig_def = dcx.tcx.lookup_adt_def(orig_did); - for (i_variant, orig_variant) in - def.variants.iter().zip(orig_def.variants.iter()) - { - debug!("astencode: copying variant {:?} => {:?}", - orig_variant.did, i_variant.node.data.id()); - copy_item_type(dcx, i_variant.node.data.id(), orig_variant.did); - } - } - hir::ItemStruct(ref def, _) => { - if !def.is_struct() { - let ctor_did = dcx.tcx.lookup_adt_def(orig_did) - .struct_variant().did; - debug!("astencode: copying ctor {:?} => {:?}", ctor_did, - def.id()); - copy_item_type(dcx, def.id(), ctor_did); - } - } - _ => {} - } - } -} - fn inlined_item_id_range(ii: &InlinedItem) -> IdRange { let mut visitor = IdRangeComputingVisitor::new(); ii.visit(&mut visitor); diff --git a/src/librustc_metadata/common.rs b/src/librustc_metadata/common.rs index 29b9cc0d1d92..c18b417466f9 100644 --- a/src/librustc_metadata/common.rs +++ b/src/librustc_metadata/common.rs @@ -10,8 +10,6 @@ #![allow(non_camel_case_types, non_upper_case_globals)] -pub use self::astencode_tag::*; - // RBML enum definitions and utils shared by the encoder and decoder // // 0x00..0x1f: reserved for RBML generic type tags @@ -97,33 +95,30 @@ pub const tag_items_data_item_reexport_def_id: usize = 0x47; pub const tag_items_data_item_reexport_name: usize = 0x48; // used to encode crate_ctxt side tables -enum_from_u32! { - #[derive(Copy, Clone, PartialEq)] - #[repr(usize)] - pub enum astencode_tag { // Reserves 0x50 -- 0x6f - tag_ast = 0x50, +pub const tag_ast: usize = 0x50; - tag_tree = 0x51, +pub const tag_tree: usize = 0x51; - tag_mir = 0x52, +pub const tag_mir: usize = 0x52; - tag_table = 0x53, - // GAP 0x54, 0x55 - tag_table_def = 0x56, - tag_table_node_type = 0x57, - tag_table_item_subst = 0x58, - tag_table_freevars = 0x59, - // GAP 0x5a, 0x5b, 0x5c, 0x5d, 0x5e - tag_table_method_map = 0x5f, - // GAP 0x60 - tag_table_adjustments = 0x61, - // GAP 0x62, 0x63, 0x64, 0x65 - tag_table_upvar_capture_map = 0x66, - // GAP 0x67, 0x68 - tag_table_const_qualif = 0x69, - tag_table_cast_kinds = 0x6a, - } -} +pub const tag_table: usize = 0x53; + +pub const tag_id_range: usize = 0x54; + +// GAP 0x55 +pub const tag_table_def: usize = 0x56; +pub const tag_table_node_type: usize = 0x57; +pub const tag_table_item_subst: usize = 0x58; +pub const tag_table_freevars: usize = 0x59; +// GAP 0x5a, 0x5b, 0x5c, 0x5d, 0x5e +pub const tag_table_method_map: usize = 0x5f; +// GAP 0x60 +pub const tag_table_adjustments: usize = 0x61; +// GAP 0x62, 0x63, 0x64, 0x65 +pub const tag_table_upvar_capture_map: usize = 0x66; +// GAP 0x67, 0x68 +pub const tag_table_const_qualif: usize = 0x69; +pub const tag_table_cast_kinds: usize = 0x6a; pub const tag_item_trait_item_sort: usize = 0x70; diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index b808aad14368..10c2747ab169 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -20,7 +20,6 @@ use common::*; use def_key; use encoder::def_to_u64; use index; -use tls_context; use tydecode::TyDecoder; use rustc::hir::def_id::CRATE_DEF_INDEX; @@ -29,15 +28,17 @@ use rustc::hir::map as hir_map; use rustc::hir::map::DefKey; use rustc::util::nodemap::FnvHashMap; use rustc::hir; +use rustc::hir::intravisit::IdRange; use rustc::session::config::PanicStrategy; use middle::cstore::{InlinedItem, LinkagePreference}; -use middle::cstore::{DefLike, DlDef, DlField, DlImpl, tls}; +use middle::cstore::{DefLike, DlDef, DlField, DlImpl}; use rustc::hir::def::Def; use rustc::hir::def_id::{DefId, DefIndex}; use middle::lang_items; use rustc::ty::{ImplContainer, TraitContainer}; use rustc::ty::{self, AdtKind, Ty, TyCtxt, TypeFoldable, VariantKind}; +use rustc::ty::subst::Substs; use rustc_const_math::ConstInt; @@ -47,12 +48,13 @@ use rustc::mir::repr::Location; use std::cell::Cell; use std::io; +use std::ops::{Deref, DerefMut}; use std::rc::Rc; use std::str; use rbml::reader; use rbml; -use rustc_serialize::Decodable; +use rustc_serialize::{Decodable, Decoder, SpecializedDecoder}; use syntax::attr; use syntax::parse::token; use syntax::ast; @@ -60,6 +62,106 @@ use syntax::codemap; use syntax::print::pprust; use syntax_pos::{self, Span, BytePos, NO_EXPANSION}; +pub struct DecodeContext<'a, 'tcx: 'a> { + pub rbml_r: rbml::reader::Decoder<'a>, + pub tcx: TyCtxt<'a, 'tcx, 'tcx>, + pub cdata: &'a cstore::CrateMetadata, + pub from_id_range: IdRange, + pub to_id_range: IdRange, + // Cache the last used filemap for translating spans as an optimization. + pub last_filemap_index: Cell, +} + +impl<'a, 'tcx> DecodeContext<'a, 'tcx> { + pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, + cdata: &'a cstore::CrateMetadata, + from_id_range: IdRange, + doc: rbml::Doc<'a>) + -> DecodeContext<'a, 'tcx> { + // Handle the case of an empty range: + let to_id_range = if from_id_range.empty() { + from_id_range + } else { + let cnt = from_id_range.max - from_id_range.min; + let to_id_min = tcx.sess.reserve_node_ids(cnt); + let to_id_max = to_id_min + cnt; + IdRange { min: to_id_min, max: to_id_max } + }; + + DecodeContext { + rbml_r: reader::Decoder::new(doc), + cdata: cdata, + tcx: tcx, + from_id_range: from_id_range, + to_id_range: to_id_range, + last_filemap_index: Cell::new(0) + } + } + + fn read_ty_encoded(&mut self, op: F) -> R + where F: for<'x> FnOnce(&mut TyDecoder<'x,'tcx>) -> R + { + self.read_opaque(|this, doc| { + Ok(op(&mut TyDecoder::with_doc( + this.tcx, this.cdata.cnum, doc, + &mut |d| this.tr_def_id(d)))) + }).unwrap() + } +} + +impl<'a, 'tcx> Deref for DecodeContext<'a, 'tcx> { + type Target = rbml::reader::Decoder<'a>; + fn deref(&self) -> &Self::Target { + &self.rbml_r + } +} + +impl<'a, 'tcx> DerefMut for DecodeContext<'a, 'tcx> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.rbml_r + } +} + +// FIXME(#36588) These impls are horribly unsound as they allow +// the caller to pick any lifetime for 'tcx, including 'static, +// by using the unspecialized proxies to them. + +impl<'a, 'tcx> SpecializedDecoder> for DecodeContext<'a, 'tcx> { + fn specialized_decode(&mut self) -> Result, Self::Error> { + Ok(self.read_ty_encoded(|d| d.parse_ty())) + } +} + +impl<'a, 'tcx> SpecializedDecoder<&'tcx Substs<'tcx>> for DecodeContext<'a, 'tcx> { + fn specialized_decode(&mut self) -> Result<&'tcx Substs<'tcx>, Self::Error> { + Ok(self.read_ty_encoded(|d| d.parse_substs())) + } +} + +impl<'a, 'tcx> SpecializedDecoder<&'tcx ty::Region> for DecodeContext<'a, 'tcx> { + fn specialized_decode(&mut self) -> Result<&'tcx ty::Region, Self::Error> { + let r = ty::Region::decode(self)?; + Ok(self.tcx.mk_region(r)) + } +} + +impl<'a, 'tcx> SpecializedDecoder> for DecodeContext<'a, 'tcx> { + fn specialized_decode(&mut self) -> Result, Self::Error> { + Ok(ty::ClosureSubsts { + func_substs: Decodable::decode(this)?, + upvar_tys: this.tcx.mk_type_list(Decodable::decode(this)?) + }) + } +} + +impl<'a, 'tcx> SpecializedDecoder> for DecodeContext<'a, 'tcx> { + fn specialized_decode(&mut self) -> Result, Self::Error> { + let def_id = DefId::decode(self)?; + let def_id = translate_def_id(self.cdata, def_id); + Ok(self.tcx.lookup_adt_def(def_id)) + } +} + pub type Cmd<'a> = &'a CrateMetadata; impl CrateMetadata { @@ -796,17 +898,13 @@ pub fn maybe_get_item_mir<'a, 'tcx>(cdata: Cmd, let item_doc = cdata.lookup_item(id); return reader::maybe_get_doc(item_doc, tag_mir as usize).map(|mir_doc| { - let dcx = tls_context::DecodingContext { - crate_metadata: cdata, - tcx: tcx, - }; - let mut decoder = reader::Decoder::new(mir_doc); + let mut dcx = DecodeContext::new(tcx, cdata, + IdRange { min: 0, max: 0 }, + mir_doc); - let mut mir = tls::enter_decoding_context(&dcx, |_| { - Decodable::decode(&mut decoder) - }).unwrap(); + let mut mir = Decodable::decode(&mut dcx).unwrap(); - assert!(decoder.position() == mir_doc.end); + assert!(dcx.rbml_r.position() == mir_doc.end); let mut def_id_and_span_translator = MirDefIdAndSpanTranslator { crate_metadata: cdata, diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 3197d52e14d0..0f7765713c3c 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -35,7 +35,7 @@ use rustc::mir::mir_map::MirMap; use rustc::session::config::{self, PanicStrategy, CrateTypeRustcMacro}; use rustc::util::nodemap::{FnvHashMap, NodeSet}; -use rustc_serialize::{Encodable, SpecializedEncoder, SpecializedDecoder}; +use rustc_serialize::{Encodable, SpecializedEncoder}; use std::cell::RefCell; use std::io::prelude::*; use std::io::{Cursor, SeekFrom}; @@ -97,30 +97,6 @@ impl<'a, 'tcx> SpecializedEncoder<&'tcx Substs<'tcx>> for EncodeContext<'a, 'tcx } } -/// FIXME(#31844) This is horribly unsound as it allows the -/// caller to pick any lifetime for 'tcx, including 'static. -impl<'a, 'tcx> SpecializedDecoder> for ::rbml::reader::Decoder<'a> { - fn specialized_decode(&mut self) -> Result, Self::Error> { - self.read_opaque(|opaque_decoder, _| { - ::middle::cstore::tls::with_decoding_context(|dcx| { - Ok(dcx.decode_ty(opaque_decoder)) - }) - }) - } -} - -/// FIXME(#31844) This is horribly unsound as it allows the -/// caller to pick any lifetime for 'tcx, including 'static. -impl<'a, 'tcx> SpecializedDecoder<&'tcx Substs<'tcx>> for ::rbml::reader::Decoder<'a> { - fn specialized_decode(&mut self) -> Result<&'tcx Substs<'tcx>, Self::Error> { - self.read_opaque(|opaque_decoder, _| { - ::middle::cstore::tls::with_decoding_context(|dcx| { - Ok(dcx.decode_substs(opaque_decoder)) - }) - }) - } -} - fn encode_name(ecx: &mut EncodeContext, name: Name) { ecx.wr_tagged_str(tag_paths_data_name, &name.as_str()); } diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs index d9d103beaf0f..428b33f2bfa6 100644 --- a/src/librustc_metadata/lib.rs +++ b/src/librustc_metadata/lib.rs @@ -61,9 +61,6 @@ pub mod rbml { pub use rustc::middle; -#[macro_use] -mod macros; - pub mod diagnostics; pub mod astencode; @@ -80,6 +77,5 @@ pub mod cstore; pub mod index; pub mod loader; pub mod macro_import; -pub mod tls_context; __build_diagnostic_array! { librustc_metadata, DIAGNOSTICS } diff --git a/src/librustc_metadata/macros.rs b/src/librustc_metadata/macros.rs deleted file mode 100644 index ed764ebd9f95..000000000000 --- a/src/librustc_metadata/macros.rs +++ /dev/null @@ -1,46 +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. - -macro_rules! enum_from_u32 { - ($(#[$attr:meta])* pub enum $name:ident { - $($variant:ident = $e:expr,)* - }) => { - $(#[$attr])* - pub enum $name { - $($variant = $e),* - } - - impl $name { - pub fn from_u32(u: u32) -> Option<$name> { - $(if u == $name::$variant as u32 { - return Some($name::$variant) - })* - None - } - } - }; - ($(#[$attr:meta])* pub enum $name:ident { - $($variant:ident,)* - }) => { - $(#[$attr])* - pub enum $name { - $($variant,)* - } - - impl $name { - pub fn from_u32(u: u32) -> Option<$name> { - $(if u == $name::$variant as u32 { - return Some($name::$variant) - })* - None - } - } - } -} diff --git a/src/librustc_metadata/rbml/reader.rs b/src/librustc_metadata/rbml/reader.rs index 7878d8af9895..02acfef612a1 100644 --- a/src/librustc_metadata/rbml/reader.rs +++ b/src/librustc_metadata/rbml/reader.rs @@ -555,20 +555,6 @@ impl<'doc> Decoder<'doc> { Ok(r_doc) } - fn push_doc(&mut self, exp_tag: EbmlEncoderTag, f: F) -> DecodeResult - where F: FnOnce(&mut Decoder<'doc>) -> DecodeResult - { - let d = self.next_doc(exp_tag)?; - let old_parent = self.parent; - let old_pos = self.pos; - self.parent = d; - self.pos = d.start; - let r = f(self)?; - self.parent = old_parent; - self.pos = old_pos; - Ok(r) - } - fn _next_sub(&mut self) -> DecodeResult { // empty vector/map optimization if self.parent.is_empty() { @@ -670,14 +656,6 @@ impl<'doc> Decoder<'doc> { Ok(r) } - pub fn read_opaque(&mut self, op: F) -> DecodeResult - where F: FnOnce(&mut opaque::Decoder, Doc) -> DecodeResult - { - let doc = self.next_doc(EsOpaque)?; - let result = op(&mut doc.opaque(), doc)?; - Ok(result) - } - pub fn position(&self) -> usize { self.pos } @@ -687,7 +665,30 @@ impl<'doc> Decoder<'doc> { } } -impl<'doc> serialize::Decoder for Decoder<'doc> { +impl<'doc, 'tcx> ::decoder::DecodeContext<'doc, 'tcx> { + pub fn read_opaque(&mut self, op: F) -> DecodeResult + where F: FnOnce(&mut Self, Doc) -> DecodeResult + { + let doc = self.next_doc(EsOpaque)?; + op(self, doc) + } + + fn push_doc(&mut self, exp_tag: EbmlEncoderTag, f: F) -> DecodeResult + where F: FnOnce(&mut Self) -> DecodeResult + { + let d = self.next_doc(exp_tag)?; + let old_parent = self.parent; + let old_pos = self.pos; + self.parent = d; + self.pos = d.start; + let r = f(self)?; + self.parent = old_parent; + self.pos = old_pos; + Ok(r) + } +} + +impl<'doc, 'tcx> serialize::Decoder for ::decoder::DecodeContext<'doc, 'tcx> { type Error = Error; fn read_nil(&mut self) -> DecodeResult<()> { Ok(()) @@ -757,7 +758,7 @@ impl<'doc> serialize::Decoder for Decoder<'doc> { // Compound types: fn read_enum(&mut self, name: &str, f: F) -> DecodeResult - where F: FnOnce(&mut Decoder<'doc>) -> DecodeResult + where F: FnOnce(&mut Self) -> DecodeResult { debug!("read_enum({})", name); @@ -775,7 +776,7 @@ impl<'doc> serialize::Decoder for Decoder<'doc> { } fn read_enum_variant(&mut self, _: &[&str], mut f: F) -> DecodeResult - where F: FnMut(&mut Decoder<'doc>, usize) -> DecodeResult + where F: FnMut(&mut Self, usize) -> DecodeResult { debug!("read_enum_variant()"); let idx = self._next_sub()?; @@ -785,14 +786,14 @@ impl<'doc> serialize::Decoder for Decoder<'doc> { } fn read_enum_variant_arg(&mut self, idx: usize, f: F) -> DecodeResult - where F: FnOnce(&mut Decoder<'doc>) -> DecodeResult + where F: FnOnce(&mut Self) -> DecodeResult { debug!("read_enum_variant_arg(idx={})", idx); f(self) } fn read_enum_struct_variant(&mut self, _: &[&str], mut f: F) -> DecodeResult - where F: FnMut(&mut Decoder<'doc>, usize) -> DecodeResult + where F: FnMut(&mut Self, usize) -> DecodeResult { debug!("read_enum_struct_variant()"); let idx = self._next_sub()?; @@ -806,28 +807,28 @@ impl<'doc> serialize::Decoder for Decoder<'doc> { idx: usize, f: F) -> DecodeResult - where F: FnOnce(&mut Decoder<'doc>) -> DecodeResult + where F: FnOnce(&mut Self) -> DecodeResult { debug!("read_enum_struct_variant_arg(name={}, idx={})", name, idx); f(self) } fn read_struct(&mut self, name: &str, _: usize, f: F) -> DecodeResult - where F: FnOnce(&mut Decoder<'doc>) -> DecodeResult + where F: FnOnce(&mut Self) -> DecodeResult { debug!("read_struct(name={})", name); f(self) } fn read_struct_field(&mut self, name: &str, idx: usize, f: F) -> DecodeResult - where F: FnOnce(&mut Decoder<'doc>) -> DecodeResult + where F: FnOnce(&mut Self) -> DecodeResult { debug!("read_struct_field(name={}, idx={})", name, idx); f(self) } fn read_tuple(&mut self, tuple_len: usize, f: F) -> DecodeResult - where F: FnOnce(&mut Decoder<'doc>) -> DecodeResult + where F: FnOnce(&mut Self) -> DecodeResult { debug!("read_tuple()"); self.read_seq(move |d, len| { @@ -843,28 +844,28 @@ impl<'doc> serialize::Decoder for Decoder<'doc> { } fn read_tuple_arg(&mut self, idx: usize, f: F) -> DecodeResult - where F: FnOnce(&mut Decoder<'doc>) -> DecodeResult + where F: FnOnce(&mut Self) -> DecodeResult { debug!("read_tuple_arg(idx={})", idx); self.read_seq_elt(idx, f) } fn read_tuple_struct(&mut self, name: &str, len: usize, f: F) -> DecodeResult - where F: FnOnce(&mut Decoder<'doc>) -> DecodeResult + where F: FnOnce(&mut Self) -> DecodeResult { debug!("read_tuple_struct(name={})", name); self.read_tuple(len, f) } fn read_tuple_struct_arg(&mut self, idx: usize, f: F) -> DecodeResult - where F: FnOnce(&mut Decoder<'doc>) -> DecodeResult + where F: FnOnce(&mut Self) -> DecodeResult { debug!("read_tuple_struct_arg(idx={})", idx); self.read_tuple_arg(idx, f) } fn read_option(&mut self, mut f: F) -> DecodeResult - where F: FnMut(&mut Decoder<'doc>, bool) -> DecodeResult + where F: FnMut(&mut Self, bool) -> DecodeResult { debug!("read_option()"); self.read_enum("Option", move |this| { @@ -879,7 +880,7 @@ impl<'doc> serialize::Decoder for Decoder<'doc> { } fn read_seq(&mut self, f: F) -> DecodeResult - where F: FnOnce(&mut Decoder<'doc>, usize) -> DecodeResult + where F: FnOnce(&mut Self, usize) -> DecodeResult { debug!("read_seq()"); self.push_doc(EsVec, move |d| { @@ -890,14 +891,14 @@ impl<'doc> serialize::Decoder for Decoder<'doc> { } fn read_seq_elt(&mut self, idx: usize, f: F) -> DecodeResult - where F: FnOnce(&mut Decoder<'doc>) -> DecodeResult + where F: FnOnce(&mut Self) -> DecodeResult { debug!("read_seq_elt(idx={})", idx); self.push_doc(EsVecElt, f) } fn read_map(&mut self, f: F) -> DecodeResult - where F: FnOnce(&mut Decoder<'doc>, usize) -> DecodeResult + where F: FnOnce(&mut Self, usize) -> DecodeResult { debug!("read_map()"); self.push_doc(EsMap, move |d| { @@ -908,14 +909,14 @@ impl<'doc> serialize::Decoder for Decoder<'doc> { } fn read_map_elt_key(&mut self, idx: usize, f: F) -> DecodeResult - where F: FnOnce(&mut Decoder<'doc>) -> DecodeResult + where F: FnOnce(&mut Self) -> DecodeResult { debug!("read_map_elt_key(idx={})", idx); self.push_doc(EsMapKey, f) } fn read_map_elt_val(&mut self, idx: usize, f: F) -> DecodeResult - where F: FnOnce(&mut Decoder<'doc>) -> DecodeResult + where F: FnOnce(&mut Self) -> DecodeResult { debug!("read_map_elt_val(idx={})", idx); self.push_doc(EsMapVal, f) diff --git a/src/librustc_metadata/tls_context.rs b/src/librustc_metadata/tls_context.rs deleted file mode 100644 index da6d04fc0ef3..000000000000 --- a/src/librustc_metadata/tls_context.rs +++ /dev/null @@ -1,84 +0,0 @@ -// 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. - -// This module provides implementations for the thread-local encoding and -// decoding context traits in rustc::middle::cstore::tls. - -use rbml::opaque::Decoder as OpaqueDecoder; -use rustc::middle::cstore::tls; -use rustc::hir::def_id::DefId; -use rustc::ty::subst::Substs; -use rustc::ty::{Ty, TyCtxt}; - -use decoder::{self, Cmd}; -use tydecode::TyDecoder; - -pub struct DecodingContext<'a, 'tcx: 'a> { - pub crate_metadata: Cmd<'a>, - pub tcx: TyCtxt<'a, 'tcx, 'tcx>, -} - -impl<'a, 'tcx: 'a> tls::DecodingContext<'tcx> for DecodingContext<'a, 'tcx> { - - fn tcx<'s>(&'s self) -> TyCtxt<'s, 'tcx, 'tcx> { - self.tcx - } - - fn decode_ty(&self, decoder: &mut OpaqueDecoder) -> Ty<'tcx> { - let def_id_convert = &mut |did| { - decoder::translate_def_id(self.crate_metadata, did) - }; - - let starting_position = decoder.position(); - - let mut ty_decoder = TyDecoder::new( - self.crate_metadata.data.as_slice(), - self.crate_metadata.cnum, - starting_position, - self.tcx, - def_id_convert); - - let ty = ty_decoder.parse_ty(); - - let end_position = ty_decoder.position(); - - // We can just reuse the tydecode implementation for parsing types, but - // we have to make sure to leave the rbml reader at the position just - // after the type. - decoder.advance(end_position - starting_position); - ty - } - - fn decode_substs(&self, decoder: &mut OpaqueDecoder) -> &'tcx Substs<'tcx> { - let def_id_convert = &mut |did| { - decoder::translate_def_id(self.crate_metadata, did) - }; - - let starting_position = decoder.position(); - - let mut ty_decoder = TyDecoder::new( - self.crate_metadata.data.as_slice(), - self.crate_metadata.cnum, - starting_position, - self.tcx, - def_id_convert); - - let substs = ty_decoder.parse_substs(); - - let end_position = ty_decoder.position(); - - decoder.advance(end_position - starting_position); - substs - } - - fn translate_def_id(&self, def_id: DefId) -> DefId { - decoder::translate_def_id(self.crate_metadata, def_id) - } -} From fc363cb482f92851b48b46402b5b5117627a840e Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Wed, 31 Aug 2016 14:00:29 +0300 Subject: [PATCH 411/443] rustc_metadata: go only through rustc_serialize in astencode. --- src/librustc/hir/def_id.rs | 54 +- src/librustc/hir/intravisit.rs | 6 +- src/librustc/hir/lowering.rs | 18 +- src/librustc/hir/map/collector.rs | 6 +- src/librustc/hir/map/definitions.rs | 7 +- src/librustc/hir/map/mod.rs | 106 +-- .../infer/region_inference/graphviz.rs | 5 +- src/librustc/middle/cstore.rs | 118 ++-- src/librustc/middle/dataflow.rs | 4 +- src/librustc/middle/dependency_format.rs | 30 +- src/librustc/middle/stability.rs | 5 +- src/librustc/session/mod.rs | 16 +- src/librustc/traits/coherence.rs | 3 +- src/librustc/traits/mod.rs | 2 +- src/librustc/ty/adjustment.rs | 6 +- src/librustc/ty/context.rs | 9 +- src/librustc/ty/item_path.rs | 5 +- src/librustc/ty/layout.rs | 15 +- src/librustc/ty/mod.rs | 13 +- src/librustc/ty/util.rs | 2 +- src/librustc_back/lib.rs | 1 - src/librustc_const_eval/check_match.rs | 4 +- src/librustc_driver/pretty.rs | 1 + src/librustc_driver/test.rs | 19 +- src/librustc_incremental/persist/directory.rs | 16 +- src/librustc_incremental/persist/fs.rs | 7 +- src/librustc_incremental/persist/hash.rs | 9 +- src/librustc_lint/types.rs | 2 +- src/librustc_metadata/astencode.rs | 642 ++---------------- src/librustc_metadata/creader.rs | 30 +- src/librustc_metadata/csearch.rs | 58 +- src/librustc_metadata/cstore.rs | 38 +- src/librustc_metadata/decoder.rs | 246 ++++--- src/librustc_metadata/encoder.rs | 9 +- src/librustc_metadata/tydecode.rs | 24 +- src/librustc_mir/transform/type_check.rs | 3 +- src/librustc_resolve/lib.rs | 4 +- src/librustc_resolve/macros.rs | 2 +- src/librustc_save_analysis/data.rs | 4 +- src/librustc_save_analysis/dump_visitor.rs | 18 +- src/librustc_save_analysis/external_data.rs | 9 +- src/librustc_save_analysis/json_api_dumper.rs | 2 +- src/librustc_save_analysis/json_dumper.rs | 2 +- src/librustc_save_analysis/lib.rs | 6 +- src/librustc_trans/adt.rs | 4 +- src/librustc_trans/back/link.rs | 9 +- src/librustc_trans/back/linker.rs | 4 +- .../back}/rpath.rs | 5 +- src/librustc_trans/back/symbol_names.rs | 8 +- src/librustc_trans/lib.rs | 2 +- src/librustc_trans/type_of.rs | 2 +- src/librustc_typeck/check/callee.rs | 3 +- src/librustc_typeck/check/compare_method.rs | 4 +- src/librustc_typeck/check/mod.rs | 9 +- src/librustc_typeck/coherence/orphan.rs | 3 +- src/librustdoc/clean/mod.rs | 12 +- src/librustdoc/core.rs | 6 +- src/librustdoc/doctree.rs | 5 +- src/librustdoc/html/format.rs | 3 +- src/librustdoc/html/render.rs | 9 +- src/librustdoc/visit_ast.rs | 3 +- src/librustdoc/visit_lib.rs | 5 +- src/libserialize/lib.rs | 3 +- src/libserialize/serialize.rs | 44 -- src/libsyntax/ast.rs | 38 +- src/libsyntax/attr.rs | 6 +- src/libsyntax/ext/expand.rs | 6 +- src/libsyntax/lib.rs | 1 + src/libsyntax_ext/deriving/generic/mod.rs | 20 +- src/libsyntax_pos/lib.rs | 17 +- 70 files changed, 605 insertions(+), 1212 deletions(-) rename src/{librustc_back => librustc_trans/back}/rpath.rs (98%) diff --git a/src/librustc/hir/def_id.rs b/src/librustc/hir/def_id.rs index 16afa705e391..f36fcfd51873 100644 --- a/src/librustc/hir/def_id.rs +++ b/src/librustc/hir/def_id.rs @@ -8,12 +8,59 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use middle::cstore::LOCAL_CRATE; use ty; -use syntax::ast::CrateNum; + +use rustc_data_structures::indexed_vec::Idx; +use serialize; + use std::fmt; use std::u32; +#[derive(Clone, Copy, Eq, Ord, PartialOrd, PartialEq, RustcEncodable, Hash, Debug)] +pub struct CrateNum(u32); + +impl Idx for CrateNum { + fn new(value: usize) -> Self { + assert!(value < (u32::MAX) as usize); + CrateNum(value as u32) + } + + fn index(self) -> usize { + self.0 as usize + } +} + +/// Item definitions in the currently-compiled crate would have the CrateNum +/// LOCAL_CRATE in their DefId. +pub const LOCAL_CRATE: CrateNum = CrateNum(0); + +impl CrateNum { + pub fn new(x: usize) -> CrateNum { + assert!(x < (u32::MAX as usize)); + CrateNum(x as u32) + } + + pub fn from_u32(x: u32) -> CrateNum { + CrateNum(x) + } + + pub fn as_usize(&self) -> usize { + self.0 as usize + } + + pub fn as_u32(&self) -> u32 { + self.0 + } +} + +impl fmt::Display for CrateNum { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(&self.0, f) + } +} + +impl serialize::UseSpecializedDecodable for CrateNum {} + /// A DefIndex is an index into the hir-map for a crate, identifying a /// particular definition. It should really be considered an interned /// shorthand for a particular DefPath. @@ -46,8 +93,7 @@ pub const CRATE_DEF_INDEX: DefIndex = DefIndex(0); /// A DefId identifies a particular *definition*, by combining a crate /// index and a def index. -#[derive(Clone, Eq, Ord, PartialOrd, PartialEq, RustcEncodable, - RustcDecodable, Hash, Copy)] +#[derive(Clone, Eq, Ord, PartialOrd, PartialEq, RustcEncodable, RustcDecodable, Hash, Copy)] pub struct DefId { pub krate: CrateNum, pub index: DefIndex, diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index f0caa971d969..726e4e53e231 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -881,8 +881,8 @@ pub struct IdRange { impl IdRange { pub fn max() -> IdRange { IdRange { - min: u32::MAX, - max: u32::MIN, + min: NodeId::from_u32(u32::MAX), + max: NodeId::from_u32(u32::MIN), } } @@ -896,7 +896,7 @@ impl IdRange { pub fn add(&mut self, id: NodeId) { self.min = cmp::min(self.min, id); - self.max = cmp::max(self.max, id + 1); + self.max = cmp::max(self.max, NodeId::from_u32(id.as_u32() + 1)); } } diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index f7c3eebdc298..9f7400c983e5 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -61,7 +61,7 @@ use syntax_pos::Span; pub struct LoweringContext<'a> { crate_root: Option<&'static str>, // Use to assign ids to hir nodes that do not directly correspond to an ast node - sess: Option<&'a Session>, + sess: &'a Session, // As we walk the AST we must keep track of the current 'parent' def id (in // the form of a DefIndex) so that if we create a new node which introduces // a definition, then we can properly create the def id. @@ -101,22 +101,13 @@ pub fn lower_crate(sess: &Session, } else { Some("std") }, - sess: Some(sess), + sess: sess, parent_def: None, resolver: resolver, }.lower_crate(krate) } impl<'a> LoweringContext<'a> { - pub fn testing_context(resolver: &'a mut Resolver) -> Self { - LoweringContext { - crate_root: None, - sess: None, - parent_def: None, - resolver: resolver, - } - } - fn lower_crate(&mut self, c: &Crate) -> hir::Crate { struct ItemLowerer<'lcx, 'interner: 'lcx> { items: BTreeMap, @@ -147,12 +138,11 @@ impl<'a> LoweringContext<'a> { } fn next_id(&self) -> NodeId { - self.sess.map(Session::next_node_id).unwrap_or(0) + self.sess.next_node_id() } fn diagnostic(&self) -> &errors::Handler { - self.sess.map(Session::diagnostic) - .unwrap_or_else(|| panic!("this lowerer cannot emit diagnostics")) + self.sess.diagnostic() } fn str_to_ident(&self, s: &'static str) -> Name { diff --git a/src/librustc/hir/map/collector.rs b/src/librustc/hir/map/collector.rs index d4e1eb70ae8f..6c6de8e89024 100644 --- a/src/librustc/hir/map/collector.rs +++ b/src/librustc/hir/map/collector.rs @@ -63,10 +63,10 @@ impl<'ast> NodeCollector<'ast> { fn insert_entry(&mut self, id: NodeId, entry: MapEntry<'ast>) { debug!("ast_map: {:?} => {:?}", id, entry); let len = self.map.len(); - if id as usize >= len { - self.map.extend(repeat(NotPresent).take(id as usize - len + 1)); + if id.as_usize() >= len { + self.map.extend(repeat(NotPresent).take(id.as_usize() - len + 1)); } - self.map[id as usize] = entry; + self.map[id.as_usize()] = entry; } fn insert(&mut self, id: NodeId, node: Node<'ast>) { diff --git a/src/librustc/hir/map/definitions.rs b/src/librustc/hir/map/definitions.rs index 901a489728ee..c0c28939ab27 100644 --- a/src/librustc/hir/map/definitions.rs +++ b/src/librustc/hir/map/definitions.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use middle::cstore::LOCAL_CRATE; -use hir::def_id::{DefId, DefIndex}; +use hir::def_id::{CrateNum, DefId, DefIndex, LOCAL_CRATE}; use hir::map::def_collector::DefCollector; use rustc_data_structures::fnv::FnvHashMap; use std::fmt::Write; @@ -70,7 +69,7 @@ pub struct DefPath { pub data: Vec, /// what krate root is this path relative to? - pub krate: ast::CrateNum, + pub krate: CrateNum, } impl DefPath { @@ -78,7 +77,7 @@ impl DefPath { self.krate == LOCAL_CRATE } - pub fn make(start_krate: ast::CrateNum, + pub fn make(start_krate: CrateNum, start_index: DefIndex, mut get_key: FN) -> DefPath where FN: FnMut(DefIndex) -> DefKey diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index 5c302d927a71..b728f1cbca09 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -22,17 +22,15 @@ use middle::cstore::InlinedItem as II; use hir::def_id::{CRATE_DEF_INDEX, DefId, DefIndex}; use syntax::abi::Abi; -use syntax::ast::{self, Name, NodeId, DUMMY_NODE_ID, }; +use syntax::ast::{self, Name, NodeId, CRATE_NODE_ID}; use syntax::codemap::Spanned; use syntax_pos::Span; use hir::*; -use hir::fold::Folder; use hir::print as pprust; use arena::TypedArena; use std::cell::RefCell; -use std::cmp; use std::io; use std::mem; @@ -240,7 +238,7 @@ impl<'ast> Map<'ast> { let mut id = id0; if !self.is_inlined_node_id(id) { loop { - match map[id as usize] { + match map[id.as_usize()] { EntryItem(_, item) => { let def_id = self.local_def_id(item.id); // NB ^~~~~~~ @@ -295,7 +293,7 @@ impl<'ast> Map<'ast> { // reading from an inlined def-id is really a read out of // the metadata from which we loaded the item. loop { - match map[id as usize] { + match map[id.as_usize()] { EntryItem(p, _) | EntryForeignItem(p, _) | EntryTraitItem(p, _) | @@ -373,7 +371,7 @@ impl<'ast> Map<'ast> { } fn find_entry(&self, id: NodeId) -> Option> { - self.map.borrow().get(id as usize).cloned() + self.map.borrow().get(id.as_usize()).cloned() } pub fn krate(&self) -> &'ast Crate { @@ -456,8 +454,8 @@ impl<'ast> Map<'ast> { let mut id = start_id; loop { let parent_node = self.get_parent_node(id); - if parent_node == 0 { - return Ok(0); + if parent_node == CRATE_NODE_ID { + return Ok(CRATE_NODE_ID); } if parent_node == id { return Err(id); @@ -680,7 +678,7 @@ impl<'ast> Map<'ast> { map: self, item_name: parts.last().unwrap(), in_which: &parts[..parts.len() - 1], - idx: 0, + idx: CRATE_NODE_ID, } } @@ -801,10 +799,10 @@ impl<'a, 'ast> Iterator for NodesMatchingSuffix<'a, 'ast> { fn next(&mut self) -> Option { loop { let idx = self.idx; - if idx as usize >= self.map.entry_count() { + if idx.as_usize() >= self.map.entry_count() { return None; } - self.idx += 1; + self.idx = NodeId::from_u32(self.idx.as_u32() + 1); let name = match self.map.find_entry(idx) { Some(EntryItem(_, n)) => n.name(), Some(EntryForeignItem(_, n))=> n.name(), @@ -832,57 +830,6 @@ impl Named for Variant_ { fn name(&self) -> Name { self.name } } impl Named for TraitItem { fn name(&self) -> Name { self.name } } impl Named for ImplItem { fn name(&self) -> Name { self.name } } -pub trait FoldOps { - fn new_id(&self, id: NodeId) -> NodeId { - id - } - fn new_def_id(&self, def_id: DefId) -> DefId { - def_id - } - fn new_span(&self, span: Span) -> Span { - span - } -} - -/// A Folder that updates IDs and Span's according to fold_ops. -pub struct IdAndSpanUpdater { - fold_ops: F, - min_id_assigned: NodeId, - max_id_assigned: NodeId, -} - -impl IdAndSpanUpdater { - pub fn new(fold_ops: F) -> IdAndSpanUpdater { - IdAndSpanUpdater { - fold_ops: fold_ops, - min_id_assigned: ::std::u32::MAX, - max_id_assigned: ::std::u32::MIN, - } - } - - pub fn id_range(&self) -> intravisit::IdRange { - intravisit::IdRange { - min: self.min_id_assigned, - max: self.max_id_assigned + 1, - } - } -} - -impl Folder for IdAndSpanUpdater { - fn new_id(&mut self, id: NodeId) -> NodeId { - let id = self.fold_ops.new_id(id); - - self.min_id_assigned = cmp::min(self.min_id_assigned, id); - self.max_id_assigned = cmp::max(self.max_id_assigned, id); - - id - } - - fn new_span(&mut self, span: Span) -> Span { - self.fold_ops.new_span(span) - } -} - pub fn map_crate<'ast>(forest: &'ast mut Forest, definitions: Definitions) -> Map<'ast> { @@ -906,7 +853,7 @@ pub fn map_crate<'ast>(forest: &'ast mut Forest, entries, vector_length, (entries as f64 / vector_length as f64) * 100.); } - let local_node_id_watermark = map.len() as NodeId; + let local_node_id_watermark = NodeId::new(map.len()); let local_def_id_watermark = definitions.len(); Map { @@ -921,36 +868,15 @@ pub fn map_crate<'ast>(forest: &'ast mut Forest, /// Used for items loaded from external crate that are being inlined into this /// crate. -pub fn map_decoded_item<'ast, F: FoldOps>(map: &Map<'ast>, - parent_def_path: DefPath, - parent_def_id: DefId, - ii: InlinedItem, - fold_ops: F) - -> &'ast InlinedItem { +pub fn map_decoded_item<'ast>(map: &Map<'ast>, + parent_def_path: DefPath, + parent_def_id: DefId, + ii: InlinedItem, + ii_parent_id: NodeId) + -> &'ast InlinedItem { let _ignore = map.forest.dep_graph.in_ignore(); - let mut fld = IdAndSpanUpdater::new(fold_ops); - let ii = match ii { - II::Item(d, i) => II::Item(fld.fold_ops.new_def_id(d), - i.map(|i| fld.fold_item(i))), - II::TraitItem(d, ti) => { - II::TraitItem(fld.fold_ops.new_def_id(d), - ti.map(|ti| fld.fold_trait_item(ti))) - } - II::ImplItem(d, ii) => { - II::ImplItem(fld.fold_ops.new_def_id(d), - ii.map(|ii| fld.fold_impl_item(ii))) - } - }; - let ii = map.forest.inlined_items.alloc(ii); - let ii_parent_id = fld.new_id(DUMMY_NODE_ID); - - // Assert that the ii_parent_id is the last NodeId in our reserved range - assert!(ii_parent_id == fld.max_id_assigned); - // Assert that we did not violate the invariant that all inlined HIR items - // have NodeIds greater than or equal to `local_node_id_watermark` - assert!(fld.min_id_assigned >= map.local_node_id_watermark); let defs = &mut *map.definitions.borrow_mut(); let mut def_collector = DefCollector::extend(ii_parent_id, diff --git a/src/librustc/infer/region_inference/graphviz.rs b/src/librustc/infer/region_inference/graphviz.rs index 1c64ebc0537a..289f7d6c7380 100644 --- a/src/librustc/infer/region_inference/graphviz.rs +++ b/src/librustc/infer/region_inference/graphviz.rs @@ -63,9 +63,8 @@ pub fn maybe_print_constraints_for<'a, 'gcx, 'tcx>( return; } - let requested_node: Option = env::var("RUST_REGION_GRAPH_NODE") - .ok() - .and_then(|s| s.parse().ok()); + let requested_node = env::var("RUST_REGION_GRAPH_NODE") + .ok().and_then(|s| s.parse().map(ast::NodeId::new).ok()); if requested_node.is_some() && requested_node != Some(subject_node) { return; diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index c201c47ef5c4..55a895b37ee3 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -23,7 +23,7 @@ // probably get a better home if someone can find one. use hir::def::{self, Def}; -use hir::def_id::{DefId, DefIndex}; +use hir::def_id::{CrateNum, DefId, DefIndex}; use hir::map as hir_map; use hir::map::definitions::DefKey; use hir::svh::Svh; @@ -64,7 +64,7 @@ pub struct LinkMeta { pub struct CrateSource { pub dylib: Option<(PathBuf, PathKind)>, pub rlib: Option<(PathBuf, PathKind)>, - pub cnum: ast::CrateNum, + pub cnum: CrateNum, } #[derive(Copy, Debug, PartialEq, Clone)] @@ -101,17 +101,13 @@ pub enum InlinedItem { } /// A borrowed version of `hir::InlinedItem`. -#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] +#[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, Hash, Debug)] pub enum InlinedItemRef<'a> { Item(DefId, &'a hir::Item), TraitItem(DefId, &'a hir::TraitItem), ImplItem(DefId, &'a hir::ImplItem) } -/// Item definitions in the currently-compiled crate would have the CrateNum -/// LOCAL_CRATE in their DefId. -pub const LOCAL_CRATE: ast::CrateNum = 0; - #[derive(Copy, Clone)] pub struct ChildItem { pub def: DefLike, @@ -203,35 +199,35 @@ pub trait CrateStore<'tcx> { fn is_typedef(&self, did: DefId) -> bool; // crate metadata - fn dylib_dependency_formats(&self, cnum: ast::CrateNum) - -> Vec<(ast::CrateNum, LinkagePreference)>; - fn lang_items(&self, cnum: ast::CrateNum) -> Vec<(DefIndex, usize)>; - fn missing_lang_items(&self, cnum: ast::CrateNum) -> Vec; - fn is_staged_api(&self, cnum: ast::CrateNum) -> bool; - fn is_explicitly_linked(&self, cnum: ast::CrateNum) -> bool; - fn is_allocator(&self, cnum: ast::CrateNum) -> bool; - fn is_panic_runtime(&self, cnum: ast::CrateNum) -> bool; - fn is_compiler_builtins(&self, cnum: ast::CrateNum) -> bool; - fn panic_strategy(&self, cnum: ast::CrateNum) -> PanicStrategy; - fn extern_crate(&self, cnum: ast::CrateNum) -> Option; - fn crate_attrs(&self, cnum: ast::CrateNum) -> Vec; + fn dylib_dependency_formats(&self, cnum: CrateNum) + -> Vec<(CrateNum, LinkagePreference)>; + fn lang_items(&self, cnum: CrateNum) -> Vec<(DefIndex, usize)>; + fn missing_lang_items(&self, cnum: CrateNum) -> Vec; + fn is_staged_api(&self, cnum: CrateNum) -> bool; + fn is_explicitly_linked(&self, cnum: CrateNum) -> bool; + fn is_allocator(&self, cnum: CrateNum) -> bool; + fn is_panic_runtime(&self, cnum: CrateNum) -> bool; + fn is_compiler_builtins(&self, cnum: CrateNum) -> bool; + fn panic_strategy(&self, cnum: CrateNum) -> PanicStrategy; + fn extern_crate(&self, cnum: CrateNum) -> Option; + fn crate_attrs(&self, cnum: CrateNum) -> Vec; /// The name of the crate as it is referred to in source code of the current /// crate. - fn crate_name(&self, cnum: ast::CrateNum) -> InternedString; + fn crate_name(&self, cnum: CrateNum) -> InternedString; /// The name of the crate as it is stored in the crate's metadata. - fn original_crate_name(&self, cnum: ast::CrateNum) -> InternedString; - fn crate_hash(&self, cnum: ast::CrateNum) -> Svh; - fn crate_disambiguator(&self, cnum: ast::CrateNum) -> InternedString; - fn crate_struct_field_attrs(&self, cnum: ast::CrateNum) + fn original_crate_name(&self, cnum: CrateNum) -> InternedString; + fn crate_hash(&self, cnum: CrateNum) -> Svh; + fn crate_disambiguator(&self, cnum: CrateNum) -> InternedString; + fn crate_struct_field_attrs(&self, cnum: CrateNum) -> FnvHashMap>; - fn plugin_registrar_fn(&self, cnum: ast::CrateNum) -> Option; - fn native_libraries(&self, cnum: ast::CrateNum) -> Vec<(NativeLibraryKind, String)>; - fn reachable_ids(&self, cnum: ast::CrateNum) -> Vec; - fn is_no_builtins(&self, cnum: ast::CrateNum) -> bool; + fn plugin_registrar_fn(&self, cnum: CrateNum) -> Option; + fn native_libraries(&self, cnum: CrateNum) -> Vec<(NativeLibraryKind, String)>; + fn reachable_ids(&self, cnum: CrateNum) -> Vec; + fn is_no_builtins(&self, cnum: CrateNum) -> bool; // resolve fn def_index_for_def_key(&self, - cnum: ast::CrateNum, + cnum: CrateNum, def: DefKey) -> Option; fn def_key(&self, def: DefId) -> hir_map::DefKey; @@ -241,7 +237,7 @@ pub trait CrateStore<'tcx> { fn tuple_struct_definition_if_ctor(&self, did: DefId) -> Option; fn struct_field_names(&self, def: DefId) -> Vec; fn item_children(&self, did: DefId) -> Vec; - fn crate_top_level_items(&self, cnum: ast::CrateNum) -> Vec; + fn crate_top_level_items(&self, cnum: CrateNum) -> Vec; // misc. metadata fn maybe_get_item_ast<'a>(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) @@ -255,7 +251,7 @@ pub trait CrateStore<'tcx> { // This is basically a 1-based range of ints, which is a little // silly - I may fix that. - fn crates(&self) -> Vec; + fn crates(&self) -> Vec; fn used_libraries(&self) -> Vec<(String, NativeLibraryKind)>; fn used_link_args(&self) -> Vec; @@ -267,9 +263,9 @@ pub trait CrateStore<'tcx> { ty: Ty<'tcx>, def_id_to_string: for<'b> fn(TyCtxt<'b, 'tcx, 'tcx>, DefId) -> String) -> Vec; - fn used_crates(&self, prefer: LinkagePreference) -> Vec<(ast::CrateNum, Option)>; - fn used_crate_source(&self, cnum: ast::CrateNum) -> CrateSource; - fn extern_mod_stmt_cnum(&self, emod_id: ast::NodeId) -> Option; + fn used_crates(&self, prefer: LinkagePreference) -> Vec<(CrateNum, Option)>; + fn used_crate_source(&self, cnum: CrateNum) -> CrateSource; + fn extern_mod_stmt_cnum(&self, emod_id: ast::NodeId) -> Option; fn encode_metadata<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, reexports: &def::ExportMap, link_meta: &LinkMeta, @@ -360,7 +356,7 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { fn trait_item_def_ids(&self, def: DefId) -> Vec { bug!("trait_item_def_ids") } fn def_index_for_def_key(&self, - cnum: ast::CrateNum, + cnum: CrateNum, def: DefKey) -> Option { None @@ -396,40 +392,40 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { fn is_typedef(&self, did: DefId) -> bool { bug!("is_typedef") } // crate metadata - fn dylib_dependency_formats(&self, cnum: ast::CrateNum) - -> Vec<(ast::CrateNum, LinkagePreference)> + fn dylib_dependency_formats(&self, cnum: CrateNum) + -> Vec<(CrateNum, LinkagePreference)> { bug!("dylib_dependency_formats") } - fn lang_items(&self, cnum: ast::CrateNum) -> Vec<(DefIndex, usize)> + fn lang_items(&self, cnum: CrateNum) -> Vec<(DefIndex, usize)> { bug!("lang_items") } - fn missing_lang_items(&self, cnum: ast::CrateNum) -> Vec + fn missing_lang_items(&self, cnum: CrateNum) -> Vec { bug!("missing_lang_items") } - fn is_staged_api(&self, cnum: ast::CrateNum) -> bool { bug!("is_staged_api") } - fn is_explicitly_linked(&self, cnum: ast::CrateNum) -> bool { bug!("is_explicitly_linked") } - fn is_allocator(&self, cnum: ast::CrateNum) -> bool { bug!("is_allocator") } - fn is_panic_runtime(&self, cnum: ast::CrateNum) -> bool { bug!("is_panic_runtime") } - fn is_compiler_builtins(&self, cnum: ast::CrateNum) -> bool { bug!("is_compiler_builtins") } - fn panic_strategy(&self, cnum: ast::CrateNum) -> PanicStrategy { + fn is_staged_api(&self, cnum: CrateNum) -> bool { bug!("is_staged_api") } + fn is_explicitly_linked(&self, cnum: CrateNum) -> bool { bug!("is_explicitly_linked") } + fn is_allocator(&self, cnum: CrateNum) -> bool { bug!("is_allocator") } + fn is_panic_runtime(&self, cnum: CrateNum) -> bool { bug!("is_panic_runtime") } + fn is_compiler_builtins(&self, cnum: CrateNum) -> bool { bug!("is_compiler_builtins") } + fn panic_strategy(&self, cnum: CrateNum) -> PanicStrategy { bug!("panic_strategy") } - fn extern_crate(&self, cnum: ast::CrateNum) -> Option { bug!("extern_crate") } - fn crate_attrs(&self, cnum: ast::CrateNum) -> Vec + fn extern_crate(&self, cnum: CrateNum) -> Option { bug!("extern_crate") } + fn crate_attrs(&self, cnum: CrateNum) -> Vec { bug!("crate_attrs") } - fn crate_name(&self, cnum: ast::CrateNum) -> InternedString { bug!("crate_name") } - fn original_crate_name(&self, cnum: ast::CrateNum) -> InternedString { + fn crate_name(&self, cnum: CrateNum) -> InternedString { bug!("crate_name") } + fn original_crate_name(&self, cnum: CrateNum) -> InternedString { bug!("original_crate_name") } - fn crate_hash(&self, cnum: ast::CrateNum) -> Svh { bug!("crate_hash") } - fn crate_disambiguator(&self, cnum: ast::CrateNum) + fn crate_hash(&self, cnum: CrateNum) -> Svh { bug!("crate_hash") } + fn crate_disambiguator(&self, cnum: CrateNum) -> InternedString { bug!("crate_disambiguator") } - fn crate_struct_field_attrs(&self, cnum: ast::CrateNum) + fn crate_struct_field_attrs(&self, cnum: CrateNum) -> FnvHashMap> { bug!("crate_struct_field_attrs") } - fn plugin_registrar_fn(&self, cnum: ast::CrateNum) -> Option + fn plugin_registrar_fn(&self, cnum: CrateNum) -> Option { bug!("plugin_registrar_fn") } - fn native_libraries(&self, cnum: ast::CrateNum) -> Vec<(NativeLibraryKind, String)> + fn native_libraries(&self, cnum: CrateNum) -> Vec<(NativeLibraryKind, String)> { bug!("native_libraries") } - fn reachable_ids(&self, cnum: ast::CrateNum) -> Vec { bug!("reachable_ids") } - fn is_no_builtins(&self, cnum: ast::CrateNum) -> bool { bug!("is_no_builtins") } + fn reachable_ids(&self, cnum: CrateNum) -> Vec { bug!("reachable_ids") } + fn is_no_builtins(&self, cnum: CrateNum) -> bool { bug!("is_no_builtins") } // resolve fn def_key(&self, def: DefId) -> hir_map::DefKey { bug!("def_key") } @@ -443,7 +439,7 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { { bug!("tuple_struct_definition_if_ctor") } fn struct_field_names(&self, def: DefId) -> Vec { bug!("struct_field_names") } fn item_children(&self, did: DefId) -> Vec { bug!("item_children") } - fn crate_top_level_items(&self, cnum: ast::CrateNum) -> Vec + fn crate_top_level_items(&self, cnum: CrateNum) -> Vec { bug!("crate_top_level_items") } // misc. metadata @@ -466,7 +462,7 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { // This is basically a 1-based range of ints, which is a little // silly - I may fix that. - fn crates(&self) -> Vec { vec![] } + fn crates(&self) -> Vec { vec![] } fn used_libraries(&self) -> Vec<(String, NativeLibraryKind)> { vec![] } fn used_link_args(&self) -> Vec { vec![] } @@ -480,10 +476,10 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { -> Vec { bug!("encode_type") } - fn used_crates(&self, prefer: LinkagePreference) -> Vec<(ast::CrateNum, Option)> + fn used_crates(&self, prefer: LinkagePreference) -> Vec<(CrateNum, Option)> { vec![] } - fn used_crate_source(&self, cnum: ast::CrateNum) -> CrateSource { bug!("used_crate_source") } - fn extern_mod_stmt_cnum(&self, emod_id: ast::NodeId) -> Option { None } + fn used_crate_source(&self, cnum: CrateNum) -> CrateSource { bug!("used_crate_source") } + fn extern_mod_stmt_cnum(&self, emod_id: ast::NodeId) -> Option { None } fn encode_metadata<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, reexports: &def::ExportMap, link_meta: &LinkMeta, diff --git a/src/librustc/middle/dataflow.rs b/src/librustc/middle/dataflow.rs index fc1294c86c44..7f3a58808c22 100644 --- a/src/librustc/middle/dataflow.rs +++ b/src/librustc/middle/dataflow.rs @@ -112,10 +112,10 @@ impl<'a, 'tcx, O:DataFlowOperator> pprust::PpAnn for DataFlowContext<'a, 'tcx, O ps: &mut pprust::State, node: pprust::AnnNode) -> io::Result<()> { let id = match node { - pprust::NodeName(_) => 0, + pprust::NodeName(_) => ast::CRATE_NODE_ID, pprust::NodeExpr(expr) => expr.id, pprust::NodeBlock(blk) => blk.id, - pprust::NodeItem(_) | pprust::NodeSubItem(_) => 0, + pprust::NodeItem(_) | pprust::NodeSubItem(_) => ast::CRATE_NODE_ID, pprust::NodePat(pat) => pat.id }; diff --git a/src/librustc/middle/dependency_format.rs b/src/librustc/middle/dependency_format.rs index 7822fe2536f1..c6908e11ed20 100644 --- a/src/librustc/middle/dependency_format.rs +++ b/src/librustc/middle/dependency_format.rs @@ -61,7 +61,7 @@ //! Additionally, the algorithm is geared towards finding *any* solution rather //! than finding a number of solutions (there are normally quite a few). -use syntax::ast; +use hir::def_id::CrateNum; use session; use session::config::{self, PanicStrategy}; @@ -169,9 +169,9 @@ fn calculate_type(sess: &session::Session, } // Collect what we've got so far in the return vector. - let last_crate = sess.cstore.crates().len() as ast::CrateNum; + let last_crate = sess.cstore.crates().len(); let mut ret = (1..last_crate+1).map(|cnum| { - match formats.get(&cnum) { + match formats.get(&CrateNum::new(cnum)) { Some(&RequireDynamic) => Linkage::Dynamic, Some(&RequireStatic) => Linkage::IncludedFromDylib, None => Linkage::NotLinked, @@ -191,7 +191,7 @@ fn calculate_type(sess: &session::Session, assert!(src.rlib.is_some()); info!("adding staticlib: {}", sess.cstore.crate_name(cnum)); add_library(sess, cnum, RequireStatic, &mut formats); - ret[cnum as usize - 1] = Linkage::Static; + ret[cnum.as_usize() - 1] = Linkage::Static; } } @@ -213,7 +213,7 @@ fn calculate_type(sess: &session::Session, // For situations like this, we perform one last pass over the dependencies, // making sure that everything is available in the requested format. for (cnum, kind) in ret.iter().enumerate() { - let cnum = (cnum + 1) as ast::CrateNum; + let cnum = CrateNum::new(cnum + 1); let src = sess.cstore.used_crate_source(cnum); match *kind { Linkage::NotLinked | @@ -237,9 +237,9 @@ fn calculate_type(sess: &session::Session, } fn add_library(sess: &session::Session, - cnum: ast::CrateNum, + cnum: CrateNum, link: LinkagePreference, - m: &mut FnvHashMap) { + m: &mut FnvHashMap) { match m.get(&cnum) { Some(&link2) => { // If the linkages differ, then we'd have two copies of the library @@ -269,9 +269,9 @@ fn attempt_static(sess: &session::Session) -> Option { // All crates are available in an rlib format, so we're just going to link // everything in explicitly so long as it's actually required. - let last_crate = sess.cstore.crates().len() as ast::CrateNum; + let last_crate = sess.cstore.crates().len(); let mut ret = (1..last_crate+1).map(|cnum| { - if sess.cstore.is_explicitly_linked(cnum) { + if sess.cstore.is_explicitly_linked(CrateNum::new(cnum)) { Linkage::Static } else { Linkage::NotLinked @@ -298,11 +298,11 @@ fn attempt_static(sess: &session::Session) -> Option { // a required dependency) in one of the session's field. If this field is not // set then this compilation doesn't actually need the dependency and we can // also skip this step entirely. -fn activate_injected_dep(injected: Option, +fn activate_injected_dep(injected: Option, list: &mut DependencyList, - replaces_injected: &Fn(ast::CrateNum) -> bool) { + replaces_injected: &Fn(CrateNum) -> bool) { for (i, slot) in list.iter().enumerate() { - let cnum = (i + 1) as ast::CrateNum; + let cnum = CrateNum::new(i + 1); if !replaces_injected(cnum) { continue } @@ -311,7 +311,7 @@ fn activate_injected_dep(injected: Option, } } if let Some(injected) = injected { - let idx = injected as usize - 1; + let idx = injected.as_usize() - 1; assert_eq!(list[idx], Linkage::NotLinked); list[idx] = Linkage::Static; } @@ -329,7 +329,7 @@ fn verify_ok(sess: &session::Session, list: &[Linkage]) { if let Linkage::NotLinked = *linkage { continue } - let cnum = (i + 1) as ast::CrateNum; + let cnum = CrateNum::new(i + 1); if sess.cstore.is_allocator(cnum) { if let Some(prev) = allocator { let prev_name = sess.cstore.crate_name(prev); @@ -380,7 +380,7 @@ fn verify_ok(sess: &session::Session, list: &[Linkage]) { if desired_strategy == PanicStrategy::Abort { continue } - let cnum = (i + 1) as ast::CrateNum; + let cnum = CrateNum::new(i + 1); let found_strategy = sess.cstore.panic_strategy(cnum); if desired_strategy == found_strategy { continue diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index 9a56959de38b..e2b997ed60f2 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -17,9 +17,8 @@ use dep_graph::DepNode; use hir::map as hir_map; use session::Session; use lint; -use middle::cstore::LOCAL_CRATE; use hir::def::Def; -use hir::def_id::{CRATE_DEF_INDEX, DefId, DefIndex}; +use hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId, DefIndex, LOCAL_CRATE}; use ty::{self, TyCtxt, AdtKind}; use middle::privacy::AccessLevels; use syntax::parse::token::InternedString; @@ -103,7 +102,7 @@ pub struct Index<'tcx> { depr_map: DefIdMap>, /// Maps for each crate whether it is part of the staged API. - staged_api: FnvHashMap + staged_api: FnvHashMap } // A private tree-walker for producing an Index. diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 49686d63ee43..268dbd70bb5b 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -9,7 +9,7 @@ // except according to those terms. use dep_graph::DepGraph; -use hir::def_id::DefIndex; +use hir::def_id::{CrateNum, DefIndex}; use hir::svh::Svh; use lint; use middle::cstore::CrateStore; @@ -93,8 +93,8 @@ pub struct Session { /// The metadata::creader module may inject an allocator/panic_runtime /// dependency if it didn't already find one, and this tracks what was /// injected. - pub injected_allocator: Cell>, - pub injected_panic_runtime: Cell>, + pub injected_allocator: Cell>, + pub injected_panic_runtime: Cell>, /// Map from imported macro spans (which consist of /// the localized span for the macro body) to the @@ -266,11 +266,13 @@ impl Session { } lints.insert(id, vec!((lint_id, sp, msg))); } - pub fn reserve_node_ids(&self, count: ast::NodeId) -> ast::NodeId { + pub fn reserve_node_ids(&self, count: usize) -> ast::NodeId { let id = self.next_node_id.get(); - match id.checked_add(count) { - Some(next) => self.next_node_id.set(next), + match id.as_usize().checked_add(count) { + Some(next) => { + self.next_node_id.set(ast::NodeId::new(next)); + } None => bug!("Input too large, ran out of node ids!") } @@ -545,7 +547,7 @@ pub fn build_session_(sopts: config::Options, crate_disambiguator: RefCell::new(token::intern("").as_str()), features: RefCell::new(feature_gate::Features::new()), recursion_limit: Cell::new(64), - next_node_id: Cell::new(1), + next_node_id: Cell::new(NodeId::new(1)), injected_allocator: Cell::new(None), injected_panic_runtime: Cell::new(None), imported_macro_spans: RefCell::new(HashMap::new()), diff --git a/src/librustc/traits/coherence.rs b/src/librustc/traits/coherence.rs index 83774f0cf7ea..68c88249ec0c 100644 --- a/src/librustc/traits/coherence.rs +++ b/src/librustc/traits/coherence.rs @@ -12,8 +12,7 @@ use super::{SelectionContext, Obligation, ObligationCause}; -use middle::cstore::LOCAL_CRATE; -use hir::def_id::DefId; +use hir::def_id::{DefId, LOCAL_CRATE}; use ty::{self, Ty, TyCtxt}; use infer::{InferCtxt, TypeOrigin}; use syntax_pos::DUMMY_SP; diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index b86a54f01cf4..a96cf1111e1d 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -571,7 +571,7 @@ impl<'tcx> ObligationCause<'tcx> { } pub fn dummy() -> ObligationCause<'tcx> { - ObligationCause { span: DUMMY_SP, body_id: 0, code: MiscObligation } + ObligationCause { span: DUMMY_SP, body_id: ast::CRATE_NODE_ID, code: MiscObligation } } } diff --git a/src/librustc/ty/adjustment.rs b/src/librustc/ty/adjustment.rs index 3386d894196f..cfe370343ae4 100644 --- a/src/librustc/ty/adjustment.rs +++ b/src/librustc/ty/adjustment.rs @@ -19,7 +19,7 @@ use syntax_pos::Span; use hir; -#[derive(Copy, Clone)] +#[derive(Copy, Clone, RustcEncodable, RustcDecodable)] pub enum AutoAdjustment<'tcx> { AdjustNeverToAny(Ty<'tcx>), // go from ! to any type AdjustReifyFnPointer, // go from a fn-item type to a fn-pointer type @@ -90,7 +90,7 @@ pub enum AutoAdjustment<'tcx> { /// unsize: Some(Box<[i32]>), /// } /// ``` -#[derive(Copy, Clone)] +#[derive(Copy, Clone, RustcEncodable, RustcDecodable)] pub struct AutoDerefRef<'tcx> { /// Step 1. Apply a number of dereferences, producing an lvalue. pub autoderefs: usize, @@ -122,7 +122,7 @@ impl<'tcx> AutoDerefRef<'tcx> { } -#[derive(Copy, Clone, PartialEq, Debug)] +#[derive(Copy, Clone, PartialEq, Debug, RustcEncodable, RustcDecodable)] pub enum AutoRef<'tcx> { /// Convert from T to &T. AutoPtr(&'tcx ty::Region, hir::Mutability), diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 6d7a2d6cba1c..bb9e90f89194 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -13,10 +13,9 @@ use dep_graph::{DepGraph, DepTrackingMap}; use session::Session; use middle; -use middle::cstore::LOCAL_CRATE; use hir::TraitMap; use hir::def::DefMap; -use hir::def_id::{DefId, DefIndex}; +use hir::def_id::{CrateNum, DefId, DefIndex, LOCAL_CRATE}; use hir::map as ast_map; use hir::map::{DefKey, DefPath, DefPathData, DisambiguatedDefPathData}; use middle::free_region::FreeRegionMap; @@ -512,7 +511,7 @@ impl<'tcx> GlobalCtxt<'tcx> { } impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { - pub fn crate_name(self, cnum: ast::CrateNum) -> token::InternedString { + pub fn crate_name(self, cnum: CrateNum) -> token::InternedString { if cnum == LOCAL_CRATE { self.crate_name.clone() } else { @@ -520,7 +519,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } } - pub fn crate_disambiguator(self, cnum: ast::CrateNum) -> token::InternedString { + pub fn crate_disambiguator(self, cnum: CrateNum) -> token::InternedString { if cnum == LOCAL_CRATE { self.sess.local_crate_disambiguator() } else { @@ -533,7 +532,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// relative to `krate`. /// /// Returns `None` if there is no `DefIndex` with that key. - pub fn def_index_for_def_key(self, krate: ast::CrateNum, key: DefKey) + pub fn def_index_for_def_key(self, krate: CrateNum, key: DefKey) -> Option { if krate == LOCAL_CRATE { self.map.def_index_for_def_key(key) diff --git a/src/librustc/ty/item_path.rs b/src/librustc/ty/item_path.rs index b6b55fc0e33d..e4247a60b15e 100644 --- a/src/librustc/ty/item_path.rs +++ b/src/librustc/ty/item_path.rs @@ -9,8 +9,7 @@ // except according to those terms. use hir::map::DefPathData; -use middle::cstore::LOCAL_CRATE; -use hir::def_id::{DefId, CRATE_DEF_INDEX}; +use hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE}; use ty::{self, Ty, TyCtxt}; use syntax::ast; use syntax::parse::token; @@ -67,7 +66,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// Returns the "path" to a particular crate. This can proceed in /// various ways, depending on the `root_mode` of the `buffer`. /// (See `RootMode` enum for more details.) - pub fn push_krate_path(self, buffer: &mut T, cnum: ast::CrateNum) + pub fn push_krate_path(self, buffer: &mut T, cnum: CrateNum) where T: ItemPathBuffer { match *buffer.root_mode() { diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 6fec698cfac9..5e7a2bc0266c 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -367,7 +367,7 @@ impl Integer { /// signed discriminant range and #[repr] attribute. /// N.B.: u64 values above i64::MAX will be treated as signed, but /// that shouldn't affect anything, other than maybe debuginfo. - pub fn repr_discr(tcx: TyCtxt, hint: attr::ReprAttr, min: i64, max: i64) + pub fn repr_discr(tcx: TyCtxt, ty: Ty, hint: attr::ReprAttr, min: i64, max: i64) -> (Integer, bool) { // Theoretically, negative values could be larger in unsigned representation // than the unsigned representation of the signed minimum. However, if there @@ -377,11 +377,12 @@ impl Integer { let signed_fit = cmp::max(Integer::fit_signed(min), Integer::fit_signed(max)); let at_least = match hint { - attr::ReprInt(span, ity) => { + attr::ReprInt(ity) => { let discr = Integer::from_attr(&tcx.data_layout, ity); let fit = if ity.is_signed() { signed_fit } else { unsigned_fit }; if discr < fit { - span_bug!(span, "representation hint insufficient for discriminant range") + bug!("Integer::repr_discr: `#[repr]` hint too small for \ + discriminant range of enum `{}", ty) } return (discr, ity.is_signed()); } @@ -397,10 +398,10 @@ impl Integer { } attr::ReprAny => I8, attr::ReprPacked => { - bug!("Integer::repr_discr: found #[repr(packed)] on an enum"); + bug!("Integer::repr_discr: found #[repr(packed)] on enum `{}", ty); } attr::ReprSimd => { - bug!("Integer::repr_discr: found #[repr(simd)] on an enum"); + bug!("Integer::repr_discr: found #[repr(simd)] on enum `{}", ty); } }; @@ -962,7 +963,7 @@ impl<'a, 'gcx, 'tcx> Layout { if x > max { max = x; } } - let (discr, signed) = Integer::repr_discr(tcx, hint, min, max); + let (discr, signed) = Integer::repr_discr(tcx, ty, hint, min, max); return success(CEnum { discr: discr, signed: signed, @@ -1052,7 +1053,7 @@ impl<'a, 'gcx, 'tcx> Layout { // The general case. let discr_max = (variants.len() - 1) as i64; assert!(discr_max >= 0); - let (min_ity, _) = Integer::repr_discr(tcx, hint, 0, discr_max); + let (min_ity, _) = Integer::repr_discr(tcx, ty, hint, 0, discr_max); let mut align = dl.aggregate_align; let mut size = Size::from_bytes(0); diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index c49094cb6881..6cabc25df6af 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -21,9 +21,8 @@ pub use self::fold::TypeFoldable; use dep_graph::{self, DepNode}; use hir::map as ast_map; use middle; -use middle::cstore::LOCAL_CRATE; use hir::def::{Def, PathResolution, ExportMap}; -use hir::def_id::DefId; +use hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem}; use middle::region::{CodeExtent, ROOT_CODE_EXTENT}; use traits; @@ -42,7 +41,7 @@ use std::iter; use std::rc::Rc; use std::slice; use std::vec::IntoIter; -use syntax::ast::{self, CrateNum, Name, NodeId}; +use syntax::ast::{self, Name, NodeId}; use syntax::attr; use syntax::parse::token::InternedString; use syntax_pos::{DUMMY_SP, Span}; @@ -425,7 +424,7 @@ pub enum Variance { Bivariant, // T <: T -- e.g., unused type parameter } -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy, Debug, RustcDecodable, RustcEncodable)] pub struct MethodCallee<'tcx> { /// Impl method ID, for inherent methods, or trait method ID, otherwise. pub def_id: DefId, @@ -627,7 +626,7 @@ pub enum BorrowKind { /// Information describing the capture of an upvar. This is computed /// during `typeck`, specifically by `regionck`. -#[derive(PartialEq, Clone, Debug, Copy)] +#[derive(PartialEq, Clone, Debug, Copy, RustcEncodable, RustcDecodable)] pub enum UpvarCapture<'tcx> { /// Upvar is captured by value. This is always true when the /// closure is labeled `move`, but can also be true in other cases @@ -638,7 +637,7 @@ pub enum UpvarCapture<'tcx> { ByRef(UpvarBorrow<'tcx>), } -#[derive(PartialEq, Clone, Copy)] +#[derive(PartialEq, Clone, Copy, RustcEncodable, RustcDecodable)] pub struct UpvarBorrow<'tcx> { /// The kind of borrow: by-ref upvars have access to shared /// immutable borrows, which are not part of the normal language @@ -1940,7 +1939,7 @@ impl<'a, 'gcx, 'tcx, 'container> FieldDefData<'tcx, 'container> { /// Records the substitutions used to translate the polytype for an /// item into the monotype of an item reference. -#[derive(Clone)] +#[derive(Clone, RustcEncodable, RustcDecodable)] pub struct ItemSubsts<'tcx> { pub substs: &'tcx Substs<'tcx>, } diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index d34fdaa7d71c..2090877fb3c9 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -240,7 +240,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn enum_repr_type(self, opt_hint: Option<&attr::ReprAttr>) -> attr::IntType { match opt_hint { // Feed in the given type - Some(&attr::ReprInt(_, int_t)) => int_t, + Some(&attr::ReprInt(int_t)) => int_t, // ... but provide sensible default if none provided // // NB. Historically `fn enum_variants` generate i64 here, while diff --git a/src/librustc_back/lib.rs b/src/librustc_back/lib.rs index 6a7bc51d15a4..f7ae47d2e5e5 100644 --- a/src/librustc_back/lib.rs +++ b/src/librustc_back/lib.rs @@ -46,7 +46,6 @@ extern crate serialize; #[macro_use] extern crate log; pub mod tempdir; -pub mod rpath; pub mod sha2; pub mod target; pub mod slice; diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs index a1e7d0a1e34d..5d2b266ec4b7 100644 --- a/src/librustc_const_eval/check_match.rs +++ b/src/librustc_const_eval/check_match.rs @@ -460,7 +460,7 @@ fn const_val_to_expr(value: &ConstVal) -> P { _ => bug!() }; P(hir::Expr { - id: 0, + id: DUMMY_NODE_ID, node: hir::ExprLit(P(Spanned { node: node, span: DUMMY_SP })), span: DUMMY_SP, attrs: ast::ThinVec::new(), @@ -625,7 +625,7 @@ fn construct_witness<'a,'tcx>(cx: &MatchCheckCtxt<'a,'tcx>, ctor: &Constructor, }; P(hir::Pat { - id: 0, + id: DUMMY_NODE_ID, node: pat, span: DUMMY_SP }) diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index 1ffeaf322bf5..215287f84399 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -539,6 +539,7 @@ impl FromStr for UserIdentifiedItem { type Err = (); fn from_str(s: &str) -> Result { Ok(s.parse() + .map(ast::NodeId::new) .map(ItemViaNode) .unwrap_or_else(|_| ItemViaPath(s.split("::").map(|s| s.to_string()).collect()))) } diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index 8569ff64f910..f6772b877184 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -166,16 +166,17 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> { pub fn create_simple_region_hierarchy(&self) { // creates a region hierarchy where 1 is root, 10 and 11 are // children of 1, etc + + let node = ast::NodeId::from_u32; let dscope = self.infcx .tcx .region_maps - .intern_code_extent(CodeExtentData::DestructionScope(1), + .intern_code_extent(CodeExtentData::DestructionScope(node(1)), region::ROOT_CODE_EXTENT); self.create_region_hierarchy(&RH { - id: 1, - sub: &[RH { id: 10, sub: &[] }, RH { id: 11, sub: &[] }], - }, - dscope); + id: node(1), + sub: &[RH { id: node(10), sub: &[] }, RH { id: node(11), sub: &[] }], + }, dscope); } #[allow(dead_code)] // this seems like it could be useful, even if we don't use it now @@ -315,8 +316,8 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> { self.infcx.tcx.mk_imm_ref(r, self.tcx().types.isize) } - pub fn t_rptr_scope(&self, id: ast::NodeId) -> Ty<'tcx> { - let r = ty::ReScope(self.tcx().region_maps.node_extent(id)); + pub fn t_rptr_scope(&self, id: u32) -> Ty<'tcx> { + let r = ty::ReScope(self.tcx().region_maps.node_extent(ast::NodeId::from_u32(id))); self.infcx.tcx.mk_imm_ref(self.infcx.tcx.mk_region(r), self.tcx().types.isize) } @@ -327,8 +328,8 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> { })) } - pub fn t_rptr_free(&self, nid: ast::NodeId, id: u32) -> Ty<'tcx> { - let r = self.re_free(nid, id); + pub fn t_rptr_free(&self, nid: u32, id: u32) -> Ty<'tcx> { + let r = self.re_free(ast::NodeId::from_u32(nid), id); self.infcx.tcx.mk_imm_ref(r, self.tcx().types.isize) } diff --git a/src/librustc_incremental/persist/directory.rs b/src/librustc_incremental/persist/directory.rs index 89a79d1a487e..cca364f442d5 100644 --- a/src/librustc_incremental/persist/directory.rs +++ b/src/librustc_incremental/persist/directory.rs @@ -15,13 +15,11 @@ use rustc::dep_graph::DepNode; use rustc::hir::map::DefPath; -use rustc::hir::def_id::DefId; -use rustc::middle::cstore::LOCAL_CRATE; +use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc::ty::TyCtxt; use rustc::util::nodemap::DefIdMap; use std::fmt::{self, Debug}; use std::iter::once; -use syntax::ast; /// Index into the DefIdDirectory #[derive(Copy, Clone, Debug, PartialOrd, Ord, Hash, PartialEq, Eq, @@ -43,7 +41,7 @@ pub struct DefIdDirectory { #[derive(Debug, RustcEncodable, RustcDecodable)] pub struct CrateInfo { - krate: ast::CrateNum, + krate: CrateNum, name: String, disambiguator: String, } @@ -53,7 +51,7 @@ impl DefIdDirectory { DefIdDirectory { paths: vec![], krates: krates } } - fn max_current_crate(&self, tcx: TyCtxt) -> ast::CrateNum { + fn max_current_crate(&self, tcx: TyCtxt) -> CrateNum { tcx.sess.cstore.crates() .into_iter() .max() @@ -72,8 +70,8 @@ impl DefIdDirectory { pub fn krate_still_valid(&self, tcx: TyCtxt, - max_current_crate: ast::CrateNum, - krate: ast::CrateNum) -> bool { + max_current_crate: CrateNum, + krate: CrateNum) -> bool { // Check that the crate-number still matches. For now, if it // doesn't, just return None. We could do better, such as // finding the new number. @@ -81,7 +79,7 @@ impl DefIdDirectory { if krate > max_current_crate { false } else { - let old_info = &self.krates[krate as usize]; + let old_info = &self.krates[krate.as_usize()]; assert_eq!(old_info.krate, krate); let old_name: &str = &old_info.name; let old_disambiguator: &str = &old_info.disambiguator; @@ -101,7 +99,7 @@ impl DefIdDirectory { } else { debug!("crate {} changed from {:?} to {:?}/{:?}", path.krate, - self.krates[path.krate as usize], + self.krates[path.krate.as_usize()], tcx.crate_name(path.krate), tcx.crate_disambiguator(path.krate)); None diff --git a/src/librustc_incremental/persist/fs.rs b/src/librustc_incremental/persist/fs.rs index 8166045be5f6..c9cfaf4f6613 100644 --- a/src/librustc_incremental/persist/fs.rs +++ b/src/librustc_incremental/persist/fs.rs @@ -114,8 +114,8 @@ //! unsupported file system and emit a warning in that case. This is not yet //! implemented. +use rustc::hir::def_id::{CrateNum, LOCAL_CRATE}; use rustc::hir::svh::Svh; -use rustc::middle::cstore::LOCAL_CRATE; use rustc::session::Session; use rustc::ty::TyCtxt; use rustc::util::fs as fs_util; @@ -129,7 +129,6 @@ use std::mem; use std::path::{Path, PathBuf}; use std::time::{UNIX_EPOCH, SystemTime, Duration}; use std::__rand::{thread_rng, Rng}; -use syntax::ast; const LOCK_FILE_EXT: &'static str = ".lock"; const DEP_GRAPH_FILENAME: &'static str = "dep-graph.bin"; @@ -580,7 +579,7 @@ fn string_to_timestamp(s: &str) -> Result { Ok(UNIX_EPOCH + duration) } -fn crate_path_tcx(tcx: TyCtxt, cnum: ast::CrateNum) -> PathBuf { +fn crate_path_tcx(tcx: TyCtxt, cnum: CrateNum) -> PathBuf { crate_path(tcx.sess, &tcx.crate_name(cnum), &tcx.crate_disambiguator(cnum)) } @@ -592,7 +591,7 @@ fn crate_path_tcx(tcx: TyCtxt, cnum: ast::CrateNum) -> PathBuf { /// crate's (name, disambiguator) pair. The metadata hashes are only valid for /// the exact version of the binary we are reading from now (i.e. the hashes /// are part of the dependency graph of a specific compilation session). -pub fn find_metadata_hashes_for(tcx: TyCtxt, cnum: ast::CrateNum) -> Option { +pub fn find_metadata_hashes_for(tcx: TyCtxt, cnum: CrateNum) -> Option { let crate_directory = crate_path_tcx(tcx, cnum); if !crate_directory.exists() { diff --git a/src/librustc_incremental/persist/hash.rs b/src/librustc_incremental/persist/hash.rs index bafaafd4afa0..6dcf2c288914 100644 --- a/src/librustc_incremental/persist/hash.rs +++ b/src/librustc_incremental/persist/hash.rs @@ -11,7 +11,7 @@ use rbml::Error; use rbml::opaque::Decoder; use rustc::dep_graph::DepNode; -use rustc::hir::def_id::DefId; +use rustc::hir::def_id::{CrateNum, DefId}; use rustc::hir::svh::Svh; use rustc::ty::TyCtxt; use rustc_data_structures::fnv::FnvHashMap; @@ -19,7 +19,6 @@ use rustc_data_structures::flock; use rustc_serialize::Decodable; use std::io::{ErrorKind, Read}; use std::fs::File; -use syntax::ast; use IncrementalHashesMap; use super::data::*; @@ -29,7 +28,7 @@ pub struct HashContext<'a, 'tcx: 'a> { pub tcx: TyCtxt<'a, 'tcx, 'tcx>, incremental_hashes_map: &'a IncrementalHashesMap, item_metadata_hashes: FnvHashMap, - crate_hashes: FnvHashMap, + crate_hashes: FnvHashMap, } impl<'a, 'tcx> HashContext<'a, 'tcx> { @@ -121,7 +120,7 @@ impl<'a, 'tcx> HashContext<'a, 'tcx> { } } - fn load_data(&mut self, cnum: ast::CrateNum) { + fn load_data(&mut self, cnum: CrateNum) { debug!("load_data(cnum={})", cnum); let svh = self.tcx.sess.cstore.crate_hash(cnum); @@ -187,7 +186,7 @@ impl<'a, 'tcx> HashContext<'a, 'tcx> { } fn load_from_data(&mut self, - cnum: ast::CrateNum, + cnum: CrateNum, data: &[u8], expected_svh: Svh) -> Result<(), Error> { debug!("load_from_data(cnum={})", cnum); diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index e8d9e90456ef..1209ced8dd3d 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -92,7 +92,7 @@ pub struct TypeLimits { impl TypeLimits { pub fn new() -> TypeLimits { TypeLimits { - negated_expr_id: !0, + negated_expr_id: ast::DUMMY_NODE_ID, } } } diff --git a/src/librustc_metadata/astencode.rs b/src/librustc_metadata/astencode.rs index 673a31c55abe..397b33178dce 100644 --- a/src/librustc_metadata/astencode.rs +++ b/src/librustc_metadata/astencode.rs @@ -9,98 +9,57 @@ // except according to those terms. #![allow(non_camel_case_types)] -// FIXME: remove this after snapshot, and Results are handled -#![allow(unused_must_use)] use rustc::hir::map as ast_map; -use rustc::hir; -use rustc::hir::fold; -use rustc::hir::fold::Folder; use rustc::hir::intravisit::{Visitor, IdRangeComputingVisitor, IdRange}; use common as c; use cstore; -use decoder; use decoder::DecodeContext; use encoder::EncodeContext; use middle::cstore::{InlinedItem, InlinedItemRef}; use rustc::ty::adjustment; -use rustc::ty::cast; -use middle::const_qualif::ConstQualif; -use rustc::hir::def::{self, Def}; +use rustc::hir::def; use rustc::hir::def_id::DefId; -use rustc::ty::{self, Ty, TyCtxt}; +use rustc::ty::{self, TyCtxt}; use syntax::ast; -use syntax::ptr::P; -use syntax_pos; - -use std::io::SeekFrom; -use std::io::prelude::*; use rbml::reader; use rbml; -use rustc_serialize::{Decodable, Decoder, DecoderHelpers}; -use rustc_serialize::{Encodable, EncoderHelpers}; - -trait tr { - fn tr(&self, dcx: &DecodeContext) -> Self; -} +use rustc_serialize::{Decodable, Encodable}; // ______________________________________________________________________ // Top-level methods. pub fn encode_inlined_item(ecx: &mut EncodeContext, ii: InlinedItemRef) { - let id = match ii { - InlinedItemRef::Item(_, i) => i.id, - InlinedItemRef::TraitItem(_, ti) => ti.id, - InlinedItemRef::ImplItem(_, ii) => ii.id, - }; - debug!("> Encoding inlined item: {} ({:?})", - ecx.tcx.node_path_str(id), - ecx.writer.seek(SeekFrom::Current(0))); + ecx.tag(c::tag_ast, |ecx| { + ecx.tag(c::tag_id_range, |ecx| { + let mut visitor = IdRangeComputingVisitor::new(); + match ii { + InlinedItemRef::Item(_, i) => visitor.visit_item(i), + InlinedItemRef::TraitItem(_, ti) => visitor.visit_trait_item(ti), + InlinedItemRef::ImplItem(_, ii) => visitor.visit_impl_item(ii) + } + visitor.result().encode(&mut ecx.opaque()).unwrap() + }); - // Folding could be avoided with a smarter encoder. - let (ii, expected_id_range) = simplify_ast(ii); - let id_range = inlined_item_id_range(&ii); - assert_eq!(expected_id_range, id_range); + ecx.tag(c::tag_tree, |ecx| ii.encode(ecx).unwrap()); - ecx.start_tag(c::tag_ast); - - ecx.start_tag(c::tag_id_range); - id_range.encode(&mut ecx.opaque()); - ecx.end_tag(); - - ecx.start_tag(c::tag_tree); - ii.encode(ecx); - ecx.end_tag(); - - encode_side_tables_for_ii(ecx, &ii); - ecx.end_tag(); - - debug!("< Encoded inlined fn: {} ({:?})", - ecx.tcx.node_path_str(id), - ecx.writer.seek(SeekFrom::Current(0))); -} - -impl<'a, 'b, 'tcx> ast_map::FoldOps for &'a DecodeContext<'b, 'tcx> { - fn new_id(&self, id: ast::NodeId) -> ast::NodeId { - if id == ast::DUMMY_NODE_ID { - // Used by ast_map to map the NodeInlinedParent. - self.tcx.sess.next_node_id() - } else { - self.tr_id(id) - } - } - fn new_def_id(&self, def_id: DefId) -> DefId { - self.tr_def_id(def_id) - } - fn new_span(&self, span: syntax_pos::Span) -> syntax_pos::Span { - self.tr_span(span) - } + ecx.tag(c::tag_table, |ecx| { + let mut visitor = SideTableEncodingIdVisitor { + ecx: ecx + }; + match ii { + InlinedItemRef::Item(_, i) => visitor.visit_item(i), + InlinedItemRef::TraitItem(_, ti) => visitor.visit_trait_item(ti), + InlinedItemRef::ImplItem(_, ii) => visitor.visit_impl_item(ii) + } + }); + }); } /// Decodes an item from its AST in the cdata's metadata and adds it to the @@ -113,8 +72,13 @@ pub fn decode_inlined_item<'a, 'tcx>(cdata: &cstore::CrateMetadata, orig_did: DefId) -> &'tcx InlinedItem { debug!("> Decoding inlined fn: {:?}", tcx.item_path_str(orig_did)); - let id_range_doc = ast_doc.get(c::tag_id_range); - let from_id_range = IdRange::decode(&mut id_range_doc.opaque()).unwrap(); + let from_id_range = { + let decoder = &mut ast_doc.get(c::tag_id_range).opaque(); + IdRange { + min: ast::NodeId::from_u32(u32::decode(decoder).unwrap()), + max: ast::NodeId::from_u32(u32::decode(decoder).unwrap()) + } + }; let mut dcx = DecodeContext::new(tcx, cdata, from_id_range, ast_doc.get(c::tag_tree)); let ii = InlinedItem::decode(&mut dcx).unwrap(); @@ -123,7 +87,7 @@ pub fn decode_inlined_item<'a, 'tcx>(cdata: &cstore::CrateMetadata, parent_def_path, parent_did, ii, - &dcx); + tcx.sess.next_node_id()); let item_node_id = match ii { &InlinedItem::Item(_, ref i) => i.id, @@ -138,376 +102,18 @@ pub fn decode_inlined_item<'a, 'tcx>(cdata: &cstore::CrateMetadata, ii } -// ______________________________________________________________________ -// Enumerating the IDs which appear in an AST - -impl<'a, 'tcx> DecodeContext<'a, 'tcx> { - /// Translates an internal id, meaning a node id that is known to refer to some part of the - /// item currently being inlined, such as a local variable or argument. All naked node-ids - /// that appear in types have this property, since if something might refer to an external item - /// we would use a def-id to allow for the possibility that the item resides in another crate. - pub fn tr_id(&self, id: ast::NodeId) -> ast::NodeId { - // from_id_range should be non-empty - assert!(!self.from_id_range.empty()); - // Make sure that translating the NodeId will actually yield a - // meaningful result - assert!(self.from_id_range.contains(id)); - - // Use wrapping arithmetic because otherwise it introduces control flow. - // Maybe we should just have the control flow? -- aatch - (id.wrapping_sub(self.from_id_range.min).wrapping_add(self.to_id_range.min)) - } - - /// Translates an EXTERNAL def-id, converting the crate number from the one used in the encoded - /// data to the current crate numbers.. By external, I mean that it be translated to a - /// reference to the item in its original crate, as opposed to being translated to a reference - /// to the inlined version of the item. This is typically, but not always, what you want, - /// because most def-ids refer to external things like types or other fns that may or may not - /// be inlined. Note that even when the inlined function is referencing itself recursively, we - /// would want `tr_def_id` for that reference--- conceptually the function calls the original, - /// non-inlined version, and trans deals with linking that recursive call to the inlined copy. - pub fn tr_def_id(&self, did: DefId) -> DefId { - decoder::translate_def_id(self.cdata, did) - } - - /// Translates a `Span` from an extern crate to the corresponding `Span` - /// within the local crate's codemap. - pub fn tr_span(&self, span: syntax_pos::Span) -> syntax_pos::Span { - decoder::translate_span(self.cdata, - self.tcx.sess.codemap(), - &self.last_filemap_index, - span) - } -} - -impl tr for DefId { - fn tr(&self, dcx: &DecodeContext) -> DefId { - dcx.tr_def_id(*self) - } -} - -impl tr for Option { - fn tr(&self, dcx: &DecodeContext) -> Option { - self.map(|d| dcx.tr_def_id(d)) - } -} - -impl tr for syntax_pos::Span { - fn tr(&self, dcx: &DecodeContext) -> syntax_pos::Span { - dcx.tr_span(*self) - } -} - -// ______________________________________________________________________ -// Encoding and decoding the AST itself -// -// When decoding, we have to renumber the AST so that the node ids that -// appear within are disjoint from the node ids in our existing ASTs. -// We also have to adjust the spans: for now we just insert a dummy span, -// but eventually we should add entries to the local codemap as required. - -struct NestedItemsDropper { - id_range: IdRange -} - -impl Folder for NestedItemsDropper { - - // The unit tests below run on HIR with NodeIds not properly assigned. That - // causes an integer overflow. So we just don't track the id_range when - // building the unit tests. - #[cfg(not(test))] - fn new_id(&mut self, id: ast::NodeId) -> ast::NodeId { - // Record the range of NodeIds we are visiting, so we can do a sanity - // check later - self.id_range.add(id); - id - } - - fn fold_block(&mut self, blk: P) -> P { - blk.and_then(|hir::Block {id, stmts, expr, rules, span, ..}| { - let stmts_sans_items = stmts.into_iter().filter_map(|stmt| { - let use_stmt = match stmt.node { - hir::StmtExpr(..) | hir::StmtSemi(..) => true, - hir::StmtDecl(ref decl, _) => { - match decl.node { - hir::DeclLocal(_) => true, - hir::DeclItem(_) => false, - } - } - }; - if use_stmt { - Some(stmt) - } else { - None - } - }).collect(); - let blk_sans_items = P(hir::Block { - stmts: stmts_sans_items, - expr: expr, - id: id, - rules: rules, - span: span, - }); - fold::noop_fold_block(blk_sans_items, self) - }) - } -} - -// Produces a simplified copy of the AST which does not include things -// that we do not need to or do not want to export. For example, we -// do not include any nested items: if these nested items are to be -// inlined, their AST will be exported separately (this only makes -// sense because, in Rust, nested items are independent except for -// their visibility). -// -// As it happens, trans relies on the fact that we do not export -// nested items, as otherwise it would get confused when translating -// inlined items. -fn simplify_ast(ii: InlinedItemRef) -> (InlinedItem, IdRange) { - let mut fld = NestedItemsDropper { - id_range: IdRange::max() - }; - - let ii = match ii { - // HACK we're not dropping items. - InlinedItemRef::Item(d, i) => { - InlinedItem::Item(d, P(fold::noop_fold_item(i.clone(), &mut fld))) - } - InlinedItemRef::TraitItem(d, ti) => { - InlinedItem::TraitItem(d, P(fold::noop_fold_trait_item(ti.clone(), &mut fld))) - } - InlinedItemRef::ImplItem(d, ii) => { - InlinedItem::ImplItem(d, P(fold::noop_fold_impl_item(ii.clone(), &mut fld))) - } - }; - - (ii, fld.id_range) -} - -// ______________________________________________________________________ -// Encoding and decoding of ast::def - -impl tr for Def { - fn tr(&self, dcx: &DecodeContext) -> Def { - match *self { - Def::Fn(did) => Def::Fn(did.tr(dcx)), - Def::Method(did) => Def::Method(did.tr(dcx)), - Def::SelfTy(opt_did, impl_id) => { - // Since the impl_id will never lie within the reserved range of - // imported NodeIds, it does not make sense to translate it. - // The result would not make any sense within the importing crate. - // We also don't allow for impl items to be inlined (just their - // members), so even if we had a DefId here, we wouldn't be able - // to do much with it. - // So, we set the id to DUMMY_NODE_ID. That way we make it - // explicit that this is no usable NodeId. - Def::SelfTy(opt_did.map(|did| did.tr(dcx)), - impl_id.map(|_| ast::DUMMY_NODE_ID)) - } - Def::Mod(did) => { Def::Mod(did.tr(dcx)) } - Def::ForeignMod(did) => { Def::ForeignMod(did.tr(dcx)) } - Def::Static(did, m) => { Def::Static(did.tr(dcx), m) } - Def::Const(did) => { Def::Const(did.tr(dcx)) } - Def::AssociatedConst(did) => Def::AssociatedConst(did.tr(dcx)), - Def::Local(_, nid) => { - let nid = dcx.tr_id(nid); - let did = dcx.tcx.map.local_def_id(nid); - Def::Local(did, nid) - } - Def::Variant(e_did, v_did) => Def::Variant(e_did.tr(dcx), v_did.tr(dcx)), - Def::Trait(did) => Def::Trait(did.tr(dcx)), - Def::Enum(did) => Def::Enum(did.tr(dcx)), - Def::TyAlias(did) => Def::TyAlias(did.tr(dcx)), - Def::AssociatedTy(trait_did, did) => - Def::AssociatedTy(trait_did.tr(dcx), did.tr(dcx)), - Def::PrimTy(p) => Def::PrimTy(p), - Def::TyParam(did) => Def::TyParam(did.tr(dcx)), - Def::Upvar(_, nid1, index, nid2) => { - let nid1 = dcx.tr_id(nid1); - let nid2 = dcx.tr_id(nid2); - let did1 = dcx.tcx.map.local_def_id(nid1); - Def::Upvar(did1, nid1, index, nid2) - } - Def::Struct(did) => Def::Struct(did.tr(dcx)), - Def::Union(did) => Def::Union(did.tr(dcx)), - Def::Label(nid) => Def::Label(dcx.tr_id(nid)), - Def::Err => Def::Err, - } - } -} - -// ______________________________________________________________________ -// Encoding and decoding of freevar information - -impl<'a, 'tcx> DecodeContext<'a, 'tcx> { - fn read_freevar_entry(&mut self) -> hir::Freevar { - hir::Freevar::decode(self).unwrap().tr(self) - } -} - -impl tr for hir::Freevar { - fn tr(&self, dcx: &DecodeContext) -> hir::Freevar { - hir::Freevar { - def: self.def.tr(dcx), - span: self.span.tr(dcx), - } - } -} - -// ______________________________________________________________________ -// Encoding and decoding of MethodCallee - -impl<'a, 'tcx> EncodeContext<'a, 'tcx> { - fn encode_method_callee(&mut self, - autoderef: u32, - method: &ty::MethodCallee<'tcx>) { - use rustc_serialize::Encoder; - - self.emit_struct("MethodCallee", 4, |this| { - this.emit_struct_field("autoderef", 0, |this| { - autoderef.encode(this) - }); - this.emit_struct_field("def_id", 1, |this| { - method.def_id.encode(this) - }); - this.emit_struct_field("ty", 2, |this| { - method.ty.encode(this) - }); - this.emit_struct_field("substs", 3, |this| { - method.substs.encode(this) - }) - }).unwrap(); - } -} - -impl<'a, 'tcx> DecodeContext<'a, 'tcx> { - fn read_method_callee(&mut self) -> (u32, ty::MethodCallee<'tcx>) { - self.read_struct("MethodCallee", 4, |this| { - let autoderef = this.read_struct_field("autoderef", 0, - Decodable::decode).unwrap(); - Ok((autoderef, ty::MethodCallee { - def_id: this.read_struct_field("def_id", 1, |this| { - DefId::decode(this).map(|d| d.tr(this)) - }).unwrap(), - ty: this.read_struct_field("ty", 2, |this| { - Ty::decode(this) - }).unwrap(), - substs: this.read_struct_field("substs", 3, |this| { - Decodable::decode(this) - }).unwrap() - })) - }).unwrap() - } -} - // ______________________________________________________________________ // Encoding and decoding the side tables impl<'a, 'tcx> EncodeContext<'a, 'tcx> { - fn emit_upvar_capture(&mut self, capture: &ty::UpvarCapture<'tcx>) { - use rustc_serialize::Encoder; - - self.emit_enum("UpvarCapture", |this| { - match *capture { - ty::UpvarCapture::ByValue => { - this.emit_enum_variant("ByValue", 1, 0, |_| Ok(())) - } - ty::UpvarCapture::ByRef(ty::UpvarBorrow { kind, region }) => { - this.emit_enum_variant("ByRef", 2, 0, |this| { - this.emit_enum_variant_arg(0, |this| kind.encode(this)); - this.emit_enum_variant_arg(1, |this| region.encode(this)) - }) - } - } - }).unwrap() - } - - fn emit_auto_adjustment(&mut self, adj: &adjustment::AutoAdjustment<'tcx>) { - use rustc_serialize::Encoder; - - self.emit_enum("AutoAdjustment", |this| { - match *adj { - adjustment::AdjustReifyFnPointer => { - this.emit_enum_variant("AdjustReifyFnPointer", 1, 0, |_| Ok(())) - } - - adjustment::AdjustUnsafeFnPointer => { - this.emit_enum_variant("AdjustUnsafeFnPointer", 2, 0, |_| { - Ok(()) - }) - } - - adjustment::AdjustMutToConstPointer => { - this.emit_enum_variant("AdjustMutToConstPointer", 3, 0, |_| { - Ok(()) - }) - } - - adjustment::AdjustDerefRef(ref auto_deref_ref) => { - this.emit_enum_variant("AdjustDerefRef", 4, 2, |this| { - this.emit_enum_variant_arg(0, - |this| Ok(this.emit_auto_deref_ref(auto_deref_ref))) - }) - } - - adjustment::AdjustNeverToAny(ref ty) => { - this.emit_enum_variant("AdjustNeverToAny", 5, 1, |this| { - this.emit_enum_variant_arg(0, |this| ty.encode(this)) - }) - } - } - }); - } - - fn emit_autoref(&mut self, autoref: &adjustment::AutoRef<'tcx>) { - use rustc_serialize::Encoder; - - self.emit_enum("AutoRef", |this| { - match autoref { - &adjustment::AutoPtr(r, m) => { - this.emit_enum_variant("AutoPtr", 0, 2, |this| { - this.emit_enum_variant_arg(0, |this| r.encode(this)); - this.emit_enum_variant_arg(1, |this| m.encode(this)) - }) - } - &adjustment::AutoUnsafe(m) => { - this.emit_enum_variant("AutoUnsafe", 1, 1, |this| { - this.emit_enum_variant_arg(0, |this| m.encode(this)) - }) - } - } - }); - } - - fn emit_auto_deref_ref(&mut self, auto_deref_ref: &adjustment::AutoDerefRef<'tcx>) { - use rustc_serialize::Encoder; - - self.emit_struct("AutoDerefRef", 2, |this| { - this.emit_struct_field("autoderefs", 0, |this| auto_deref_ref.autoderefs.encode(this)); - - this.emit_struct_field("autoref", 1, |this| { - this.emit_option(|this| { - match auto_deref_ref.autoref { - None => this.emit_option_none(), - Some(ref a) => this.emit_option_some(|this| Ok(this.emit_autoref(a))), - } - }) - }); - - this.emit_struct_field("unsize", 2, |this| { - auto_deref_ref.unsize.encode(this) - }) - }); - } - fn tag(&mut self, tag_id: usize, f: F) where F: FnOnce(&mut Self), { - self.start_tag(tag_id); + self.start_tag(tag_id).unwrap(); f(self); - self.end_tag(); + self.end_tag().unwrap(); } fn id(&mut self, id: ast::NodeId) { @@ -525,14 +131,6 @@ impl<'a, 'b, 'tcx, 'v> Visitor<'v> for SideTableEncodingIdVisitor<'a, 'b, 'tcx> } } -fn encode_side_tables_for_ii(ecx: &mut EncodeContext, ii: &InlinedItem) { - ecx.start_tag(c::tag_table); - ii.visit(&mut SideTableEncodingIdVisitor { - ecx: ecx - }); - ecx.end_tag(); -} - fn encode_side_tables_for_id(ecx: &mut EncodeContext, id: ast::NodeId) { let tcx = ecx.tcx; @@ -548,23 +146,21 @@ fn encode_side_tables_for_id(ecx: &mut EncodeContext, id: ast::NodeId) { if let Some(ty) = tcx.node_types().get(&id) { ecx.tag(c::tag_table_node_type, |ecx| { ecx.id(id); - ty.encode(ecx); + ty.encode(ecx).unwrap(); }) } if let Some(item_substs) = tcx.tables.borrow().item_substs.get(&id) { ecx.tag(c::tag_table_item_subst, |ecx| { ecx.id(id); - item_substs.substs.encode(ecx); + item_substs.substs.encode(ecx).unwrap(); }) } if let Some(fv) = tcx.freevars.borrow().get(&id) { ecx.tag(c::tag_table_freevars, |ecx| { ecx.id(id); - ecx.emit_from_vec(fv, |ecx, fv_entry| { - fv_entry.encode(ecx) - }); + fv.encode(ecx).unwrap(); }); for freevar in fv { @@ -582,8 +178,8 @@ fn encode_side_tables_for_id(ecx: &mut EncodeContext, id: ast::NodeId) { .get(&upvar_id) .unwrap() .clone(); - var_id.encode(ecx); - ecx.emit_upvar_capture(&upvar_capture); + var_id.encode(ecx).unwrap(); + upvar_capture.encode(ecx).unwrap(); }) } } @@ -592,7 +188,8 @@ fn encode_side_tables_for_id(ecx: &mut EncodeContext, id: ast::NodeId) { if let Some(method) = tcx.tables.borrow().method_map.get(&method_call) { ecx.tag(c::tag_table_method_map, |ecx| { ecx.id(id); - ecx.encode_method_callee(method_call.autoderef, method) + method_call.autoderef.encode(ecx).unwrap(); + method.encode(ecx).unwrap(); }) } @@ -604,7 +201,8 @@ fn encode_side_tables_for_id(ecx: &mut EncodeContext, id: ast::NodeId) { if let Some(method) = tcx.tables.borrow().method_map.get(&method_call) { ecx.tag(c::tag_table_method_map, |ecx| { ecx.id(id); - ecx.encode_method_callee(method_call.autoderef, method) + method_call.autoderef.encode(ecx).unwrap(); + method.encode(ecx).unwrap(); }) } } @@ -614,7 +212,7 @@ fn encode_side_tables_for_id(ecx: &mut EncodeContext, id: ast::NodeId) { ecx.tag(c::tag_table_adjustments, |ecx| { ecx.id(id); - ecx.emit_auto_adjustment(adjustment); + adjustment.encode(ecx).unwrap(); }) } @@ -633,180 +231,60 @@ fn encode_side_tables_for_id(ecx: &mut EncodeContext, id: ast::NodeId) { } } -impl<'a, 'tcx> DecodeContext<'a, 'tcx> { - fn read_upvar_capture(&mut self) -> ty::UpvarCapture<'tcx> { - self.read_enum("UpvarCapture", |this| { - let variants = ["ByValue", "ByRef"]; - this.read_enum_variant(&variants, |this, i| { - Ok(match i { - 1 => ty::UpvarCapture::ByValue, - 2 => ty::UpvarCapture::ByRef(ty::UpvarBorrow { - kind: this.read_enum_variant_arg(0, - |this| Decodable::decode(this)).unwrap(), - region: this.read_enum_variant_arg(1, - |this| Decodable::decode(this)).unwrap() - }), - _ => bug!("bad enum variant for ty::UpvarCapture") - }) - }) - }).unwrap() - } - fn read_auto_adjustment(&mut self) -> adjustment::AutoAdjustment<'tcx> { - self.read_enum("AutoAdjustment", |this| { - let variants = ["AdjustReifyFnPointer", "AdjustUnsafeFnPointer", - "AdjustMutToConstPointer", "AdjustDerefRef", - "AdjustNeverToAny"]; - this.read_enum_variant(&variants, |this, i| { - Ok(match i { - 1 => adjustment::AdjustReifyFnPointer, - 2 => adjustment::AdjustUnsafeFnPointer, - 3 => adjustment::AdjustMutToConstPointer, - 4 => { - let auto_deref_ref: adjustment::AutoDerefRef = - this.read_enum_variant_arg(0, - |this| Ok(this.read_auto_deref_ref())).unwrap(); - - adjustment::AdjustDerefRef(auto_deref_ref) - } - 5 => { - let ty: Ty<'tcx> = this.read_enum_variant_arg(0, |this| { - Ty::decode(this) - }).unwrap(); - - adjustment::AdjustNeverToAny(ty) - } - _ => bug!("bad enum variant for adjustment::AutoAdjustment") - }) - }) - }).unwrap() - } - - fn read_auto_deref_ref(&mut self) -> adjustment::AutoDerefRef<'tcx> { - self.read_struct("AutoDerefRef", 2, |this| { - Ok(adjustment::AutoDerefRef { - autoderefs: this.read_struct_field("autoderefs", 0, |this| { - Decodable::decode(this) - }).unwrap(), - autoref: this.read_struct_field("autoref", 1, |this| { - this.read_option(|this, b| { - if b { - Ok(Some(this.read_autoref())) - } else { - Ok(None) - } - }) - }).unwrap(), - unsize: this.read_struct_field("unsize", 2, |this| { - Decodable::decode(this) - }).unwrap(), - }) - }).unwrap() - } - - fn read_autoref(&mut self) -> adjustment::AutoRef<'tcx> { - self.read_enum("AutoRef", |this| { - let variants = ["AutoPtr", "AutoUnsafe"]; - this.read_enum_variant(&variants, |this, i| { - Ok(match i { - 0 => { - let r: &'tcx ty::Region = - this.read_enum_variant_arg(0, |this| { - Decodable::decode(this) - }).unwrap(); - let m: hir::Mutability = - this.read_enum_variant_arg(1, |this| { - Decodable::decode(this) - }).unwrap(); - - adjustment::AutoPtr(r, m) - } - 1 => { - let m: hir::Mutability = - this.read_enum_variant_arg(0, |this| Decodable::decode(this)).unwrap(); - - adjustment::AutoUnsafe(m) - } - _ => bug!("bad enum variant for adjustment::AutoRef") - }) - }) - }).unwrap() - } -} - fn decode_side_tables<'a, 'tcx>(dcx: &mut DecodeContext<'a, 'tcx>, ast_doc: rbml::Doc<'a>) { for (tag, entry_doc) in reader::docs(ast_doc.get(c::tag_table)) { dcx.rbml_r = reader::Decoder::new(entry_doc); - - let id0: ast::NodeId = Decodable::decode(dcx).unwrap(); - let id = dcx.tr_id(id0); - - debug!(">> Side table document with tag 0x{:x} \ - found for id {} (orig {})", - tag, id, id0); - + let id = Decodable::decode(dcx).unwrap(); + debug!("decode_side_tables: entry for id={}, tag=0x{:x}", id, tag); match tag { c::tag_table_def => { - let def = Def::decode(dcx).unwrap().tr(dcx); + let def = Decodable::decode(dcx).unwrap(); dcx.tcx.def_map.borrow_mut().insert(id, def::PathResolution::new(def)); } c::tag_table_node_type => { - let ty = Ty::decode(dcx).unwrap(); + let ty = Decodable::decode(dcx).unwrap(); dcx.tcx.node_type_insert(id, ty); } c::tag_table_item_subst => { - let item_substs = ty::ItemSubsts { - substs: Decodable::decode(dcx).unwrap() - }; - dcx.tcx.tables.borrow_mut().item_substs.insert( - id, item_substs); + let item_substs = Decodable::decode(dcx).unwrap(); + dcx.tcx.tables.borrow_mut().item_substs.insert(id, item_substs); } c::tag_table_freevars => { - let fv_info = dcx.read_to_vec(|dcx| { - Ok(dcx.read_freevar_entry()) - }).unwrap().into_iter().collect(); + let fv_info = Decodable::decode(dcx).unwrap(); dcx.tcx.freevars.borrow_mut().insert(id, fv_info); } c::tag_table_upvar_capture_map => { - let var_id = ast::NodeId::decode(dcx).unwrap(); let upvar_id = ty::UpvarId { - var_id: dcx.tr_id(var_id), + var_id: Decodable::decode(dcx).unwrap(), closure_expr_id: id }; - let ub = dcx.read_upvar_capture(); + let ub = Decodable::decode(dcx).unwrap(); dcx.tcx.tables.borrow_mut().upvar_capture_map.insert(upvar_id, ub); } c::tag_table_method_map => { - let (autoderef, method) = dcx.read_method_callee(); let method_call = ty::MethodCall { expr_id: id, - autoderef: autoderef + autoderef: Decodable::decode(dcx).unwrap() }; + let method = Decodable::decode(dcx).unwrap(); dcx.tcx.tables.borrow_mut().method_map.insert(method_call, method); } c::tag_table_adjustments => { - let adj = dcx.read_auto_adjustment(); + let adj = Decodable::decode(dcx).unwrap(); dcx.tcx.tables.borrow_mut().adjustments.insert(id, adj); } c::tag_table_cast_kinds => { - let cast_kind = cast::CastKind::decode(dcx).unwrap(); + let cast_kind = Decodable::decode(dcx).unwrap(); dcx.tcx.cast_kinds.borrow_mut().insert(id, cast_kind); } c::tag_table_const_qualif => { - let qualif = ConstQualif::decode(dcx).unwrap(); + let qualif = Decodable::decode(dcx).unwrap(); dcx.tcx.const_qualif_map.borrow_mut().insert(id, qualif); } _ => { - bug!("unknown tag found in side tables: {:x}", tag); + bug!("unknown tag found in side tables: 0x{:x}", tag); } } - - debug!(">< Side table doc loaded"); } } - -fn inlined_item_id_range(ii: &InlinedItem) -> IdRange { - let mut visitor = IdRangeComputingVisitor::new(); - ii.visit(&mut visitor); - visitor.result() -} diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index a1ade43f6475..2774ffdf6c77 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -16,7 +16,7 @@ use cstore::{self, CStore, CrateSource, MetadataBlob}; use decoder; use loader::{self, CratePaths}; -use rustc::hir::def_id::DefIndex; +use rustc::hir::def_id::{CrateNum, DefIndex}; use rustc::hir::svh::Svh; use rustc::dep_graph::{DepGraph, DepNode}; use rustc::session::{config, Session}; @@ -52,7 +52,7 @@ struct LocalCrateReader<'a> { pub struct CrateReader<'a> { sess: &'a Session, cstore: &'a CStore, - next_crate_num: ast::CrateNum, + next_crate_num: CrateNum, foreign_item_map: FnvHashMap>, local_crate_name: String, local_crate_config: ast::CrateConfig, @@ -152,7 +152,7 @@ impl PMDSource { } enum LoadResult { - Previous(ast::CrateNum), + Previous(CrateNum), Loaded(loader::Library), } @@ -208,7 +208,7 @@ impl<'a> CrateReader<'a> { } fn existing_match(&self, name: &str, hash: Option<&Svh>, kind: PathKind) - -> Option { + -> Option { let mut ret = None; self.cstore.iter_crate_data(|cnum, data| { if data.name != name { return } @@ -295,14 +295,14 @@ impl<'a> CrateReader<'a> { span: Span, lib: loader::Library, explicitly_linked: bool) - -> (ast::CrateNum, Rc, + -> (CrateNum, Rc, cstore::CrateSource) { info!("register crate `extern crate {} as {}`", name, ident); self.verify_no_symbol_conflicts(span, &lib.metadata); // Claim this crate number and cache it let cnum = self.next_crate_num; - self.next_crate_num += 1; + self.next_crate_num = CrateNum::from_u32(cnum.as_u32() + 1); // Stash paths for top-most crate locally if necessary. let crate_paths = if root.is_none() { @@ -370,7 +370,7 @@ impl<'a> CrateReader<'a> { span: Span, kind: PathKind, explicitly_linked: bool) - -> (ast::CrateNum, Rc, cstore::CrateSource) { + -> (CrateNum, Rc, cstore::CrateSource) { info!("resolving crate `extern crate {} as {}`", name, ident); let result = match self.existing_match(name, hash, kind) { Some(cnum) => LoadResult::Previous(cnum), @@ -447,9 +447,9 @@ impl<'a> CrateReader<'a> { } fn update_extern_crate(&mut self, - cnum: ast::CrateNum, + cnum: CrateNum, mut extern_crate: ExternCrate, - visited: &mut FnvHashSet<(ast::CrateNum, bool)>) + visited: &mut FnvHashSet<(CrateNum, bool)>) { if !visited.insert((cnum, extern_crate.direct)) { return } @@ -482,7 +482,7 @@ impl<'a> CrateReader<'a> { fn resolve_crate_deps(&mut self, root: &Option, cdata: &[u8], - krate: ast::CrateNum, + krate: CrateNum, span: Span) -> cstore::CrateNumMap { debug!("resolving deps of external crate"); @@ -500,11 +500,13 @@ impl<'a> CrateReader<'a> { (dep.cnum, local_cnum) }).collect(); - let max_cnum = map.values().cloned().max().unwrap_or(0); + let max_cnum = map.values().cloned().max().map(|cnum| cnum.as_u32()).unwrap_or(0); // we map 0 and all other holes in the map to our parent crate. The "additional" // self-dependencies should be harmless. - (0..max_cnum+1).map(|cnum| map.get(&cnum).cloned().unwrap_or(krate)).collect() + (0..max_cnum+1).map(|cnum| { + map.get(&CrateNum::from_u32(cnum)).cloned().unwrap_or(krate) + }).collect() } fn read_extension_crate(&mut self, span: Span, info: &CrateInfo) -> ExtensionCrate { @@ -875,7 +877,7 @@ impl<'a> CrateReader<'a> { } fn inject_dependency_if(&self, - krate: ast::CrateNum, + krate: CrateNum, what: &str, needs_dep: &Fn(&cstore::CrateMetadata) -> bool) { // don't perform this validation if the session has errors, as one of @@ -1113,7 +1115,7 @@ pub fn read_local_crates(sess: & Session, /// function. When an item from an external crate is later inlined into this /// crate, this correspondence information is used to translate the span /// information of the inlined item so that it refers the correct positions in -/// the local codemap (see `astencode::DecodeContext::tr_span()`). +/// the local codemap (see `>`). /// /// The import algorithm in the function below will reuse FileMaps already /// existing in the local codemap. For example, even if the FileMap of some diff --git a/src/librustc_metadata/csearch.rs b/src/librustc_metadata/csearch.rs index c37b2de751f9..a30a5743c34f 100644 --- a/src/librustc_metadata/csearch.rs +++ b/src/librustc_metadata/csearch.rs @@ -20,7 +20,7 @@ use middle::cstore::{NativeLibraryKind, LinkMeta, LinkagePreference}; use rustc::hir::def; use middle::lang_items; use rustc::ty::{self, Ty, TyCtxt, VariantKind}; -use rustc::hir::def_id::{DefId, DefIndex, CRATE_DEF_INDEX}; +use rustc::hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX}; use rustc::dep_graph::DepNode; use rustc::hir::map as hir_map; @@ -303,14 +303,14 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { decoder::is_typedef(&cdata, did.index) } - fn dylib_dependency_formats(&self, cnum: ast::CrateNum) - -> Vec<(ast::CrateNum, LinkagePreference)> + fn dylib_dependency_formats(&self, cnum: CrateNum) + -> Vec<(CrateNum, LinkagePreference)> { let cdata = self.get_crate_data(cnum); decoder::get_dylib_dependency_formats(&cdata) } - fn lang_items(&self, cnum: ast::CrateNum) -> Vec<(DefIndex, usize)> + fn lang_items(&self, cnum: CrateNum) -> Vec<(DefIndex, usize)> { let mut result = vec![]; let crate_data = self.get_crate_data(cnum); @@ -320,80 +320,80 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { result } - fn missing_lang_items(&self, cnum: ast::CrateNum) + fn missing_lang_items(&self, cnum: CrateNum) -> Vec { let cdata = self.get_crate_data(cnum); decoder::get_missing_lang_items(&cdata) } - fn is_staged_api(&self, cnum: ast::CrateNum) -> bool + fn is_staged_api(&self, cnum: CrateNum) -> bool { self.get_crate_data(cnum).staged_api } - fn is_explicitly_linked(&self, cnum: ast::CrateNum) -> bool + fn is_explicitly_linked(&self, cnum: CrateNum) -> bool { self.get_crate_data(cnum).explicitly_linked.get() } - fn is_allocator(&self, cnum: ast::CrateNum) -> bool + fn is_allocator(&self, cnum: CrateNum) -> bool { self.get_crate_data(cnum).is_allocator() } - fn is_panic_runtime(&self, cnum: ast::CrateNum) -> bool + fn is_panic_runtime(&self, cnum: CrateNum) -> bool { self.get_crate_data(cnum).is_panic_runtime() } - fn is_compiler_builtins(&self, cnum: ast::CrateNum) -> bool { + fn is_compiler_builtins(&self, cnum: CrateNum) -> bool { self.get_crate_data(cnum).is_compiler_builtins() } - fn panic_strategy(&self, cnum: ast::CrateNum) -> PanicStrategy { + fn panic_strategy(&self, cnum: CrateNum) -> PanicStrategy { self.get_crate_data(cnum).panic_strategy() } - fn crate_attrs(&self, cnum: ast::CrateNum) -> Vec + fn crate_attrs(&self, cnum: CrateNum) -> Vec { decoder::get_crate_attributes(self.get_crate_data(cnum).data()) } - fn crate_name(&self, cnum: ast::CrateNum) -> token::InternedString + fn crate_name(&self, cnum: CrateNum) -> token::InternedString { token::intern_and_get_ident(&self.get_crate_data(cnum).name[..]) } - fn original_crate_name(&self, cnum: ast::CrateNum) -> token::InternedString + fn original_crate_name(&self, cnum: CrateNum) -> token::InternedString { token::intern_and_get_ident(&self.get_crate_data(cnum).name()) } - fn extern_crate(&self, cnum: ast::CrateNum) -> Option + fn extern_crate(&self, cnum: CrateNum) -> Option { self.get_crate_data(cnum).extern_crate.get() } - fn crate_hash(&self, cnum: ast::CrateNum) -> Svh + fn crate_hash(&self, cnum: CrateNum) -> Svh { let cdata = self.get_crate_data(cnum); decoder::get_crate_hash(cdata.data()) } - fn crate_disambiguator(&self, cnum: ast::CrateNum) -> token::InternedString + fn crate_disambiguator(&self, cnum: CrateNum) -> token::InternedString { let cdata = self.get_crate_data(cnum); token::intern_and_get_ident(decoder::get_crate_disambiguator(cdata.data())) } - fn crate_struct_field_attrs(&self, cnum: ast::CrateNum) + fn crate_struct_field_attrs(&self, cnum: CrateNum) -> FnvHashMap> { decoder::get_struct_field_attrs(&self.get_crate_data(cnum)) } - fn plugin_registrar_fn(&self, cnum: ast::CrateNum) -> Option + fn plugin_registrar_fn(&self, cnum: CrateNum) -> Option { let cdata = self.get_crate_data(cnum); decoder::get_plugin_registrar_fn(cdata.data()).map(|index| DefId { @@ -402,24 +402,24 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { }) } - fn native_libraries(&self, cnum: ast::CrateNum) -> Vec<(NativeLibraryKind, String)> + fn native_libraries(&self, cnum: CrateNum) -> Vec<(NativeLibraryKind, String)> { let cdata = self.get_crate_data(cnum); decoder::get_native_libraries(&cdata) } - fn reachable_ids(&self, cnum: ast::CrateNum) -> Vec + fn reachable_ids(&self, cnum: CrateNum) -> Vec { let cdata = self.get_crate_data(cnum); decoder::get_reachable_ids(&cdata) } - fn is_no_builtins(&self, cnum: ast::CrateNum) -> bool { + fn is_no_builtins(&self, cnum: CrateNum) -> bool { attr::contains_name(&self.crate_attrs(cnum), "no_builtins") } fn def_index_for_def_key(&self, - cnum: ast::CrateNum, + cnum: CrateNum, def: DefKey) -> Option { let cdata = self.get_crate_data(cnum); @@ -488,7 +488,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { result } - fn crate_top_level_items(&self, cnum: ast::CrateNum) -> Vec + fn crate_top_level_items(&self, cnum: CrateNum) -> Vec { let mut result = vec![]; let crate_data = self.get_crate_data(cnum); @@ -651,7 +651,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { decoder::is_item_mir_available(&cdata, def.index) } - fn crates(&self) -> Vec + fn crates(&self) -> Vec { let mut result = vec![]; self.iter_crate_data(|cnum, _| result.push(cnum)); @@ -686,17 +686,17 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { encoder::encoded_ty(tcx, ty, def_id_to_string) } - fn used_crates(&self, prefer: LinkagePreference) -> Vec<(ast::CrateNum, Option)> + fn used_crates(&self, prefer: LinkagePreference) -> Vec<(CrateNum, Option)> { self.do_get_used_crates(prefer) } - fn used_crate_source(&self, cnum: ast::CrateNum) -> CrateSource + fn used_crate_source(&self, cnum: CrateNum) -> CrateSource { self.opt_used_crate_source(cnum).unwrap() } - fn extern_mod_stmt_cnum(&self, emod_id: ast::NodeId) -> Option + fn extern_mod_stmt_cnum(&self, emod_id: ast::NodeId) -> Option { self.do_extern_mod_stmt_cnum(emod_id) } @@ -738,7 +738,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { use rustc::middle::cstore::ChildItem; use std::collections::vec_deque::VecDeque; use std::collections::hash_map::Entry; - for cnum in 1 .. self.next_crate_num() { + for cnum in (1 .. self.next_crate_num().as_usize()).map(CrateNum::new) { let cdata = self.get_crate_data(cnum); match cdata.extern_crate.get() { diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs index bc3d92c11a1e..388620a2dafd 100644 --- a/src/librustc_metadata/cstore.rs +++ b/src/librustc_metadata/cstore.rs @@ -22,7 +22,7 @@ use index; use loader; use rustc::dep_graph::DepGraph; -use rustc::hir::def_id::{DefIndex, DefId}; +use rustc::hir::def_id::{CrateNum, DefIndex, DefId}; use rustc::hir::map::DefKey; use rustc::hir::svh::Svh; use rustc::middle::cstore::ExternCrate; @@ -47,7 +47,7 @@ pub use middle::cstore::{CrateSource, LinkMeta}; // local crate numbers (as generated during this session). Each external // crate may refer to types in other external crates, and each has their // own crate numbers. -pub type CrateNumMap = IndexVec; +pub type CrateNumMap = IndexVec; pub enum MetadataBlob { MetadataVec(Bytes), @@ -75,7 +75,7 @@ pub struct CrateMetadata { pub data: MetadataBlob, pub cnum_map: RefCell, - pub cnum: ast::CrateNum, + pub cnum: CrateNum, pub codemap_import_info: RefCell>, pub staged_api: bool, @@ -105,9 +105,9 @@ pub struct CachedInlinedItem { pub struct CStore { pub dep_graph: DepGraph, - metas: RefCell>>, + metas: RefCell>>, /// Map from NodeId's of local extern crate statements to crate numbers - extern_mod_crate_map: RefCell>, + extern_mod_crate_map: RefCell>, used_crate_sources: RefCell>, used_libraries: RefCell>, used_link_args: RefCell>, @@ -135,25 +135,25 @@ impl CStore { } } - pub fn next_crate_num(&self) -> ast::CrateNum { - self.metas.borrow().len() as ast::CrateNum + 1 + pub fn next_crate_num(&self) -> CrateNum { + CrateNum::new(self.metas.borrow().len() + 1) } - pub fn get_crate_data(&self, cnum: ast::CrateNum) -> Rc { + pub fn get_crate_data(&self, cnum: CrateNum) -> Rc { self.metas.borrow().get(&cnum).unwrap().clone() } - pub fn get_crate_hash(&self, cnum: ast::CrateNum) -> Svh { + pub fn get_crate_hash(&self, cnum: CrateNum) -> Svh { let cdata = self.get_crate_data(cnum); decoder::get_crate_hash(cdata.data()) } - pub fn set_crate_data(&self, cnum: ast::CrateNum, data: Rc) { + pub fn set_crate_data(&self, cnum: CrateNum, data: Rc) { self.metas.borrow_mut().insert(cnum, data); } pub fn iter_crate_data(&self, mut i: I) where - I: FnMut(ast::CrateNum, &Rc), + I: FnMut(CrateNum, &Rc), { for (&k, v) in self.metas.borrow().iter() { i(k, v); @@ -162,7 +162,7 @@ impl CStore { /// Like `iter_crate_data`, but passes source paths (if available) as well. pub fn iter_crate_data_origins(&self, mut i: I) where - I: FnMut(ast::CrateNum, &CrateMetadata, Option), + I: FnMut(CrateNum, &CrateMetadata, Option), { for (&k, v) in self.metas.borrow().iter() { let origin = self.opt_used_crate_source(k); @@ -178,7 +178,7 @@ impl CStore { } } - pub fn opt_used_crate_source(&self, cnum: ast::CrateNum) + pub fn opt_used_crate_source(&self, cnum: CrateNum) -> Option { self.used_crate_sources.borrow_mut() .iter().find(|source| source.cnum == cnum).cloned() @@ -193,7 +193,7 @@ impl CStore { self.statically_included_foreign_items.borrow_mut().clear(); } - pub fn crate_dependencies_in_rpo(&self, krate: ast::CrateNum) -> Vec + pub fn crate_dependencies_in_rpo(&self, krate: CrateNum) -> Vec { let mut ordering = Vec::new(); self.push_dependencies_in_postorder(&mut ordering, krate); @@ -202,8 +202,8 @@ impl CStore { } pub fn push_dependencies_in_postorder(&self, - ordering: &mut Vec, - krate: ast::CrateNum) + ordering: &mut Vec, + krate: CrateNum) { if ordering.contains(&krate) { return } @@ -227,7 +227,7 @@ impl CStore { // topological sort of all crates putting the leaves at the right-most // positions. pub fn do_get_used_crates(&self, prefer: LinkagePreference) - -> Vec<(ast::CrateNum, Option)> { + -> Vec<(CrateNum, Option)> { let mut ordering = Vec::new(); for (&num, _) in self.metas.borrow().iter() { self.push_dependencies_in_postorder(&mut ordering, num); @@ -272,7 +272,7 @@ impl CStore { pub fn add_extern_mod_stmt_cnum(&self, emod_id: ast::NodeId, - cnum: ast::CrateNum) { + cnum: CrateNum) { self.extern_mod_crate_map.borrow_mut().insert(emod_id, cnum); } @@ -284,7 +284,7 @@ impl CStore { self.statically_included_foreign_items.borrow().contains(&id) } - pub fn do_extern_mod_stmt_cnum(&self, emod_id: ast::NodeId) -> Option + pub fn do_extern_mod_stmt_cnum(&self, emod_id: ast::NodeId) -> Option { self.extern_mod_crate_map.borrow().get(&emod_id).cloned() } diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 10c2747ab169..72e95804ce8e 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -34,7 +34,7 @@ use rustc::session::config::PanicStrategy; use middle::cstore::{InlinedItem, LinkagePreference}; use middle::cstore::{DefLike, DlDef, DlField, DlImpl}; use rustc::hir::def::Def; -use rustc::hir::def_id::{DefId, DefIndex}; +use rustc::hir::def_id::{CrateNum, DefId, DefIndex, LOCAL_CRATE}; use middle::lang_items; use rustc::ty::{ImplContainer, TraitContainer}; use rustc::ty::{self, AdtKind, Ty, TyCtxt, TypeFoldable, VariantKind}; @@ -42,11 +42,8 @@ use rustc::ty::subst::Substs; use rustc_const_math::ConstInt; -use rustc::mir; -use rustc::mir::visit::MutVisitor; -use rustc::mir::repr::Location; +use rustc::mir::repr::Mir; -use std::cell::Cell; use std::io; use std::ops::{Deref, DerefMut}; use std::rc::Rc; @@ -54,11 +51,10 @@ use std::str; use rbml::reader; use rbml; -use rustc_serialize::{Decodable, Decoder, SpecializedDecoder}; +use rustc_serialize::{Decodable, SpecializedDecoder}; use syntax::attr; use syntax::parse::token; -use syntax::ast; -use syntax::codemap; +use syntax::ast::{self, NodeId}; use syntax::print::pprust; use syntax_pos::{self, Span, BytePos, NO_EXPANSION}; @@ -66,10 +62,10 @@ pub struct DecodeContext<'a, 'tcx: 'a> { pub rbml_r: rbml::reader::Decoder<'a>, pub tcx: TyCtxt<'a, 'tcx, 'tcx>, pub cdata: &'a cstore::CrateMetadata, - pub from_id_range: IdRange, - pub to_id_range: IdRange, + from_id_range: IdRange, + to_id_range: IdRange, // Cache the last used filemap for translating spans as an optimization. - pub last_filemap_index: Cell, + last_filemap_index: usize, } impl<'a, 'tcx> DecodeContext<'a, 'tcx> { @@ -82,9 +78,9 @@ impl<'a, 'tcx> DecodeContext<'a, 'tcx> { let to_id_range = if from_id_range.empty() { from_id_range } else { - let cnt = from_id_range.max - from_id_range.min; + let cnt = from_id_range.max.as_usize() - from_id_range.min.as_usize(); let to_id_min = tcx.sess.reserve_node_ids(cnt); - let to_id_max = to_id_min + cnt; + let to_id_max = NodeId::new(to_id_min.as_usize() + cnt); IdRange { min: to_id_min, max: to_id_max } }; @@ -94,7 +90,7 @@ impl<'a, 'tcx> DecodeContext<'a, 'tcx> { tcx: tcx, from_id_range: from_id_range, to_id_range: to_id_range, - last_filemap_index: Cell::new(0) + last_filemap_index: 0 } } @@ -104,7 +100,7 @@ impl<'a, 'tcx> DecodeContext<'a, 'tcx> { self.read_opaque(|this, doc| { Ok(op(&mut TyDecoder::with_doc( this.tcx, this.cdata.cnum, doc, - &mut |d| this.tr_def_id(d)))) + &mut |d| translate_def_id(&this.cdata, d)))) }).unwrap() } } @@ -122,6 +118,93 @@ impl<'a, 'tcx> DerefMut for DecodeContext<'a, 'tcx> { } } +impl<'a, 'tcx> SpecializedDecoder for DecodeContext<'a, 'tcx> { + fn specialized_decode(&mut self) -> Result { + let id = u32::decode(self)?; + + // from_id_range should be non-empty + assert!(!self.from_id_range.empty()); + // Make sure that translating the NodeId will actually yield a + // meaningful result + if !self.from_id_range.contains(NodeId::from_u32(id)) { + bug!("NodeId::decode: {} out of DecodeContext range ({:?} -> {:?})", + id, self.from_id_range, self.to_id_range); + } + + // Use wrapping arithmetic because otherwise it introduces control flow. + // Maybe we should just have the control flow? -- aatch + Ok(NodeId::from_u32(id.wrapping_sub(self.from_id_range.min.as_u32()) + .wrapping_add(self.to_id_range.min.as_u32()))) + } +} + +impl<'a, 'tcx> SpecializedDecoder for DecodeContext<'a, 'tcx> { + fn specialized_decode(&mut self) -> Result { + let cnum = CrateNum::from_u32(u32::decode(self)?); + if cnum == LOCAL_CRATE { + Ok(self.cdata.cnum) + } else { + Ok(self.cdata.cnum_map.borrow()[cnum]) + } + } +} + +impl<'a, 'tcx> SpecializedDecoder for DecodeContext<'a, 'tcx> { + fn specialized_decode(&mut self) -> Result { + let lo = BytePos::decode(self)?; + let hi = BytePos::decode(self)?; + + let (lo, hi) = if lo > hi { + // Currently macro expansion sometimes produces invalid Span values + // where lo > hi. In order not to crash the compiler when trying to + // translate these values, let's transform them into something we + // can handle (and which will produce useful debug locations at + // least some of the time). + // This workaround is only necessary as long as macro expansion is + // not fixed. FIXME(#23480) + (lo, lo) + } else { + (lo, hi) + }; + + let imported_filemaps = self.cdata.imported_filemaps(&self.tcx.sess.codemap()); + let filemap = { + // Optimize for the case that most spans within a translated item + // originate from the same filemap. + let last_filemap = &imported_filemaps[self.last_filemap_index]; + + if lo >= last_filemap.original_start_pos && + lo <= last_filemap.original_end_pos && + hi >= last_filemap.original_start_pos && + hi <= last_filemap.original_end_pos { + last_filemap + } else { + let mut a = 0; + let mut b = imported_filemaps.len(); + + while b - a > 1 { + let m = (a + b) / 2; + if imported_filemaps[m].original_start_pos > lo { + b = m; + } else { + a = m; + } + } + + self.last_filemap_index = a; + &imported_filemaps[a] + } + }; + + let lo = (lo - filemap.original_start_pos) + + filemap.translated_filemap.start_pos; + let hi = (hi - filemap.original_start_pos) + + filemap.translated_filemap.start_pos; + + Ok(syntax_pos::mk_sp(lo, hi)) + } +} + // FIXME(#36588) These impls are horribly unsound as they allow // the caller to pick any lifetime for 'tcx, including 'static, // by using the unspecialized proxies to them. @@ -148,8 +231,8 @@ impl<'a, 'tcx> SpecializedDecoder<&'tcx ty::Region> for DecodeContext<'a, 'tcx> impl<'a, 'tcx> SpecializedDecoder> for DecodeContext<'a, 'tcx> { fn specialized_decode(&mut self) -> Result, Self::Error> { Ok(ty::ClosureSubsts { - func_substs: Decodable::decode(this)?, - upvar_tys: this.tcx.mk_type_list(Decodable::decode(this)?) + func_substs: Decodable::decode(self)?, + upvar_tys: self.tcx.mk_type_list(Decodable::decode(self)?) }) } } @@ -157,7 +240,6 @@ impl<'a, 'tcx> SpecializedDecoder> for DecodeContext<'a, impl<'a, 'tcx> SpecializedDecoder> for DecodeContext<'a, 'tcx> { fn specialized_decode(&mut self) -> Result, Self::Error> { let def_id = DefId::decode(self)?; - let def_id = translate_def_id(self.cdata, def_id); Ok(self.tcx.lookup_adt_def(def_id)) } } @@ -318,8 +400,10 @@ fn item_sort(item: rbml::Doc) -> Option { fn untranslated_def_id(d: rbml::Doc) -> DefId { let id = reader::doc_as_u64(d); - let index = DefIndex::new((id & 0xFFFF_FFFF) as usize); - DefId { krate: (id >> 32) as u32, index: index } + DefId { + krate: CrateNum::from_u32((id >> 32) as u32), + index: DefIndex::from_u32((id & 0xFFFF_FFFF) as u32) + } } fn translated_def_id(cdata: Cmd, d: rbml::Doc) -> DefId { @@ -744,7 +828,7 @@ fn each_child_of_item_or_crate(cdata: Cmd, mut get_crate_data: G, mut callback: F) where F: FnMut(DefLike, ast::Name, ty::Visibility), - G: FnMut(ast::CrateNum) -> Rc, + G: FnMut(CrateNum) -> Rc, { // Iterate over all children. for child_info_doc in reader::tagged_docs(item_doc, tag_mod_child) { @@ -806,7 +890,7 @@ fn each_child_of_item_or_crate(cdata: Cmd, /// Iterates over each child of the given item. pub fn each_child_of_item(cdata: Cmd, id: DefIndex, get_crate_data: G, callback: F) where F: FnMut(DefLike, ast::Name, ty::Visibility), - G: FnMut(ast::CrateNum) -> Rc, + G: FnMut(CrateNum) -> Rc, { // Find the item. let item_doc = match cdata.get_item(id) { @@ -820,7 +904,7 @@ pub fn each_child_of_item(cdata: Cmd, id: DefIndex, get_crate_data: G, cal /// Iterates over all the top-level crate items. pub fn each_top_level_item_of_crate(cdata: Cmd, get_crate_data: G, callback: F) where F: FnMut(DefLike, ast::Name, ty::Visibility), - G: FnMut(ast::CrateNum) -> Rc, + G: FnMut(CrateNum) -> Rc, { each_child_of_item(cdata, CRATE_DEF_INDEX, get_crate_data, callback) } @@ -894,52 +978,14 @@ pub fn is_item_mir_available<'tcx>(cdata: Cmd, id: DefIndex) -> bool { pub fn maybe_get_item_mir<'a, 'tcx>(cdata: Cmd, tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefIndex) - -> Option> { + -> Option> { let item_doc = cdata.lookup_item(id); - return reader::maybe_get_doc(item_doc, tag_mir as usize).map(|mir_doc| { - let mut dcx = DecodeContext::new(tcx, cdata, - IdRange { min: 0, max: 0 }, - mir_doc); - - let mut mir = Decodable::decode(&mut dcx).unwrap(); - - assert!(dcx.rbml_r.position() == mir_doc.end); - - let mut def_id_and_span_translator = MirDefIdAndSpanTranslator { - crate_metadata: cdata, - codemap: tcx.sess.codemap(), - last_filemap_index_hint: Cell::new(0), - }; - - def_id_and_span_translator.visit_mir(&mut mir); - for promoted in &mut mir.promoted { - def_id_and_span_translator.visit_mir(promoted); - } - - mir - }); - - struct MirDefIdAndSpanTranslator<'cdata, 'codemap> { - crate_metadata: Cmd<'cdata>, - codemap: &'codemap codemap::CodeMap, - last_filemap_index_hint: Cell - } - - impl<'v, 'cdata, 'codemap> mir::visit::MutVisitor<'v> - for MirDefIdAndSpanTranslator<'cdata, 'codemap> - { - fn visit_def_id(&mut self, def_id: &mut DefId, _: Location) { - *def_id = translate_def_id(self.crate_metadata, *def_id); - } - - fn visit_span(&mut self, span: &mut Span) { - *span = translate_span(self.crate_metadata, - self.codemap, - &self.last_filemap_index_hint, - *span); - } - } + reader::maybe_get_doc(item_doc, tag_mir).map(|mir_doc| { + let id_range = IdRange { min: NodeId::new(0), max: NodeId::new(0) }; + let mut dcx = DecodeContext::new(tcx, cdata, id_range, mir_doc); + Decodable::decode(&mut dcx).unwrap() + }) } fn get_explicit_self<'a, 'tcx>(item: rbml::Doc, tcx: TyCtxt<'a, 'tcx, 'tcx>) @@ -1225,7 +1271,7 @@ pub fn get_crate_attributes(data: &[u8]) -> Vec { #[derive(Clone)] pub struct CrateDep { - pub cnum: ast::CrateNum, + pub cnum: CrateNum, pub name: String, pub hash: Svh, pub explicitly_linked: bool, @@ -1246,7 +1292,7 @@ pub fn get_crate_deps(data: &[u8]) -> Vec { let doc = reader::get_doc(depdoc, tag_crate_dep_explicitly_linked); let explicitly_linked = reader::doc_as_u8(doc) != 0; CrateDep { - cnum: crate_num as u32 + 1, + cnum: CrateNum::new(crate_num + 1), name: name, hash: hash, explicitly_linked: explicitly_linked, @@ -1335,64 +1381,6 @@ fn reverse_translate_def_id(cdata: Cmd, did: DefId) -> Option { None } -/// Translates a `Span` from an extern crate to the corresponding `Span` -/// within the local crate's codemap. -pub fn translate_span(cdata: Cmd, - codemap: &codemap::CodeMap, - last_filemap_index_hint: &Cell, - span: syntax_pos::Span) - -> syntax_pos::Span { - let span = if span.lo > span.hi { - // Currently macro expansion sometimes produces invalid Span values - // where lo > hi. In order not to crash the compiler when trying to - // translate these values, let's transform them into something we - // can handle (and which will produce useful debug locations at - // least some of the time). - // This workaround is only necessary as long as macro expansion is - // not fixed. FIXME(#23480) - syntax_pos::mk_sp(span.lo, span.lo) - } else { - span - }; - - let imported_filemaps = cdata.imported_filemaps(&codemap); - let filemap = { - // Optimize for the case that most spans within a translated item - // originate from the same filemap. - let last_filemap_index = last_filemap_index_hint.get(); - let last_filemap = &imported_filemaps[last_filemap_index]; - - if span.lo >= last_filemap.original_start_pos && - span.lo <= last_filemap.original_end_pos && - span.hi >= last_filemap.original_start_pos && - span.hi <= last_filemap.original_end_pos { - last_filemap - } else { - let mut a = 0; - let mut b = imported_filemaps.len(); - - while b - a > 1 { - let m = (a + b) / 2; - if imported_filemaps[m].original_start_pos > span.lo { - b = m; - } else { - a = m; - } - } - - last_filemap_index_hint.set(a); - &imported_filemaps[a] - } - }; - - let lo = (span.lo - filemap.original_start_pos) + - filemap.translated_filemap.start_pos; - let hi = (span.hi - filemap.original_start_pos) + - filemap.translated_filemap.start_pos; - - syntax_pos::mk_sp(lo, hi) -} - pub fn each_inherent_implementation_for_type(cdata: Cmd, id: DefIndex, mut callback: F) @@ -1491,7 +1479,7 @@ pub fn get_macro_span(doc: rbml::Doc) -> Span { } pub fn get_dylib_dependency_formats(cdata: Cmd) - -> Vec<(ast::CrateNum, LinkagePreference)> + -> Vec<(CrateNum, LinkagePreference)> { let formats = reader::get_doc(rbml::Doc::new(cdata.data()), tag_dylib_dependency_formats); @@ -1503,7 +1491,7 @@ pub fn get_dylib_dependency_formats(cdata: Cmd) let mut split = spec.split(':'); let cnum = split.next().unwrap(); let link = split.next().unwrap(); - let cnum: ast::CrateNum = cnum.parse().unwrap(); + let cnum = CrateNum::new(cnum.parse().unwrap()); let cnum = cdata.cnum_map.borrow()[cnum]; result.push((cnum, if link == "d" { LinkagePreference::RequireDynamic diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 0f7765713c3c..e493daab0910 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -23,7 +23,7 @@ use index::{self, IndexData}; use middle::cstore::{InlinedItemRef, LinkMeta}; use rustc::hir::def; -use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId}; +use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId}; use middle::dependency_format::Linkage; use rustc::dep_graph::DepNode; use rustc::traits::specialization_graph; @@ -42,7 +42,7 @@ use std::io::{Cursor, SeekFrom}; use std::ops::{Deref, DerefMut}; use std::rc::Rc; use std::u32; -use syntax::ast::{self, NodeId, Name, CRATE_NODE_ID, CrateNum}; +use syntax::ast::{self, NodeId, Name, CRATE_NODE_ID}; use syntax::attr; use syntax; use syntax_pos::BytePos; @@ -136,8 +136,7 @@ fn encode_family(ecx: &mut EncodeContext, c: char) { } pub fn def_to_u64(did: DefId) -> u64 { - assert!(did.index.as_u32() < u32::MAX); - (did.krate as u64) << 32 | (did.index.as_usize() as u64) + (did.krate.as_u32() as u64) << 32 | (did.index.as_u32() as u64) } pub fn def_to_string(_tcx: TyCtxt, did: DefId) -> String { @@ -1457,7 +1456,7 @@ fn encode_crate_deps(ecx: &mut EncodeContext, cstore: &cstore::CStore) { // Sanity-check the crate numbers let mut expected_cnum = 1; for &(n, _) in &deps { - assert_eq!(n, expected_cnum); + assert_eq!(n, CrateNum::new(expected_cnum)); expected_cnum += 1; } diff --git a/src/librustc_metadata/tydecode.rs b/src/librustc_metadata/tydecode.rs index bcaf1640bc41..6d3b8571d3c3 100644 --- a/src/librustc_metadata/tydecode.rs +++ b/src/librustc_metadata/tydecode.rs @@ -18,7 +18,7 @@ use rustc::hir; -use rustc::hir::def_id::{DefId, DefIndex}; +use rustc::hir::def_id::{CrateNum, DefId, DefIndex}; use middle::region; use rustc::ty::subst::{Kind, Substs}; use rustc::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable}; @@ -38,7 +38,7 @@ pub type DefIdConvert<'a> = &'a mut FnMut(DefId) -> DefId; pub struct TyDecoder<'a, 'tcx: 'a> { data: &'a [u8], - krate: ast::CrateNum, + krate: CrateNum, pos: usize, tcx: TyCtxt<'a, 'tcx, 'tcx>, conv_def_id: DefIdConvert<'a>, @@ -46,7 +46,7 @@ pub struct TyDecoder<'a, 'tcx: 'a> { impl<'a,'tcx> TyDecoder<'a,'tcx> { pub fn with_doc(tcx: TyCtxt<'a, 'tcx, 'tcx>, - crate_num: ast::CrateNum, + crate_num: CrateNum, doc: rbml::Doc<'a>, conv: DefIdConvert<'a>) -> TyDecoder<'a,'tcx> { @@ -54,7 +54,7 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> { } pub fn new(data: &'a [u8], - crate_num: ast::CrateNum, + crate_num: CrateNum, pos: usize, tcx: TyCtxt<'a, 'tcx, 'tcx>, conv: DefIdConvert<'a>) @@ -258,9 +258,9 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> { // May still be worth fixing though. 'C' => { assert_eq!(self.next(), '['); - let fn_id = self.parse_uint() as ast::NodeId; + let fn_id = ast::NodeId::new(self.parse_uint()); assert_eq!(self.next(), '|'); - let body_id = self.parse_uint() as ast::NodeId; + let body_id = ast::NodeId::new(self.parse_uint()); assert_eq!(self.next(), ']'); region::CodeExtentData::CallSiteScope { fn_id: fn_id, body_id: body_id @@ -269,25 +269,25 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> { // This creates scopes with the wrong NodeId. (See note above.) 'P' => { assert_eq!(self.next(), '['); - let fn_id = self.parse_uint() as ast::NodeId; + let fn_id = ast::NodeId::new(self.parse_uint()); assert_eq!(self.next(), '|'); - let body_id = self.parse_uint() as ast::NodeId; + let body_id = ast::NodeId::new(self.parse_uint()); assert_eq!(self.next(), ']'); region::CodeExtentData::ParameterScope { fn_id: fn_id, body_id: body_id } } 'M' => { - let node_id = self.parse_uint() as ast::NodeId; + let node_id = ast::NodeId::new(self.parse_uint()); region::CodeExtentData::Misc(node_id) } 'D' => { - let node_id = self.parse_uint() as ast::NodeId; + let node_id = ast::NodeId::new(self.parse_uint()); region::CodeExtentData::DestructionScope(node_id) } 'B' => { assert_eq!(self.next(), '['); - let node_id = self.parse_uint() as ast::NodeId; + let node_id = ast::NodeId::new(self.parse_uint()); assert_eq!(self.next(), '|'); let first_stmt_index = self.parse_u32(); assert_eq!(self.next(), ']'); @@ -726,7 +726,7 @@ fn parse_defid(buf: &[u8]) -> DefId { let crate_num = match str::from_utf8(crate_part).ok().and_then(|s| { s.parse::().ok() }) { - Some(cn) => cn as ast::CrateNum, + Some(cn) => CrateNum::new(cn), None => bug!("internal error: parse_defid: crate number expected, found {:?}", crate_part) }; diff --git a/src/librustc_mir/transform/type_check.rs b/src/librustc_mir/transform/type_check.rs index 7fda658185e0..e75a95431966 100644 --- a/src/librustc_mir/transform/type_check.rs +++ b/src/librustc_mir/transform/type_check.rs @@ -20,6 +20,7 @@ use rustc::mir::tcx::LvalueTy; use rustc::mir::transform::{MirPass, MirSource, Pass}; use rustc::mir::visit::{self, Visitor}; use std::fmt; +use syntax::ast; use syntax_pos::{Span, DUMMY_SP}; use rustc_data_structures::indexed_vec::Idx; @@ -673,7 +674,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { where T: fmt::Debug + TypeFoldable<'tcx> { let mut selcx = traits::SelectionContext::new(self.infcx); - let cause = traits::ObligationCause::misc(self.last_span, 0); + let cause = traits::ObligationCause::misc(self.last_span, ast::CRATE_NODE_ID); let traits::Normalized { value, obligations } = traits::normalize(&mut selcx, cause, value); diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 31893b0873c7..659edb86be16 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -49,14 +49,14 @@ use rustc::middle::cstore::MacroLoader; use rustc::session::Session; use rustc::lint; use rustc::hir::def::*; -use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId}; +use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId}; use rustc::ty; use rustc::hir::{Freevar, FreevarMap, TraitCandidate, TraitMap, GlobMap}; use rustc::util::nodemap::{NodeMap, NodeSet, FnvHashMap, FnvHashSet}; use syntax::ext::hygiene::Mark; use syntax::ast::{self, FloatTy}; -use syntax::ast::{CRATE_NODE_ID, Name, NodeId, CrateNum, IntTy, UintTy}; +use syntax::ast::{CRATE_NODE_ID, Name, NodeId, IntTy, UintTy}; use syntax::parse::token::{self, keywords}; use syntax::util::lev_distance::find_best_match_for_name; diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 67ee4c307d3c..e452a44cea58 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -135,7 +135,7 @@ struct ExpansionVisitor<'b, 'a: 'b> { impl<'a, 'b> ExpansionVisitor<'a, 'b> { fn visit_invoc(&mut self, id: ast::NodeId) { - assert_eq!(id, self.resolver.expansion_data.len() as u32); + assert_eq!(id.as_u32(), self.resolver.expansion_data.len() as u32); self.resolver.expansion_data.push(ExpansionData { module: self.current_module.clone(), }); diff --git a/src/librustc_save_analysis/data.rs b/src/librustc_save_analysis/data.rs index 4e03ea4218f0..fc235aaf9276 100644 --- a/src/librustc_save_analysis/data.rs +++ b/src/librustc_save_analysis/data.rs @@ -14,8 +14,8 @@ //! retrieve the data from a crate. use rustc::hir; -use rustc::hir::def_id::DefId; -use syntax::ast::{self, CrateNum, NodeId}; +use rustc::hir::def_id::{CrateNum, DefId}; +use syntax::ast::{self, NodeId}; use syntax_pos::Span; pub struct CrateData { diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 8820f3616d50..37b31eda5a35 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -29,7 +29,7 @@ use rustc::hir; use rustc::hir::def::Def; -use rustc::hir::def_id::DefId; +use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc::hir::map::{Node, NodeItem}; use rustc::session::Session; use rustc::ty::{self, TyCtxt, ImplOrTraitItem, ImplOrTraitItemContainer}; @@ -37,7 +37,7 @@ use rustc::ty::{self, TyCtxt, ImplOrTraitItem, ImplOrTraitItemContainer}; use std::collections::HashSet; use std::hash::*; -use syntax::ast::{self, NodeId, PatKind, Attribute}; +use syntax::ast::{self, NodeId, PatKind, Attribute, CRATE_NODE_ID}; use syntax::parse::token::{self, keywords}; use syntax::visit::{self, Visitor}; use syntax::print::pprust::{path_to_string, ty_to_string, bounds_to_string, generics_to_string}; @@ -95,7 +95,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { analysis: analysis, dumper: dumper, span: span_utils.clone(), - cur_scope: 0, + cur_scope: CRATE_NODE_ID, mac_defs: HashSet::new(), mac_uses: HashSet::new(), } @@ -124,7 +124,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { let lo_loc = self.span.sess.codemap().lookup_char_pos(c.span.lo); ExternalCrateData { name: c.name, - num: c.number, + num: CrateNum::from_u32(c.number), file_name: SpanUtils::make_path_string(&lo_loc.file.name), } }).collect(); @@ -252,7 +252,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { ref_id: None, span: *span, qualname: qualname.to_owned(), - scope: 0 + scope: CRATE_NODE_ID }.lower(self.tcx)); // write the other sub-paths @@ -368,7 +368,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { qualname: format!("{}::{}", qualname, path_to_string(p)), type_value: typ, value: String::new(), - scope: 0, + scope: CRATE_NODE_ID, parent: None, visibility: Visibility::Inherited, docs: String::new(), @@ -1044,7 +1044,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { qualname: format!("{}${}", path_to_string(p), id), value: value, type_value: typ, - scope: 0, + scope: CRATE_NODE_ID, parent: None, visibility: Visibility::Inherited, docs: String::new(), @@ -1239,7 +1239,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D> let alias_span = self.span.span_for_last_ident(item.span); let cnum = match self.sess.cstore.extern_mod_stmt_cnum(item.id) { Some(cnum) => cnum, - None => 0, + None => LOCAL_CRATE, }; if !self.span.filter_generated(alias_span, item.span) { @@ -1478,7 +1478,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D> qualname: format!("{}${}", path_to_string(p), id), value: value, type_value: typ, - scope: 0, + scope: CRATE_NODE_ID, parent: None, visibility: Visibility::Inherited, docs: String::new(), diff --git a/src/librustc_save_analysis/external_data.rs b/src/librustc_save_analysis/external_data.rs index 32280a5c9262..584757574234 100644 --- a/src/librustc_save_analysis/external_data.rs +++ b/src/librustc_save_analysis/external_data.rs @@ -8,10 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use rustc::hir::def_id::{DefId, DefIndex}; +use rustc::hir::def_id::{CrateNum, DefId, DefIndex}; use rustc::hir::map::Map; use rustc::ty::TyCtxt; -use syntax::ast::{CrateNum, NodeId}; +use syntax::ast::NodeId; use syntax::codemap::CodeMap; use syntax_pos::Span; @@ -28,7 +28,10 @@ pub fn make_def_id(id: NodeId, map: &Map) -> DefId { } pub fn null_def_id() -> DefId { - DefId { krate: u32::max_value(), index: DefIndex::from_u32(u32::max_value()) } + DefId { + krate: CrateNum::from_u32(u32::max_value()), + index: DefIndex::from_u32(u32::max_value()) + } } #[derive(Clone, Debug, RustcEncodable)] diff --git a/src/librustc_save_analysis/json_api_dumper.rs b/src/librustc_save_analysis/json_api_dumper.rs index 78eaa65872a4..d56aae18a7cd 100644 --- a/src/librustc_save_analysis/json_api_dumper.rs +++ b/src/librustc_save_analysis/json_api_dumper.rs @@ -117,7 +117,7 @@ struct Id { impl From for Id { fn from(id: DefId) -> Id { Id { - krate: id.krate, + krate: id.krate.as_u32(), index: id.index.as_u32(), } } diff --git a/src/librustc_save_analysis/json_dumper.rs b/src/librustc_save_analysis/json_dumper.rs index 75abff8d37ed..0378d75cc6eb 100644 --- a/src/librustc_save_analysis/json_dumper.rs +++ b/src/librustc_save_analysis/json_dumper.rs @@ -120,7 +120,7 @@ struct Id { impl From for Id { fn from(id: DefId) -> Id { Id { - krate: id.krate, + krate: id.krate.as_u32(), index: id.index.as_u32(), } } diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 51274068b26c..3764e26b020d 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -52,7 +52,7 @@ use std::env; use std::fs::{self, File}; use std::path::{Path, PathBuf}; -use syntax::ast::{self, NodeId, PatKind, Attribute}; +use syntax::ast::{self, NodeId, PatKind, Attribute, CRATE_NODE_ID}; use syntax::parse::lexer::comments::strip_doc_comment_decoration; use syntax::parse::token::{self, keywords, InternedString}; use syntax::visit::{self, Visitor}; @@ -120,7 +120,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { }; result.push(CrateData { name: (&self.tcx.sess.cstore.crate_name(n)[..]).to_owned(), - number: n, + number: n.as_u32(), span: span, }); } @@ -676,7 +676,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { #[inline] pub fn enclosing_scope(&self, id: NodeId) -> NodeId { - self.tcx.map.get_enclosing_scope(id).unwrap_or(0) + self.tcx.map.get_enclosing_scope(id).unwrap_or(CRATE_NODE_ID) } } diff --git a/src/librustc_trans/adt.rs b/src/librustc_trans/adt.rs index 67e5ec2616d2..2b92d7e9e457 100644 --- a/src/librustc_trans/adt.rs +++ b/src/librustc_trans/adt.rs @@ -556,9 +556,9 @@ fn range_to_inttype(cx: &CrateContext, hint: Hint, bounds: &IntBounds) -> IntTyp let attempts; match hint { - attr::ReprInt(span, ity) => { + attr::ReprInt(ity) => { if !bounds_usable(cx, ity, bounds) { - span_bug!(span, "representation hint insufficient for discriminant range") + bug!("representation hint insufficient for discriminant range") } return ity; } diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs index 288249a7d993..201e1e5f2ec4 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_trans/back/link.rs @@ -26,6 +26,7 @@ use CrateTranslation; use util::common::time; use util::fs::fix_windows_verbatim_for_gcc; use rustc::dep_graph::DepNode; +use rustc::hir::def_id::CrateNum; use rustc::hir::svh::Svh; use rustc_back::tempdir::TempDir; use rustc_incremental::IncrementalHashesMap; @@ -288,7 +289,7 @@ pub fn filename_for_input(sess: &Session, } pub fn each_linked_rlib(sess: &Session, - f: &mut FnMut(ast::CrateNum, &Path)) { + f: &mut FnMut(CrateNum, &Path)) { let crates = sess.cstore.used_crates(LinkagePreference::RequireStatic).into_iter(); let fmts = sess.dependency_formats.borrow(); let fmts = fmts.get(&config::CrateTypeExecutable) @@ -299,7 +300,7 @@ pub fn each_linked_rlib(sess: &Session, bug!("could not find formats for rlibs") }); for (cnum, path) in crates { - match fmts[cnum as usize - 1] { + match fmts[cnum.as_usize() - 1] { Linkage::NotLinked | Linkage::IncludedFromDylib => continue, _ => {} } @@ -933,7 +934,7 @@ fn add_upstream_rust_crates(cmd: &mut Linker, // appear statically in an existing dylib, meaning we'll pick up all the // symbols from the dylib. let src = sess.cstore.used_crate_source(cnum); - match data[cnum as usize - 1] { + match data[cnum.as_usize() - 1] { // compiler-builtins are always placed last to ensure that they're // linked correctly. _ if sess.cstore.is_compiler_builtins(cnum) => { @@ -1003,7 +1004,7 @@ fn add_upstream_rust_crates(cmd: &mut Linker, sess: &Session, tmpdir: &Path, crate_type: config::CrateType, - cnum: ast::CrateNum) { + cnum: CrateNum) { let src = sess.cstore.used_crate_source(cnum); let cratepath = &src.rlib.unwrap().0; if !sess.lto() && crate_type != config::CrateTypeDylib { diff --git a/src/librustc_trans/back/linker.rs b/src/librustc_trans/back/linker.rs index 58cad5c117f9..dd14f98c9207 100644 --- a/src/librustc_trans/back/linker.rs +++ b/src/librustc_trans/back/linker.rs @@ -21,10 +21,10 @@ use monomorphize::Instance; use back::archive; use middle::dependency_format::Linkage; +use rustc::hir::def_id::CrateNum; use session::Session; use session::config::CrateType; use session::config; -use syntax::ast; /// For all the linkers we support, and information they might /// need out of the shared crate context before we get rid of it. @@ -473,7 +473,7 @@ fn exported_symbols(scx: &SharedCrateContext, let deps = formats[&crate_type].iter(); symbols.extend(deps.enumerate().filter_map(|(i, f)| { if *f == Linkage::Static { - Some((i + 1) as ast::CrateNum) + Some(CrateNum::new(i + 1)) } else { None } diff --git a/src/librustc_back/rpath.rs b/src/librustc_trans/back/rpath.rs similarity index 98% rename from src/librustc_back/rpath.rs rename to src/librustc_trans/back/rpath.rs index 6cba27fcf340..4ed860bd40d8 100644 --- a/src/librustc_back/rpath.rs +++ b/src/librustc_trans/back/rpath.rs @@ -12,10 +12,11 @@ use std::collections::HashSet; use std::env; use std::path::{Path, PathBuf}; use std::fs; -use syntax::ast; + +use rustc::hir::def_id::CrateNum; pub struct RPathConfig<'a> { - pub used_crates: Vec<(ast::CrateNum, Option)>, + pub used_crates: Vec<(CrateNum, Option)>, pub out_filename: PathBuf, pub is_like_osx: bool, pub has_rpath: bool, diff --git a/src/librustc_trans/back/symbol_names.rs b/src/librustc_trans/back/symbol_names.rs index 76d83eee4bb4..ab1474c23513 100644 --- a/src/librustc_trans/back/symbol_names.rs +++ b/src/librustc_trans/back/symbol_names.rs @@ -101,8 +101,8 @@ use common::{CrateContext, SharedCrateContext, gensym_name}; use monomorphize::Instance; use util::sha2::{Digest, Sha256}; -use rustc::middle::{cstore, weak_lang_items}; -use rustc::hir::def_id::DefId; +use rustc::middle::weak_lang_items; +use rustc::hir::def_id::{DefId, LOCAL_CRATE}; use rustc::hir::map as hir_map; use rustc::ty::{Ty, TyCtxt, TypeFoldable}; use rustc::ty::item_path::{self, ItemPathBuffer, RootMode}; @@ -298,7 +298,7 @@ pub fn exported_name_from_type_and_prefix<'a, 'tcx>(scx: &SharedCrateContext<'a, -> String { let empty_def_path = DefPath { data: vec![], - krate: cstore::LOCAL_CRATE, + krate: LOCAL_CRATE, }; let hash = get_symbol_hash(scx, &empty_def_path, t, None); let path = [token::intern_and_get_ident(prefix)]; @@ -315,7 +315,7 @@ pub fn internal_name_from_type_and_suffix<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx> gensym_name(suffix).as_str()]; let def_path = DefPath { data: vec![], - krate: cstore::LOCAL_CRATE, + krate: LOCAL_CRATE, }; let hash = get_symbol_hash(ccx.shared(), &def_path, t, None); mangle(path.iter().cloned(), Some(&hash[..])) diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index 3e60369acbff..41c8d565d418 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -69,7 +69,6 @@ pub use base::trans_crate; pub use disr::Disr; pub mod back { - pub use rustc_back::rpath; pub use rustc::hir::svh; pub mod archive; @@ -79,6 +78,7 @@ pub mod back { pub mod symbol_names; pub mod write; pub mod msvc; + pub mod rpath; } pub mod diagnostics; diff --git a/src/librustc_trans/type_of.rs b/src/librustc_trans/type_of.rs index 3873c24a9f67..141b8506c39b 100644 --- a/src/librustc_trans/type_of.rs +++ b/src/librustc_trans/type_of.rs @@ -356,7 +356,7 @@ fn llvm_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, format!("{}<{}>", base, strings.join(", ")) }; - if did.krate == 0 { + if did.is_local() { tstr } else { format!("{}.{}", did.krate, tstr) diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index 5bd4f13a1119..d1fb0736d211 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -12,9 +12,8 @@ use super::{DeferredCallResolution, Expectation, FnCtxt, TupleArgumentsFlag}; use CrateCtxt; -use middle::cstore::LOCAL_CRATE; use hir::def::Def; -use hir::def_id::DefId; +use hir::def_id::{DefId, LOCAL_CRATE}; use rustc::{infer, traits}; use rustc::ty::{self, LvaluePreference, Ty}; use syntax::parse::token; diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index faad3f9b000c..4a631493398e 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -577,7 +577,7 @@ pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, assoc::normalize_associated_types_in(&infcx, &mut fulfillment_cx, impl_c_span, - 0, + ast::CRATE_NODE_ID, &impl_ty); debug!("compare_const_impl: impl_ty={:?}", @@ -587,7 +587,7 @@ pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, assoc::normalize_associated_types_in(&infcx, &mut fulfillment_cx, impl_c_span, - 0, + ast::CRATE_NODE_ID, &trait_ty); debug!("compare_const_impl: trait_ty={:?}", diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index baa084212a2d..01d7b1e54751 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -83,9 +83,8 @@ use self::TupleArgumentsFlag::*; use astconv::{AstConv, ast_region_to_region, PathParamMode}; use dep_graph::DepNode; use fmt_macros::{Parser, Piece, Position}; -use middle::cstore::LOCAL_CRATE; use hir::def::{Def, PathResolution}; -use hir::def_id::DefId; +use hir::def_id::{DefId, LOCAL_CRATE}; use hir::pat_util; use rustc::infer::{self, InferCtxt, InferOk, TypeOrigin, TypeTrace, type_variable}; use rustc::ty::subst::{Subst, Substs}; @@ -1450,7 +1449,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { writeback_errors: Cell::new(false), err_count_on_creation: inh.tcx.sess.err_count(), ret_ty: rty, - ps: RefCell::new(UnsafetyState::function(hir::Unsafety::Normal, 0)), + ps: RefCell::new(UnsafetyState::function(hir::Unsafety::Normal, + ast::CRATE_NODE_ID)), inh: inh, } } @@ -2117,7 +2117,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { .unwrap_or(type_variable::Default { ty: self.next_ty_var(), origin_span: syntax_pos::DUMMY_SP, - def_id: self.tcx.map.local_def_id(0) // what do I put here? + // what do I put here? + def_id: self.tcx.map.local_def_id(ast::CRATE_NODE_ID) }); // This is to ensure that we elimnate any non-determinism from the error diff --git a/src/librustc_typeck/coherence/orphan.rs b/src/librustc_typeck/coherence/orphan.rs index d1eb0f995de1..70342a0cd258 100644 --- a/src/librustc_typeck/coherence/orphan.rs +++ b/src/librustc_typeck/coherence/orphan.rs @@ -11,8 +11,7 @@ //! Orphan checker: every impl either implements a trait defined in this //! crate or pertains to a type defined in this crate. -use middle::cstore::LOCAL_CRATE; -use hir::def_id::DefId; +use hir::def_id::{DefId, LOCAL_CRATE}; use rustc::traits; use rustc::ty::{self, TyCtxt}; use syntax::ast; diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index b9dc75cdd9f1..7ee173019a51 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -37,7 +37,7 @@ use rustc::middle::cstore; use rustc::middle::privacy::AccessLevels; use rustc::middle::resolve_lifetime::DefRegion::*; use rustc::hir::def::Def; -use rustc::hir::def_id::{DefId, DefIndex, CRATE_DEF_INDEX}; +use rustc::hir::def_id::{self, DefId, DefIndex, CRATE_DEF_INDEX}; use rustc::hir::fold::Folder; use rustc::hir::print as pprust; use rustc::ty::subst::Substs; @@ -116,7 +116,7 @@ pub struct Crate { pub name: String, pub src: PathBuf, pub module: Option, - pub externs: Vec<(ast::CrateNum, ExternalCrate)>, + pub externs: Vec<(def_id::CrateNum, ExternalCrate)>, pub primitives: Vec, pub access_levels: Arc>, // These are later on moved into `CACHEKEY`, leaving the map empty. @@ -124,7 +124,7 @@ pub struct Crate { pub external_traits: FnvHashMap, } -struct CrateNum(ast::CrateNum); +struct CrateNum(def_id::CrateNum); impl<'a, 'tcx> Clean for visit_ast::RustdocVisitor<'a, 'tcx> { fn clean(&self, cx: &DocContext) -> Crate { @@ -1159,7 +1159,7 @@ impl<'a, 'tcx> Clean for (DefId, &'a ty::PolyFnSig<'tcx>) { values: sig.0.inputs.iter().map(|t| { Argument { type_: t.clean(cx), - id: 0, + id: ast::CRATE_NODE_ID, name: names.next().unwrap_or("".to_string()), } }).collect(), @@ -1808,7 +1808,7 @@ impl<'tcx> Clean for ty::Ty<'tcx> { type_params: Vec::new(), where_predicates: Vec::new() }, - decl: (cx.map.local_def_id(0), &fty.sig).clean(cx), + decl: (cx.map.local_def_id(ast::CRATE_NODE_ID), &fty.sig).clean(cx), abi: fty.abi, }), ty::TyAdt(def, substs) => { @@ -2590,7 +2590,7 @@ impl Clean> for doctree::Import { name: None, attrs: self.attrs.clean(cx), source: self.whence.clean(cx), - def_id: cx.map.local_def_id(0), + def_id: cx.map.local_def_id(ast::CRATE_NODE_ID), visibility: self.vis.clean(cx), stability: None, deprecation: None, diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 1e3804955e94..ab6858a09310 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -13,7 +13,7 @@ use rustc_lint; use rustc_driver::{driver, target_features, abort_on_err}; use rustc::dep_graph::DepGraph; use rustc::session::{self, config}; -use rustc::hir::def_id::DefId; +use rustc::hir::def_id::{CrateNum, DefId}; use rustc::middle::privacy::AccessLevels; use rustc::ty::{self, TyCtxt}; use rustc::hir::map as hir_map; @@ -23,7 +23,7 @@ use rustc_trans::back::link; use rustc_resolve as resolve; use rustc_metadata::cstore::CStore; -use syntax::{ast, codemap}; +use syntax::codemap; use syntax::feature_gate::UnstableFeatures; use errors; use errors::emitter::ColorConfig; @@ -51,7 +51,7 @@ pub struct DocContext<'a, 'tcx: 'a> { pub map: &'a hir_map::Map<'tcx>, pub maybe_typed: MaybeTyped<'a, 'tcx>, pub input: Input, - pub populated_crate_impls: RefCell>, + pub populated_crate_impls: RefCell>, pub deref_trait_did: Cell>, pub deref_mut_trait_did: Cell>, // Note that external items for which `doc(hidden)` applies to are shown as diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs index c2404f4294e9..609ae0c0e6da 100644 --- a/src/librustdoc/doctree.rs +++ b/src/librustdoc/doctree.rs @@ -21,6 +21,7 @@ use syntax::ptr::P; use syntax_pos::{self, Span}; use rustc::hir; +use rustc::hir::def_id::CrateNum; pub struct Module { pub name: Option, @@ -53,7 +54,7 @@ impl Module { pub fn new(name: Option) -> Module { Module { name : name, - id: 0, + id: ast::CRATE_NODE_ID, vis: hir::Inherited, stab: None, depr: None, @@ -245,7 +246,7 @@ pub struct Macro { pub struct ExternCrate { pub name: Name, - pub cnum: ast::CrateNum, + pub cnum: CrateNum, pub path: Option, pub vis: hir::Visibility, pub attrs: hir::HirVec, diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 65992798ab09..adcdc7aaab40 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -18,8 +18,7 @@ use std::fmt; use std::iter::repeat; -use rustc::middle::cstore::LOCAL_CRATE; -use rustc::hir::def_id::DefId; +use rustc::hir::def_id::{DefId, LOCAL_CRATE}; use syntax::abi::Abi; use rustc::hir; diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 8cc9bbb422ae..03d772d1a6db 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -53,10 +53,9 @@ use std::sync::Arc; use externalfiles::ExternalHtml; use serialize::json::{ToJson, Json, as_json}; -use syntax::{abi, ast}; +use syntax::abi; use syntax::feature_gate::UnstableFeatures; -use rustc::middle::cstore::LOCAL_CRATE; -use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId}; +use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId, LOCAL_CRATE}; use rustc::middle::privacy::AccessLevels; use rustc::middle::stability; use rustc::session::config::get_unstable_features_setting; @@ -246,10 +245,10 @@ pub struct Cache { pub implementors: FnvHashMap>, /// Cache of where external crate documentation can be found. - pub extern_locations: FnvHashMap, + pub extern_locations: FnvHashMap, /// Cache of where documentation for primitives can be found. - pub primitive_locations: FnvHashMap, + pub primitive_locations: FnvHashMap, // Note that external items for which `doc(hidden)` applies to are shown as // non-reachable while local items aren't. This is because we're reusing diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 16a6e994b5a0..a29566f7a071 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -20,6 +20,7 @@ use syntax_pos::Span; use rustc::hir::map as hir_map; use rustc::hir::def::Def; +use rustc::hir::def_id::LOCAL_CRATE; use rustc::middle::privacy::AccessLevel; use rustc::util::nodemap::FnvHashSet; @@ -339,7 +340,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { let cstore = &self.cx.sess().cstore; om.extern_crates.push(ExternCrate { cnum: cstore.extern_mod_stmt_cnum(item.id) - .unwrap_or(ast::CrateNum::max_value()), + .unwrap_or(LOCAL_CRATE), name: name, path: p.map(|x|x.to_string()), vis: item.vis.clone(), diff --git a/src/librustdoc/visit_lib.rs b/src/librustdoc/visit_lib.rs index 3af030706b73..cbc556730fb6 100644 --- a/src/librustdoc/visit_lib.rs +++ b/src/librustdoc/visit_lib.rs @@ -11,9 +11,8 @@ use rustc::middle::cstore::{CrateStore, ChildItem, DefLike}; use rustc::middle::privacy::{AccessLevels, AccessLevel}; use rustc::hir::def::Def; -use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId}; +use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId}; use rustc::ty::Visibility; -use syntax::ast; use std::cell::RefMut; @@ -42,7 +41,7 @@ impl<'a, 'b, 'tcx> LibEmbargoVisitor<'a, 'b, 'tcx> { } } - pub fn visit_lib(&mut self, cnum: ast::CrateNum) { + pub fn visit_lib(&mut self, cnum: CrateNum) { let did = DefId { krate: cnum, index: CRATE_DEF_INDEX }; self.update(did, Some(AccessLevel::Public)); self.visit_mod(did); diff --git a/src/libserialize/lib.rs b/src/libserialize/lib.rs index ebd939120973..7082ee5d292d 100644 --- a/src/libserialize/lib.rs +++ b/src/libserialize/lib.rs @@ -45,8 +45,7 @@ Core encoding and decoding interfaces. extern crate rustc_unicode; extern crate collections; -pub use self::serialize::{Decoder, Encoder, Decodable, Encodable, - DecoderHelpers, EncoderHelpers}; +pub use self::serialize::{Decoder, Encoder, Decodable, Encodable}; pub use self::serialize::{SpecializationError, SpecializedEncoder, SpecializedDecoder}; pub use self::serialize::{UseSpecializedEncodable, UseSpecializedDecodable}; diff --git a/src/libserialize/serialize.rs b/src/libserialize/serialize.rs index 4414fee78788..ba6eefe82bbc 100644 --- a/src/libserialize/serialize.rs +++ b/src/libserialize/serialize.rs @@ -593,50 +593,6 @@ impl Decodable for Arc { } } -// ___________________________________________________________________________ -// Helper routines - -pub trait EncoderHelpers: Encoder { - fn emit_from_vec(&mut self, v: &[T], f: F) - -> Result<(), Self::Error> - where F: FnMut(&mut Self, &T) -> Result<(), Self::Error>; -} - -impl EncoderHelpers for S { - fn emit_from_vec(&mut self, v: &[T], mut f: F) -> Result<(), S::Error> where - F: FnMut(&mut S, &T) -> Result<(), S::Error>, - { - self.emit_seq(v.len(), |this| { - for (i, e) in v.iter().enumerate() { - this.emit_seq_elt(i, |this| { - f(this, e) - })?; - } - Ok(()) - }) - } -} - -pub trait DecoderHelpers: Decoder { - fn read_to_vec(&mut self, f: F) - -> Result, Self::Error> where - F: FnMut(&mut Self) -> Result; -} - -impl DecoderHelpers for D { - fn read_to_vec(&mut self, mut f: F) -> Result, D::Error> where F: - FnMut(&mut D) -> Result, - { - self.read_seq(|this, len| { - let mut v = Vec::with_capacity(len); - for i in 0..len { - v.push(this.read_seq_elt(i, |this| f(this))?); - } - Ok(v) - }) - } -} - // ___________________________________________________________________________ // Specialization-based interface for multi-dispatch Encodable/Decodable. diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 40c8ba93bd5d..70e614f9c9a9 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -27,7 +27,9 @@ use tokenstream::{TokenTree}; use std::fmt; use std::rc::Rc; -use serialize::{Encodable, Decodable, Encoder, Decoder}; +use std::u32; + +use serialize::{self, Encodable, Decodable, Encoder, Decoder}; /// A name is a part of an identifier, representing a string or gensym. It's /// the result of interning. @@ -298,17 +300,43 @@ pub struct ParenthesizedParameterData { pub output: Option>, } -pub type CrateNum = u32; +#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, RustcEncodable, Hash, Debug)] +pub struct NodeId(u32); -pub type NodeId = u32; +impl NodeId { + pub fn new(x: usize) -> NodeId { + assert!(x < (u32::MAX as usize)); + NodeId(x as u32) + } + + pub fn from_u32(x: u32) -> NodeId { + NodeId(x) + } + + pub fn as_usize(&self) -> usize { + self.0 as usize + } + + pub fn as_u32(&self) -> u32 { + self.0 + } +} + +impl fmt::Display for NodeId { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(&self.0, f) + } +} + +impl serialize::UseSpecializedDecodable for NodeId {} /// Node id used to represent the root of the crate. -pub const CRATE_NODE_ID: NodeId = 0; +pub const CRATE_NODE_ID: NodeId = NodeId(0); /// When parsing and doing expansions, we initially give all AST nodes this AST /// node value. Then later, in the renumber pass, we renumber them to have /// small, positive ids. -pub const DUMMY_NODE_ID: NodeId = !0; +pub const DUMMY_NODE_ID: NodeId = NodeId(!0); /// The AST represents all type param bounds as types. /// typeck::collect::compute_bounds matches these against diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index 81ee96459fd6..dc02c26039c1 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -895,7 +895,7 @@ pub fn find_repr_attrs(diagnostic: &Handler, attr: &Attribute) -> Vec "packed" => Some(ReprPacked), "simd" => Some(ReprSimd), _ => match int_type_of_word(word) { - Some(ity) => Some(ReprInt(item.span, ity)), + Some(ity) => Some(ReprInt(ity)), None => { // Not a word we recognize span_err!(diagnostic, item.span, E0552, @@ -939,7 +939,7 @@ fn int_type_of_word(s: &str) -> Option { #[derive(PartialEq, Debug, RustcEncodable, RustcDecodable, Copy, Clone)] pub enum ReprAttr { ReprAny, - ReprInt(Span, IntType), + ReprInt(IntType), ReprExtern, ReprPacked, ReprSimd, @@ -949,7 +949,7 @@ impl ReprAttr { pub fn is_ffi_safe(&self) -> bool { match *self { ReprAny => false, - ReprInt(_sp, ity) => ity.is_ffi_safe(), + ReprInt(ity) => ity.is_ffi_safe(), ReprExtern => true, ReprPacked => false, ReprSimd => true, diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 4e87d8ee9dda..db0183a8b3a2 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -242,11 +242,11 @@ impl<'a, 'b> MacroExpander<'a, 'b> { while let Some(expansions) = expansions.pop() { for (mark, expansion) in expansions.into_iter().rev() { let expansion = expansion.fold_with(&mut placeholder_expander); - placeholder_expander.add(mark, expansion); + placeholder_expander.add(ast::NodeId::from_u32(mark), expansion); } } - placeholder_expander.remove(0) + placeholder_expander.remove(ast::NodeId::from_u32(0)) } fn collect_invocations(&mut self, expansion: Expansion) -> (Expansion, Vec) { @@ -424,7 +424,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { expansion_kind: expansion_kind, expansion_data: ExpansionData { mark: mark, ..self.cx.current_expansion.clone() }, }); - placeholder(expansion_kind, mark.as_u32()) + placeholder(expansion_kind, ast::NodeId::from_u32(mark.as_u32())) } fn collect_bang( diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs index 4a2c9aff2d2b..118ceb17ab4a 100644 --- a/src/libsyntax/lib.rs +++ b/src/libsyntax/lib.rs @@ -33,6 +33,7 @@ #![feature(unicode)] #![feature(question_mark)] #![feature(rustc_diagnostic_macros)] +#![feature(specialization)] extern crate serialize; extern crate term; diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index 339a6c477ccd..e307925a6ed8 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -780,17 +780,17 @@ fn find_repr_type_name(diagnostic: &Handler, type_attrs: &[ast::Attribute]) -> & attr::ReprAny | attr::ReprPacked | attr::ReprSimd => continue, attr::ReprExtern => "i32", - attr::ReprInt(_, attr::SignedInt(ast::IntTy::Is)) => "isize", - attr::ReprInt(_, attr::SignedInt(ast::IntTy::I8)) => "i8", - attr::ReprInt(_, attr::SignedInt(ast::IntTy::I16)) => "i16", - attr::ReprInt(_, attr::SignedInt(ast::IntTy::I32)) => "i32", - attr::ReprInt(_, attr::SignedInt(ast::IntTy::I64)) => "i64", + attr::ReprInt(attr::SignedInt(ast::IntTy::Is)) => "isize", + attr::ReprInt(attr::SignedInt(ast::IntTy::I8)) => "i8", + attr::ReprInt(attr::SignedInt(ast::IntTy::I16)) => "i16", + attr::ReprInt(attr::SignedInt(ast::IntTy::I32)) => "i32", + attr::ReprInt(attr::SignedInt(ast::IntTy::I64)) => "i64", - attr::ReprInt(_, attr::UnsignedInt(ast::UintTy::Us)) => "usize", - attr::ReprInt(_, attr::UnsignedInt(ast::UintTy::U8)) => "u8", - attr::ReprInt(_, attr::UnsignedInt(ast::UintTy::U16)) => "u16", - attr::ReprInt(_, attr::UnsignedInt(ast::UintTy::U32)) => "u32", - attr::ReprInt(_, attr::UnsignedInt(ast::UintTy::U64)) => "u64", + attr::ReprInt(attr::UnsignedInt(ast::UintTy::Us)) => "usize", + attr::ReprInt(attr::UnsignedInt(ast::UintTy::U8)) => "u8", + attr::ReprInt(attr::UnsignedInt(ast::UintTy::U16)) => "u16", + attr::ReprInt(attr::UnsignedInt(ast::UintTy::U32)) => "u32", + attr::ReprInt(attr::UnsignedInt(ast::UintTy::U64)) => "u64", } } } diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index d835f8058fa0..fb59f4111067 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -28,6 +28,7 @@ #![feature(rustc_private)] #![feature(staged_api)] #![feature(question_mark)] +#![feature(specialization)] use std::cell::{Cell, RefCell}; use std::ops::{Add, Sub}; @@ -151,21 +152,7 @@ impl Encodable for Span { } } -impl Decodable for Span { - fn decode(d: &mut D) -> Result { - d.read_struct("Span", 2, |d| { - let lo = d.read_struct_field("lo", 0, |d| { - BytePos::decode(d) - })?; - - let hi = d.read_struct_field("hi", 1, |d| { - BytePos::decode(d) - })?; - - Ok(mk_sp(lo, hi)) - }) - } -} +impl serialize::UseSpecializedDecodable for Span {} fn default_span_debug(span: Span, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "Span {{ lo: {:?}, hi: {:?}, expn_id: {:?} }}", From 903ec52ba9172e38026fd6b833053e1a019fe68e Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Wed, 31 Aug 2016 14:08:22 +0300 Subject: [PATCH 412/443] rustc: replace uses of NodeId in Def, other than closures and labels. --- src/librustc/hir/def.rs | 25 ++--------- src/librustc/hir/lowering.rs | 4 +- src/librustc/middle/expr_use_visitor.rs | 5 ++- src/librustc/middle/liveness.rs | 9 ++-- src/librustc/middle/mem_categorization.rs | 6 ++- src/librustc/mir/repr.rs | 4 +- src/librustc/util/ppaux.rs | 3 +- src/librustc_const_eval/eval.rs | 3 +- src/librustc_metadata/astencode.rs | 3 +- src/librustc_mir/build/mod.rs | 5 ++- src/librustc_mir/hair/cx/expr.rs | 8 ++-- src/librustc_mir/hair/cx/pattern.rs | 3 +- src/librustc_resolve/lib.rs | 13 +++--- src/librustc_save_analysis/dump_visitor.rs | 3 +- src/librustc_typeck/astconv.rs | 21 +++------- src/librustc_typeck/check/_match.rs | 3 +- src/librustc_typeck/check/mod.rs | 3 +- src/librustc_typeck/check/upvar.rs | 48 +++++++++++----------- src/librustdoc/clean/mod.rs | 7 +--- 19 files changed, 81 insertions(+), 95 deletions(-) diff --git a/src/librustc/hir/def.rs b/src/librustc/hir/def.rs index a270be4f1dfd..b4418ed424ea 100644 --- a/src/librustc/hir/def.rs +++ b/src/librustc/hir/def.rs @@ -16,14 +16,13 @@ use hir; #[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub enum Def { Fn(DefId), - SelfTy(Option /* trait */, Option /* impl */), + SelfTy(Option /* trait */, Option /* impl */), Mod(DefId), ForeignMod(DefId), Static(DefId, bool /* is_mutbl */), Const(DefId), AssociatedConst(DefId), - Local(DefId, // def id of variable - ast::NodeId), // node id of variable + Local(DefId), Variant(DefId /* enum */, DefId /* variant */), Enum(DefId), TyAlias(DefId), @@ -32,7 +31,6 @@ pub enum Def { PrimTy(hir::PrimTy), TyParam(DefId), Upvar(DefId, // def id of closed over local - ast::NodeId, // node id of closed over local usize, // index in the freevars list of the closure ast::NodeId), // expr node that creates the closure @@ -101,30 +99,13 @@ pub struct Export { } impl Def { - pub fn var_id(&self) -> ast::NodeId { - match *self { - Def::Local(_, id) | - Def::Upvar(_, id, ..) => { - id - } - - Def::Fn(..) | Def::Mod(..) | Def::ForeignMod(..) | Def::Static(..) | - Def::Variant(..) | Def::Enum(..) | Def::TyAlias(..) | Def::AssociatedTy(..) | - Def::TyParam(..) | Def::Struct(..) | Def::Union(..) | Def::Trait(..) | - Def::Method(..) | Def::Const(..) | Def::AssociatedConst(..) | - Def::PrimTy(..) | Def::Label(..) | Def::SelfTy(..) | Def::Err => { - bug!("attempted .var_id() on invalid {:?}", self) - } - } - } - pub fn def_id(&self) -> DefId { match *self { Def::Fn(id) | Def::Mod(id) | Def::ForeignMod(id) | Def::Static(id, _) | Def::Variant(_, id) | Def::Enum(id) | Def::TyAlias(id) | Def::AssociatedTy(_, id) | Def::TyParam(id) | Def::Struct(id) | Def::Union(id) | Def::Trait(id) | Def::Method(id) | Def::Const(id) | Def::AssociatedConst(id) | - Def::Local(id, _) | Def::Upvar(id, ..) => { + Def::Local(id) | Def::Upvar(id, ..) => { id } diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 9f7400c983e5..37b5eac3ccee 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -1697,7 +1697,7 @@ impl<'a> LoweringContext<'a> { let def = { let defs = self.resolver.definitions(); - Def::Local(defs.local_def_id(binding), binding) + Def::Local(defs.local_def_id(binding)) }; self.resolver.record_resolution(expr.id, def); @@ -1850,7 +1850,7 @@ impl<'a> LoweringContext<'a> { let defs = self.resolver.definitions(); let def_path_data = DefPathData::Binding(name.as_str()); let def_index = defs.create_def_with_parent(parent_def, pat.id, def_path_data); - Def::Local(DefId::local(def_index), pat.id) + Def::Local(DefId::local(def_index)) }; self.resolver.record_resolution(pat.id, def); diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 9f05dde4e66f..ec3fe3903179 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -1029,7 +1029,8 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { self.tcx().with_freevars(closure_expr.id, |freevars| { for freevar in freevars { - let id_var = freevar.def.var_id(); + let def_id = freevar.def.def_id(); + let id_var = self.tcx().map.as_local_node_id(def_id).unwrap(); let upvar_id = ty::UpvarId { var_id: id_var, closure_expr_id: closure_expr.id }; let upvar_capture = self.mc.infcx.upvar_capture(upvar_id).unwrap(); @@ -1061,7 +1062,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { -> mc::McResult> { // Create the cmt for the variable being borrowed, from the // caller's perspective - let var_id = upvar_def.var_id(); + let var_id = self.tcx().map.as_local_node_id(upvar_def.def_id()).unwrap(); let var_ty = self.mc.infcx.node_ty(var_id)?; self.mc.cat_def(closure_id, closure_span, var_ty, upvar_def) } diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index b579c69cd05c..db9dd82d492d 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -465,7 +465,8 @@ fn visit_expr(ir: &mut IrMaps, expr: &Expr) { let mut call_caps = Vec::new(); ir.tcx.with_freevars(expr.id, |freevars| { for fv in freevars { - if let Def::Local(_, rv) = fv.def { + if let Def::Local(def_id) = fv.def { + let rv = ir.tcx.map.as_local_node_id(def_id).unwrap(); let fv_ln = ir.add_live_node(FreeVarNode(fv.span)); call_caps.push(CaptureInfo {ln: fv_ln, var_nid: rv}); @@ -1270,7 +1271,8 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { fn access_path(&mut self, expr: &Expr, succ: LiveNode, acc: u32) -> LiveNode { match self.ir.tcx.expect_def(expr.id) { - Def::Local(_, nid) => { + Def::Local(def_id) => { + let nid = self.ir.tcx.map.as_local_node_id(def_id).unwrap(); let ln = self.live_node(expr.id, expr.span); if acc != 0 { self.init_from_succ(ln, succ); @@ -1529,11 +1531,12 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { fn check_lvalue(&mut self, expr: &Expr) { match expr.node { hir::ExprPath(..) => { - if let Def::Local(_, nid) = self.ir.tcx.expect_def(expr.id) { + if let Def::Local(def_id) = self.ir.tcx.expect_def(expr.id) { // Assignment to an immutable variable or argument: only legal // if there is no later assignment. If this local is actually // mutable, then check for a reassignment to flag the mutability // as being used. + let nid = self.ir.tcx.map.as_local_node_id(def_id).unwrap(); let ln = self.live_node(expr.id, expr.span); let var = self.variable(nid, expr.span); self.warn_about_dead_assign(expr.span, expr.id, ln, var); diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index c419f96e8209..26cc6007ed07 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -549,7 +549,8 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { })) } - Def::Upvar(_, var_id, _, fn_node_id) => { + Def::Upvar(def_id, _, fn_node_id) => { + let var_id = self.tcx().map.as_local_node_id(def_id).unwrap(); let ty = self.node_ty(fn_node_id)?; match ty.sty { ty::TyClosure(closure_id, _) => { @@ -585,7 +586,8 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { } } - Def::Local(_, vid) => { + Def::Local(def_id) => { + let vid = self.tcx().map.as_local_node_id(def_id).unwrap(); Ok(Rc::new(cmt_ { id: id, span: span, diff --git a/src/librustc/mir/repr.rs b/src/librustc/mir/repr.rs index 53b6ccdbd530..1ffaf3c0ed5a 100644 --- a/src/librustc/mir/repr.rs +++ b/src/librustc/mir/repr.rs @@ -1098,7 +1098,9 @@ impl<'tcx> Debug for Rvalue<'tcx> { tcx.with_freevars(node_id, |freevars| { for (freevar, lv) in freevars.iter().zip(lvs) { - let var_name = tcx.local_var_name_str(freevar.def.var_id()); + let def_id = freevar.def.def_id(); + let var_id = tcx.map.as_local_node_id(def_id).unwrap(); + let var_name = tcx.local_var_name_str(var_id); struct_fmt.field(&var_name, lv); } }); diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 3b84ff86ab9f..1df0cf2d5cdf 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -920,7 +920,8 @@ impl<'tcx> fmt::Display for ty::TypeVariants<'tcx> { let mut sep = " "; tcx.with_freevars(node_id, |freevars| { for (freevar, upvar_ty) in freevars.iter().zip(substs.upvar_tys) { - let node_id = freevar.def.var_id(); + let def_id = freevar.def.def_id(); + let node_id = tcx.map.as_local_node_id(def_id).unwrap(); write!(f, "{}{}:{}", sep, diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index 4ced9d87f0a5..ede13aa4dc8b 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -824,7 +824,8 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, Def::Struct(..) => { ConstVal::Struct(e.id) } - Def::Local(_, id) => { + Def::Local(def_id) => { + let id = tcx.map.as_local_node_id(def_id).unwrap(); debug!("Def::Local({:?}): {:?}", id, fn_args); if let Some(val) = fn_args.and_then(|args| args.get(&id)) { val.clone() diff --git a/src/librustc_metadata/astencode.rs b/src/librustc_metadata/astencode.rs index 397b33178dce..2f845936a6c4 100644 --- a/src/librustc_metadata/astencode.rs +++ b/src/librustc_metadata/astencode.rs @@ -167,7 +167,8 @@ fn encode_side_tables_for_id(ecx: &mut EncodeContext, id: ast::NodeId) { ecx.tag(c::tag_table_upvar_capture_map, |ecx| { ecx.id(id); - let var_id = freevar.def.var_id(); + let def_id = freevar.def.def_id(); + let var_id = tcx.map.as_local_node_id(def_id).unwrap(); let upvar_id = ty::UpvarId { var_id: var_id, closure_expr_id: id diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index 59d6cf118596..23591f05b877 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -197,8 +197,9 @@ pub fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>, // Gather the upvars of a closure, if any. let upvar_decls: Vec<_> = tcx.with_freevars(fn_id, |freevars| { freevars.iter().map(|fv| { + let var_id = tcx.map.as_local_node_id(fv.def.def_id()).unwrap(); let by_ref = tcx.upvar_capture(ty::UpvarId { - var_id: fv.def.var_id(), + var_id: var_id, closure_expr_id: fn_id }).map_or(false, |capture| match capture { ty::UpvarCapture::ByValue => false, @@ -208,7 +209,7 @@ pub fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>, debug_name: keywords::Invalid.name(), by_ref: by_ref }; - if let Some(hir::map::NodeLocal(pat)) = tcx.map.find(fv.def.var_id()) { + if let Some(hir::map::NodeLocal(pat)) = tcx.map.find(var_id) { if let hir::PatKind::Binding(_, ref ident, _) = pat.node { decl.debug_name = ident.node; } diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 4518f8cb373f..248690befac0 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -729,13 +729,15 @@ fn convert_var<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, let temp_lifetime = cx.tcx.region_maps.temporary_scope(expr.id); match def { - Def::Local(_, node_id) => { + Def::Local(def_id) => { + let node_id = cx.tcx.map.as_local_node_id(def_id).unwrap(); ExprKind::VarRef { id: node_id, } } - Def::Upvar(_, id_var, index, closure_expr_id) => { + Def::Upvar(def_id, index, closure_expr_id) => { + let id_var = cx.tcx.map.as_local_node_id(def_id).unwrap(); debug!("convert_var(upvar({:?}, {:?}, {:?}))", id_var, index, closure_expr_id); let var_ty = cx.tcx.node_id_to_type(id_var); @@ -974,7 +976,7 @@ fn capture_freevar<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, freevar: &hir::Freevar, freevar_ty: Ty<'tcx>) -> ExprRef<'tcx> { - let id_var = freevar.def.var_id(); + let id_var = cx.tcx.map.as_local_node_id(freevar.def.def_id()).unwrap(); let upvar_id = ty::UpvarId { var_id: id_var, closure_expr_id: closure_expr.id, diff --git a/src/librustc_mir/hair/cx/pattern.rs b/src/librustc_mir/hair/cx/pattern.rs index 3639b165eb5a..2c946b078a2f 100644 --- a/src/librustc_mir/hair/cx/pattern.rs +++ b/src/librustc_mir/hair/cx/pattern.rs @@ -158,7 +158,8 @@ impl<'patcx, 'cx, 'gcx, 'tcx> PatCx<'patcx, 'cx, 'gcx, 'tcx> { } PatKind::Binding(bm, ref ident, ref sub) => { - let id = self.cx.tcx.expect_def(pat.id).var_id(); + let def_id = self.cx.tcx.expect_def(pat.id).def_id(); + let id = self.cx.tcx.map.as_local_node_id(def_id).unwrap(); let var_ty = self.cx.tcx.node_id_to_type(pat.id); let region = match var_ty.sty { ty::TyRef(r, _) => Some(r), diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 659edb86be16..5e78ac7ca94c 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1959,7 +1959,8 @@ impl<'a> Resolver<'a> { // Resolve the self type. this.visit_ty(self_type); - this.with_self_rib(Def::SelfTy(trait_id, Some(item_id)), |this| { + let item_def_id = this.definitions.local_def_id(item_id); + this.with_self_rib(Def::SelfTy(trait_id, Some(item_def_id)), |this| { this.with_current_self_type(self_type, |this| { for impl_item in impl_items { this.resolve_visibility(&impl_item.vis); @@ -2243,7 +2244,7 @@ impl<'a> Resolver<'a> { // must not add it if it's in the bindings map // because that breaks the assumptions later // passes make about or-patterns.) - let mut def = Def::Local(self.definitions.local_def_id(pat_id), pat_id); + let mut def = Def::Local(self.definitions.local_def_id(pat_id)); match bindings.get(&ident.node).cloned() { Some(id) if id == outer_pat_id => { // `Variant(a, a)`, error @@ -2559,7 +2560,7 @@ impl<'a> Resolver<'a> { Def::Upvar(..) => { span_bug!(span, "unexpected {:?} in bindings", def) } - Def::Local(_, node_id) => { + Def::Local(def_id) => { for rib in ribs { match rib.kind { NormalRibKind | ModuleRibKind(..) | MacroDefinition(..) => { @@ -2567,13 +2568,13 @@ impl<'a> Resolver<'a> { } ClosureRibKind(function_id) => { let prev_def = def; - let node_def_id = self.definitions.local_def_id(node_id); + let node_id = self.definitions.as_local_node_id(def_id).unwrap(); let seen = self.freevars_seen .entry(function_id) .or_insert_with(|| NodeMap()); if let Some(&index) = seen.get(&node_id) { - def = Def::Upvar(node_def_id, node_id, index, function_id); + def = Def::Upvar(def_id, index, function_id); continue; } let vec = self.freevars @@ -2585,7 +2586,7 @@ impl<'a> Resolver<'a> { span: span, }); - def = Def::Upvar(node_def_id, node_id, depth, function_id); + def = Def::Upvar(def_id, depth, function_id); seen.insert(node_id, depth); } ItemRibKind | MethodRibKind(_) => { diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 37b31eda5a35..2cbc110c56af 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -1456,7 +1456,8 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor for DumpVisitor<'l, 'tcx, 'll, D> // process collected paths for &(id, ref p, immut, ref_kind) in &collector.collected_paths { match self.tcx.expect_def(id) { - Def::Local(_, id) => { + Def::Local(def_id) => { + let id = self.tcx.map.as_local_node_id(def_id).unwrap(); let mut value = if immut == ast::Mutability::Immutable { self.span.snippet(p.span).to_string() } else { diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 334b7a5063a3..675c863a3bf0 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1284,23 +1284,17 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { // Find the type of the associated item, and the trait where the associated // item is declared. let bound = match (&ty.sty, ty_path_def) { - (_, Def::SelfTy(Some(trait_did), Some(impl_id))) => { - // For Def::SelfTy() values inlined from another crate, the - // impl_id will be DUMMY_NODE_ID, which would cause problems - // here. But we should never run into an impl from another crate - // in this pass. - assert!(impl_id != ast::DUMMY_NODE_ID); - + (_, Def::SelfTy(Some(_), Some(impl_def_id))) => { // `Self` in an impl of a trait - we have a concrete self type and a // trait reference. - let trait_ref = tcx.impl_trait_ref(tcx.map.local_def_id(impl_id)).unwrap(); + let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap(); let trait_ref = if let Some(free_substs) = self.get_free_substs() { trait_ref.subst(tcx, free_substs) } else { trait_ref }; - if self.ensure_super_predicates(span, trait_did).is_err() { + if self.ensure_super_predicates(span, trait_ref.def_id).is_err() { return (tcx.types.err, Def::Err); } @@ -1504,16 +1498,11 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { tcx.types.err } } - Def::SelfTy(_, Some(impl_id)) => { + Def::SelfTy(_, Some(def_id)) => { // Self in impl (we know the concrete type). - // For Def::SelfTy() values inlined from another crate, the - // impl_id will be DUMMY_NODE_ID, which would cause problems - // here. But we should never run into an impl from another crate - // in this pass. - assert!(impl_id != ast::DUMMY_NODE_ID); - tcx.prohibit_type_params(base_segments); + let impl_id = tcx.map.as_local_node_id(def_id).unwrap(); let ty = tcx.node_id_to_type(impl_id); if let Some(free_substs) = self.get_free_substs() { ty.subst(tcx, free_substs) diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index dd3ac6ff2d45..de7ca479b0b6 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -134,7 +134,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // what the type of the binding `x` ought to be match tcx.expect_def(pat.id) { Def::Err => {} - Def::Local(_, var_id) => { + Def::Local(def_id) => { + let var_id = tcx.map.as_local_node_id(def_id).unwrap(); if var_id != pat.id { let vt = self.local_ty(pat.span, var_id); self.demand_eqtype(pat.span, vt, typ); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 01d7b1e54751..8d9fd523a8f5 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -4188,7 +4188,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.tcx.prohibit_type_params(&segments[..segments.len() - poly_segments]); match def { - Def::Local(_, nid) | Def::Upvar(_, nid, ..) => { + Def::Local(def_id) | Def::Upvar(def_id, ..) => { + let nid = self.tcx.map.as_local_node_id(def_id).unwrap(); let ty = self.local_ty(span, nid); let ty = self.normalize_associated_types_in(span, &ty); self.write_ty(node_id, ty); diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs index f4a0df4611d3..aa221c33b5dd 100644 --- a/src/librustc_typeck/check/upvar.rs +++ b/src/librustc_typeck/check/upvar.rs @@ -120,7 +120,8 @@ impl<'a, 'gcx, 'tcx> SeedBorrowKind<'a, 'gcx, 'tcx> { self.fcx.tcx.with_freevars(expr.id, |freevars| { for freevar in freevars { - let var_node_id = freevar.def.var_id(); + let def_id = freevar.def.def_id(); + let var_node_id = self.fcx.tcx.map.as_local_node_id(def_id).unwrap(); let upvar_id = ty::UpvarId { var_id: var_node_id, closure_expr_id: expr.id }; debug!("seed upvar_id {:?}", upvar_id); @@ -236,31 +237,30 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { // implemented. let tcx = self.fcx.tcx; tcx.with_freevars(closure_id, |freevars| { - freevars.iter() - .map(|freevar| { - let freevar_node_id = freevar.def.var_id(); - let freevar_ty = self.fcx.node_ty(freevar_node_id); - let upvar_id = ty::UpvarId { - var_id: freevar_node_id, - closure_expr_id: closure_id - }; - let capture = self.fcx.upvar_capture(upvar_id).unwrap(); + freevars.iter().map(|freevar| { + let def_id = freevar.def.def_id(); + let var_id = tcx.map.as_local_node_id(def_id).unwrap(); + let freevar_ty = self.fcx.node_ty(var_id); + let upvar_id = ty::UpvarId { + var_id: var_id, + closure_expr_id: closure_id + }; + let capture = self.fcx.upvar_capture(upvar_id).unwrap(); - debug!("freevar_node_id={:?} freevar_ty={:?} capture={:?}", - freevar_node_id, freevar_ty, capture); + debug!("var_id={:?} freevar_ty={:?} capture={:?}", + var_id, freevar_ty, capture); - match capture { - ty::UpvarCapture::ByValue => freevar_ty, - ty::UpvarCapture::ByRef(borrow) => - tcx.mk_ref(borrow.region, - ty::TypeAndMut { - ty: freevar_ty, - mutbl: borrow.kind.to_mutbl_lossy(), - }), - } - }) - .collect() - }) + match capture { + ty::UpvarCapture::ByValue => freevar_ty, + ty::UpvarCapture::ByRef(borrow) => + tcx.mk_ref(borrow.region, + ty::TypeAndMut { + ty: freevar_ty, + mutbl: borrow.kind.to_mutbl_lossy(), + }), + } + }).collect() + }) } fn adjust_upvar_borrow_kind_for_consume(&mut self, diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 7ee173019a51..3983c098f306 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2790,11 +2790,8 @@ fn register_def(cx: &DocContext, def: Def) -> DefId { Def::Static(i, _) => (i, TypeStatic), Def::Variant(i, _) => (i, TypeEnum), Def::SelfTy(Some(def_id), _) => (def_id, TypeTrait), - Def::SelfTy(_, Some(impl_id)) => { - // For Def::SelfTy() values inlined from another crate, the - // impl_id will be DUMMY_NODE_ID, which would cause problems. - // But we should never run into an impl from another crate here. - return cx.map.local_def_id(impl_id) + Def::SelfTy(_, Some(impl_def_id)) => { + return impl_def_id } _ => return def.def_id() }; From ed593bed882e1ad6bc7ff6a3b3b6730176b5536b Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Thu, 1 Sep 2016 06:19:58 +0300 Subject: [PATCH 413/443] rustc_metadata: go back to not using the opaque format. --- src/librustc_metadata/astencode.rs | 222 ++++++++++++--------------- src/librustc_metadata/common.rs | 21 +-- src/librustc_metadata/decoder.rs | 96 ++++++------ src/librustc_metadata/encoder.rs | 18 +-- src/librustc_metadata/rbml/reader.rs | 5 - src/librustc_metadata/rbml/writer.rs | 6 +- 6 files changed, 165 insertions(+), 203 deletions(-) diff --git a/src/librustc_metadata/astencode.rs b/src/librustc_metadata/astencode.rs index 2f845936a6c4..ce15ec6a29d2 100644 --- a/src/librustc_metadata/astencode.rs +++ b/src/librustc_metadata/astencode.rs @@ -14,9 +14,7 @@ use rustc::hir::map as ast_map; use rustc::hir::intravisit::{Visitor, IdRangeComputingVisitor, IdRange}; -use common as c; -use cstore; - +use cstore::CrateMetadata; use decoder::DecodeContext; use encoder::EncodeContext; @@ -28,7 +26,6 @@ use rustc::ty::{self, TyCtxt}; use syntax::ast; -use rbml::reader; use rbml; use rustc_serialize::{Decodable, Encodable}; @@ -36,35 +33,31 @@ use rustc_serialize::{Decodable, Encodable}; // Top-level methods. pub fn encode_inlined_item(ecx: &mut EncodeContext, ii: InlinedItemRef) { - ecx.tag(c::tag_ast, |ecx| { - ecx.tag(c::tag_id_range, |ecx| { - let mut visitor = IdRangeComputingVisitor::new(); - match ii { - InlinedItemRef::Item(_, i) => visitor.visit_item(i), - InlinedItemRef::TraitItem(_, ti) => visitor.visit_trait_item(ti), - InlinedItemRef::ImplItem(_, ii) => visitor.visit_impl_item(ii) - } - visitor.result().encode(&mut ecx.opaque()).unwrap() - }); + ecx.tag(::common::tag_ast, |ecx| { + let mut visitor = IdRangeComputingVisitor::new(); + match ii { + InlinedItemRef::Item(_, i) => visitor.visit_item(i), + InlinedItemRef::TraitItem(_, ti) => visitor.visit_trait_item(ti), + InlinedItemRef::ImplItem(_, ii) => visitor.visit_impl_item(ii) + } + visitor.result().encode(ecx).unwrap(); - ecx.tag(c::tag_tree, |ecx| ii.encode(ecx).unwrap()); + ii.encode(ecx).unwrap(); - ecx.tag(c::tag_table, |ecx| { - let mut visitor = SideTableEncodingIdVisitor { - ecx: ecx - }; - match ii { - InlinedItemRef::Item(_, i) => visitor.visit_item(i), - InlinedItemRef::TraitItem(_, ti) => visitor.visit_trait_item(ti), - InlinedItemRef::ImplItem(_, ii) => visitor.visit_impl_item(ii) - } - }); + let mut visitor = SideTableEncodingIdVisitor { + ecx: ecx + }; + match ii { + InlinedItemRef::Item(_, i) => visitor.visit_item(i), + InlinedItemRef::TraitItem(_, ti) => visitor.visit_trait_item(ti), + InlinedItemRef::ImplItem(_, ii) => visitor.visit_impl_item(ii) + } }); } /// Decodes an item from its AST in the cdata's metadata and adds it to the /// ast-map. -pub fn decode_inlined_item<'a, 'tcx>(cdata: &cstore::CrateMetadata, +pub fn decode_inlined_item<'a, 'tcx>(cdata: &CrateMetadata, tcx: TyCtxt<'a, 'tcx, 'tcx>, parent_def_path: ast_map::DefPath, parent_did: DefId, @@ -72,16 +65,14 @@ pub fn decode_inlined_item<'a, 'tcx>(cdata: &cstore::CrateMetadata, orig_did: DefId) -> &'tcx InlinedItem { debug!("> Decoding inlined fn: {:?}", tcx.item_path_str(orig_did)); - let from_id_range = { - let decoder = &mut ast_doc.get(c::tag_id_range).opaque(); - IdRange { - min: ast::NodeId::from_u32(u32::decode(decoder).unwrap()), - max: ast::NodeId::from_u32(u32::decode(decoder).unwrap()) - } - }; - let mut dcx = DecodeContext::new(tcx, cdata, from_id_range, - ast_doc.get(c::tag_tree)); - let ii = InlinedItem::decode(&mut dcx).unwrap(); + let dcx = &mut ast_doc.decoder(); + dcx.tcx = Some(tcx); + dcx.cdata = Some(cdata); + dcx.from_id_range = IdRange::decode(dcx).unwrap(); + let cnt = dcx.from_id_range.max.as_usize() - dcx.from_id_range.min.as_usize(); + dcx.to_id_range.min = tcx.sess.reserve_node_ids(cnt); + dcx.to_id_range.max = ast::NodeId::new(dcx.to_id_range.min.as_usize() + cnt); + let ii = InlinedItem::decode(dcx).unwrap(); let ii = ast_map::map_decoded_item(&tcx.map, parent_def_path, @@ -97,7 +88,7 @@ pub fn decode_inlined_item<'a, 'tcx>(cdata: &cstore::CrateMetadata, let inlined_did = tcx.map.local_def_id(item_node_id); tcx.register_item_type(inlined_did, tcx.lookup_item_type(orig_did)); - decode_side_tables(&mut dcx, ast_doc); + decode_side_tables(dcx, ast_doc); ii } @@ -116,7 +107,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.end_tag().unwrap(); } - fn id(&mut self, id: ast::NodeId) { + fn entry(&mut self, table: Table, id: ast::NodeId) { + table.encode(self).unwrap(); id.encode(self).unwrap(); } } @@ -131,67 +123,67 @@ impl<'a, 'b, 'tcx, 'v> Visitor<'v> for SideTableEncodingIdVisitor<'a, 'b, 'tcx> } } +#[derive(RustcEncodable, RustcDecodable, Debug)] +enum Table { + Def, + NodeType, + ItemSubsts, + Freevars, + MethodMap, + Adjustment, + UpvarCaptureMap, + ConstQualif, + CastKind +} + fn encode_side_tables_for_id(ecx: &mut EncodeContext, id: ast::NodeId) { let tcx = ecx.tcx; debug!("Encoding side tables for id {}", id); if let Some(def) = tcx.expect_def_or_none(id) { - ecx.tag(c::tag_table_def, |ecx| { - ecx.id(id); - def.encode(ecx).unwrap(); - }) + ecx.entry(Table::Def, id); + def.encode(ecx).unwrap(); } if let Some(ty) = tcx.node_types().get(&id) { - ecx.tag(c::tag_table_node_type, |ecx| { - ecx.id(id); - ty.encode(ecx).unwrap(); - }) + ecx.entry(Table::NodeType, id); + ty.encode(ecx).unwrap(); } if let Some(item_substs) = tcx.tables.borrow().item_substs.get(&id) { - ecx.tag(c::tag_table_item_subst, |ecx| { - ecx.id(id); - item_substs.substs.encode(ecx).unwrap(); - }) + ecx.entry(Table::ItemSubsts, id); + item_substs.substs.encode(ecx).unwrap(); } if let Some(fv) = tcx.freevars.borrow().get(&id) { - ecx.tag(c::tag_table_freevars, |ecx| { - ecx.id(id); - fv.encode(ecx).unwrap(); - }); + ecx.entry(Table::Freevars, id); + fv.encode(ecx).unwrap(); for freevar in fv { - ecx.tag(c::tag_table_upvar_capture_map, |ecx| { - ecx.id(id); - - let def_id = freevar.def.def_id(); - let var_id = tcx.map.as_local_node_id(def_id).unwrap(); - let upvar_id = ty::UpvarId { - var_id: var_id, - closure_expr_id: id - }; - let upvar_capture = tcx.tables - .borrow() - .upvar_capture_map - .get(&upvar_id) - .unwrap() - .clone(); - var_id.encode(ecx).unwrap(); - upvar_capture.encode(ecx).unwrap(); - }) + ecx.entry(Table::UpvarCaptureMap, id); + let def_id = freevar.def.def_id(); + let var_id = tcx.map.as_local_node_id(def_id).unwrap(); + let upvar_id = ty::UpvarId { + var_id: var_id, + closure_expr_id: id + }; + let upvar_capture = tcx.tables + .borrow() + .upvar_capture_map + .get(&upvar_id) + .unwrap() + .clone(); + var_id.encode(ecx).unwrap(); + upvar_capture.encode(ecx).unwrap(); } } let method_call = ty::MethodCall::expr(id); if let Some(method) = tcx.tables.borrow().method_map.get(&method_call) { - ecx.tag(c::tag_table_method_map, |ecx| { - ecx.id(id); - method_call.autoderef.encode(ecx).unwrap(); - method.encode(ecx).unwrap(); - }) + ecx.entry(Table::MethodMap, id); + method_call.autoderef.encode(ecx).unwrap(); + method.encode(ecx).unwrap(); } if let Some(adjustment) = tcx.tables.borrow().adjustments.get(&id) { @@ -200,91 +192,79 @@ fn encode_side_tables_for_id(ecx: &mut EncodeContext, id: ast::NodeId) { for autoderef in 0..adj.autoderefs { let method_call = ty::MethodCall::autoderef(id, autoderef as u32); if let Some(method) = tcx.tables.borrow().method_map.get(&method_call) { - ecx.tag(c::tag_table_method_map, |ecx| { - ecx.id(id); - method_call.autoderef.encode(ecx).unwrap(); - method.encode(ecx).unwrap(); - }) + ecx.entry(Table::MethodMap, id); + method_call.autoderef.encode(ecx).unwrap(); + method.encode(ecx).unwrap(); } } } _ => {} } - ecx.tag(c::tag_table_adjustments, |ecx| { - ecx.id(id); - adjustment.encode(ecx).unwrap(); - }) + ecx.entry(Table::Adjustment, id); + adjustment.encode(ecx).unwrap(); } if let Some(cast_kind) = tcx.cast_kinds.borrow().get(&id) { - ecx.tag(c::tag_table_cast_kinds, |ecx| { - ecx.id(id); - cast_kind.encode(ecx).unwrap() - }) + ecx.entry(Table::CastKind, id); + cast_kind.encode(ecx).unwrap(); } if let Some(qualif) = tcx.const_qualif_map.borrow().get(&id) { - ecx.tag(c::tag_table_const_qualif, |ecx| { - ecx.id(id); - qualif.encode(ecx).unwrap() - }) + ecx.entry(Table::ConstQualif, id); + qualif.encode(ecx).unwrap(); } } -fn decode_side_tables<'a, 'tcx>(dcx: &mut DecodeContext<'a, 'tcx>, - ast_doc: rbml::Doc<'a>) { - for (tag, entry_doc) in reader::docs(ast_doc.get(c::tag_table)) { - dcx.rbml_r = reader::Decoder::new(entry_doc); +fn decode_side_tables(dcx: &mut DecodeContext, ast_doc: rbml::Doc) { + while dcx.position() < ast_doc.end { + let table = Decodable::decode(dcx).unwrap(); let id = Decodable::decode(dcx).unwrap(); - debug!("decode_side_tables: entry for id={}, tag=0x{:x}", id, tag); - match tag { - c::tag_table_def => { + debug!("decode_side_tables: entry for id={}, table={:?}", id, table); + match table { + Table::Def => { let def = Decodable::decode(dcx).unwrap(); - dcx.tcx.def_map.borrow_mut().insert(id, def::PathResolution::new(def)); + dcx.tcx().def_map.borrow_mut().insert(id, def::PathResolution::new(def)); } - c::tag_table_node_type => { + Table::NodeType => { let ty = Decodable::decode(dcx).unwrap(); - dcx.tcx.node_type_insert(id, ty); + dcx.tcx().node_type_insert(id, ty); } - c::tag_table_item_subst => { + Table::ItemSubsts => { let item_substs = Decodable::decode(dcx).unwrap(); - dcx.tcx.tables.borrow_mut().item_substs.insert(id, item_substs); + dcx.tcx().tables.borrow_mut().item_substs.insert(id, item_substs); } - c::tag_table_freevars => { + Table::Freevars => { let fv_info = Decodable::decode(dcx).unwrap(); - dcx.tcx.freevars.borrow_mut().insert(id, fv_info); + dcx.tcx().freevars.borrow_mut().insert(id, fv_info); } - c::tag_table_upvar_capture_map => { + Table::UpvarCaptureMap => { let upvar_id = ty::UpvarId { var_id: Decodable::decode(dcx).unwrap(), closure_expr_id: id }; let ub = Decodable::decode(dcx).unwrap(); - dcx.tcx.tables.borrow_mut().upvar_capture_map.insert(upvar_id, ub); + dcx.tcx().tables.borrow_mut().upvar_capture_map.insert(upvar_id, ub); } - c::tag_table_method_map => { + Table::MethodMap => { let method_call = ty::MethodCall { expr_id: id, autoderef: Decodable::decode(dcx).unwrap() }; let method = Decodable::decode(dcx).unwrap(); - dcx.tcx.tables.borrow_mut().method_map.insert(method_call, method); + dcx.tcx().tables.borrow_mut().method_map.insert(method_call, method); } - c::tag_table_adjustments => { + Table::Adjustment => { let adj = Decodable::decode(dcx).unwrap(); - dcx.tcx.tables.borrow_mut().adjustments.insert(id, adj); + dcx.tcx().tables.borrow_mut().adjustments.insert(id, adj); } - c::tag_table_cast_kinds => { + Table::CastKind => { let cast_kind = Decodable::decode(dcx).unwrap(); - dcx.tcx.cast_kinds.borrow_mut().insert(id, cast_kind); + dcx.tcx().cast_kinds.borrow_mut().insert(id, cast_kind); } - c::tag_table_const_qualif => { + Table::ConstQualif => { let qualif = Decodable::decode(dcx).unwrap(); - dcx.tcx.const_qualif_map.borrow_mut().insert(id, qualif); - } - _ => { - bug!("unknown tag found in side tables: 0x{:x}", tag); + dcx.tcx().const_qualif_map.borrow_mut().insert(id, qualif); } } } diff --git a/src/librustc_metadata/common.rs b/src/librustc_metadata/common.rs index c18b417466f9..512f4ca6584c 100644 --- a/src/librustc_metadata/common.rs +++ b/src/librustc_metadata/common.rs @@ -97,28 +97,11 @@ pub const tag_items_data_item_reexport_name: usize = 0x48; // used to encode crate_ctxt side tables pub const tag_ast: usize = 0x50; -pub const tag_tree: usize = 0x51; +// GAP 0x51 pub const tag_mir: usize = 0x52; -pub const tag_table: usize = 0x53; - -pub const tag_id_range: usize = 0x54; - -// GAP 0x55 -pub const tag_table_def: usize = 0x56; -pub const tag_table_node_type: usize = 0x57; -pub const tag_table_item_subst: usize = 0x58; -pub const tag_table_freevars: usize = 0x59; -// GAP 0x5a, 0x5b, 0x5c, 0x5d, 0x5e -pub const tag_table_method_map: usize = 0x5f; -// GAP 0x60 -pub const tag_table_adjustments: usize = 0x61; -// GAP 0x62, 0x63, 0x64, 0x65 -pub const tag_table_upvar_capture_map: usize = 0x66; -// GAP 0x67, 0x68 -pub const tag_table_const_qualif: usize = 0x69; -pub const tag_table_cast_kinds: usize = 0x6a; +// GAP 0x53...0x6a pub const tag_item_trait_item_sort: usize = 0x70; diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 72e95804ce8e..1bec365e472b 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -48,6 +48,7 @@ use std::io; use std::ops::{Deref, DerefMut}; use std::rc::Rc; use std::str; +use std::u32; use rbml::reader; use rbml; @@ -59,48 +60,48 @@ use syntax::print::pprust; use syntax_pos::{self, Span, BytePos, NO_EXPANSION}; pub struct DecodeContext<'a, 'tcx: 'a> { - pub rbml_r: rbml::reader::Decoder<'a>, - pub tcx: TyCtxt<'a, 'tcx, 'tcx>, - pub cdata: &'a cstore::CrateMetadata, - from_id_range: IdRange, - to_id_range: IdRange, + rbml_r: rbml::reader::Decoder<'a>, + pub tcx: Option>, + pub cdata: Option<&'a cstore::CrateMetadata>, + pub from_id_range: IdRange, + pub to_id_range: IdRange, // Cache the last used filemap for translating spans as an optimization. last_filemap_index: usize, } -impl<'a, 'tcx> DecodeContext<'a, 'tcx> { - pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, - cdata: &'a cstore::CrateMetadata, - from_id_range: IdRange, - doc: rbml::Doc<'a>) - -> DecodeContext<'a, 'tcx> { - // Handle the case of an empty range: - let to_id_range = if from_id_range.empty() { - from_id_range - } else { - let cnt = from_id_range.max.as_usize() - from_id_range.min.as_usize(); - let to_id_min = tcx.sess.reserve_node_ids(cnt); - let to_id_max = NodeId::new(to_id_min.as_usize() + cnt); - IdRange { min: to_id_min, max: to_id_max } +impl<'doc> rbml::Doc<'doc> { + pub fn decoder<'tcx>(self) -> DecodeContext<'doc, 'tcx> { + let id_range = IdRange { + min: NodeId::from_u32(u32::MIN), + max: NodeId::from_u32(u32::MAX) }; - DecodeContext { - rbml_r: reader::Decoder::new(doc), - cdata: cdata, - tcx: tcx, - from_id_range: from_id_range, - to_id_range: to_id_range, + rbml_r: reader::Decoder::new(self), + cdata: None, + tcx: None, + from_id_range: id_range, + to_id_range: id_range, last_filemap_index: 0 } } +} + +impl<'a, 'tcx> DecodeContext<'a, 'tcx> { + pub fn tcx(&self) -> TyCtxt<'a, 'tcx, 'tcx> { + self.tcx.expect("missing TyCtxt in DecodeContext") + } + + pub fn cdata(&self) -> &'a cstore::CrateMetadata { + self.cdata.expect("missing CrateMetadata in DecodeContext") + } fn read_ty_encoded(&mut self, op: F) -> R where F: for<'x> FnOnce(&mut TyDecoder<'x,'tcx>) -> R { self.read_opaque(|this, doc| { Ok(op(&mut TyDecoder::with_doc( - this.tcx, this.cdata.cnum, doc, - &mut |d| translate_def_id(&this.cdata, d)))) + this.tcx(), this.cdata().cnum, doc, + &mut |d| translate_def_id(this.cdata(), d)))) }).unwrap() } } @@ -142,9 +143,9 @@ impl<'a, 'tcx> SpecializedDecoder for DecodeContext<'a, 'tcx> { fn specialized_decode(&mut self) -> Result { let cnum = CrateNum::from_u32(u32::decode(self)?); if cnum == LOCAL_CRATE { - Ok(self.cdata.cnum) + Ok(self.cdata().cnum) } else { - Ok(self.cdata.cnum_map.borrow()[cnum]) + Ok(self.cdata().cnum_map.borrow()[cnum]) } } } @@ -154,6 +155,12 @@ impl<'a, 'tcx> SpecializedDecoder for DecodeContext<'a, 'tcx> { let lo = BytePos::decode(self)?; let hi = BytePos::decode(self)?; + let tcx = if let Some(tcx) = self.tcx { + tcx + } else { + return Ok(syntax_pos::mk_sp(lo, hi)); + }; + let (lo, hi) = if lo > hi { // Currently macro expansion sometimes produces invalid Span values // where lo > hi. In order not to crash the compiler when trying to @@ -167,7 +174,7 @@ impl<'a, 'tcx> SpecializedDecoder for DecodeContext<'a, 'tcx> { (lo, hi) }; - let imported_filemaps = self.cdata.imported_filemaps(&self.tcx.sess.codemap()); + let imported_filemaps = self.cdata().imported_filemaps(&tcx.sess.codemap()); let filemap = { // Optimize for the case that most spans within a translated item // originate from the same filemap. @@ -224,7 +231,7 @@ impl<'a, 'tcx> SpecializedDecoder<&'tcx Substs<'tcx>> for DecodeContext<'a, 'tcx impl<'a, 'tcx> SpecializedDecoder<&'tcx ty::Region> for DecodeContext<'a, 'tcx> { fn specialized_decode(&mut self) -> Result<&'tcx ty::Region, Self::Error> { let r = ty::Region::decode(self)?; - Ok(self.tcx.mk_region(r)) + Ok(self.tcx().mk_region(r)) } } @@ -232,7 +239,7 @@ impl<'a, 'tcx> SpecializedDecoder> for DecodeContext<'a, fn specialized_decode(&mut self) -> Result, Self::Error> { Ok(ty::ClosureSubsts { func_substs: Decodable::decode(self)?, - upvar_tys: self.tcx.mk_type_list(Decodable::decode(self)?) + upvar_tys: self.tcx().mk_type_list(Decodable::decode(self)?) }) } } @@ -240,7 +247,7 @@ impl<'a, 'tcx> SpecializedDecoder> for DecodeContext<'a, impl<'a, 'tcx> SpecializedDecoder> for DecodeContext<'a, 'tcx> { fn specialized_decode(&mut self) -> Result, Self::Error> { let def_id = DefId::decode(self)?; - Ok(self.tcx.lookup_adt_def(def_id)) + Ok(self.tcx().lookup_adt_def(def_id)) } } @@ -739,14 +746,14 @@ pub fn get_type<'a, 'tcx>(cdata: Cmd, id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>) pub fn get_stability(cdata: Cmd, id: DefIndex) -> Option { let item = cdata.lookup_item(id); reader::maybe_get_doc(item, tag_items_data_item_stability).map(|doc| { - Decodable::decode(&mut doc.opaque()).unwrap() + Decodable::decode(&mut doc.decoder()).unwrap() }) } pub fn get_deprecation(cdata: Cmd, id: DefIndex) -> Option { let item = cdata.lookup_item(id); reader::maybe_get_doc(item, tag_items_data_item_deprecation).map(|doc| { - Decodable::decode(&mut doc.opaque()).unwrap() + Decodable::decode(&mut doc.decoder()).unwrap() }) } @@ -764,7 +771,7 @@ pub fn get_parent_impl(cdata: Cmd, id: DefIndex) -> Option { pub fn get_repr_attrs(cdata: Cmd, id: DefIndex) -> Vec { let item = cdata.lookup_item(id); reader::maybe_get_doc(item, tag_items_data_item_repr).map_or(vec![], |doc| { - Decodable::decode(&mut doc.opaque()).unwrap() + Decodable::decode(&mut doc.decoder()).unwrap() }) } @@ -786,7 +793,7 @@ pub fn get_custom_coerce_unsized_kind( { let item_doc = cdata.lookup_item(id); reader::maybe_get_doc(item_doc, tag_impl_coerce_unsized_kind).map(|kind_doc| { - Decodable::decode(&mut kind_doc.opaque()).unwrap() + Decodable::decode(&mut kind_doc.decoder()).unwrap() }) } @@ -982,8 +989,9 @@ pub fn maybe_get_item_mir<'a, 'tcx>(cdata: Cmd, let item_doc = cdata.lookup_item(id); reader::maybe_get_doc(item_doc, tag_mir).map(|mir_doc| { - let id_range = IdRange { min: NodeId::new(0), max: NodeId::new(0) }; - let mut dcx = DecodeContext::new(tcx, cdata, id_range, mir_doc); + let mut dcx = mir_doc.decoder(); + dcx.tcx = Some(tcx); + dcx.cdata = Some(cdata); Decodable::decode(&mut dcx).unwrap() }) } @@ -1123,7 +1131,7 @@ pub fn get_trait_item_def_ids(cdata: Cmd, id: DefIndex) pub fn get_item_variances(cdata: Cmd, id: DefIndex) -> Vec { let item_doc = cdata.lookup_item(id); let variance_doc = reader::get_doc(item_doc, tag_item_variances); - Decodable::decode(&mut variance_doc.opaque()).unwrap() + Decodable::decode(&mut variance_doc.decoder()).unwrap() } pub fn get_provided_trait_methods<'a, 'tcx>(cdata: Cmd, @@ -1242,7 +1250,7 @@ pub fn get_struct_field_names(cdata: Cmd, id: DefIndex) -> Vec { fn get_attributes(md: rbml::Doc) -> Vec { reader::maybe_get_doc(md, tag_attributes).map_or(vec![], |attrs_doc| { - let mut attrs = Vec::::decode(&mut attrs_doc.opaque()).unwrap(); + let mut attrs = Vec::::decode(&mut attrs_doc.decoder()).unwrap(); // Need new unique IDs: old thread-local IDs won't map to new threads. for attr in attrs.iter_mut() { @@ -1647,14 +1655,14 @@ pub fn get_imported_filemaps(metadata: &[u8]) -> Vec { let cm_doc = reader::get_doc(crate_doc, tag_codemap); reader::tagged_docs(cm_doc, tag_codemap_filemap).map(|filemap_doc| { - Decodable::decode(&mut filemap_doc.opaque()).unwrap() + Decodable::decode(&mut filemap_doc.decoder()).unwrap() }).collect() } pub fn closure_kind(cdata: Cmd, closure_id: DefIndex) -> ty::ClosureKind { let closure_doc = cdata.lookup_item(closure_id); let closure_kind_doc = reader::get_doc(closure_doc, tag_items_closure_kind); - ty::ClosureKind::decode(&mut closure_kind_doc.opaque()).unwrap() + ty::ClosureKind::decode(&mut closure_kind_doc.decoder()).unwrap() } pub fn closure_ty<'a, 'tcx>(cdata: Cmd, closure_id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>) @@ -1674,7 +1682,7 @@ pub fn def_key(cdata: Cmd, id: DefIndex) -> hir_map::DefKey { fn item_def_key(item_doc: rbml::Doc) -> hir_map::DefKey { match reader::maybe_get_doc(item_doc, tag_def_key) { Some(def_key_doc) => { - let simple_key = def_key::DefKey::decode(&mut def_key_doc.opaque()).unwrap(); + let simple_key = def_key::DefKey::decode(&mut def_key_doc.decoder()).unwrap(); let name = reader::maybe_get_doc(item_doc, tag_paths_data_name).map(|name| { token::intern(name.as_str()).as_str() }); diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index e493daab0910..9773823c77de 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -108,7 +108,7 @@ fn encode_def_id(ecx: &mut EncodeContext, id: DefId) { fn encode_def_key(ecx: &mut EncodeContext, key: DefKey) { let simple_key = def_key::simplify_def_key(key); ecx.start_tag(tag_def_key); - simple_key.encode(&mut ecx.opaque()); + simple_key.encode(ecx); ecx.end_tag(); } @@ -146,7 +146,7 @@ pub fn def_to_string(_tcx: TyCtxt, did: DefId) -> String { fn encode_item_variances(ecx: &mut EncodeContext, id: NodeId) { let v = ecx.tcx.item_variances(ecx.tcx.map.local_def_id(id)); ecx.start_tag(tag_item_variances); - v.encode(&mut ecx.opaque()); + v.encode(ecx); ecx.end_tag(); } @@ -761,7 +761,7 @@ impl<'a, 'b, 'tcx> ItemContentBuilder<'a, 'b, 'tcx> { attr)); } self.start_tag(tag_items_data_item_repr); - repr_attrs.encode(&mut self.opaque()); + repr_attrs.encode(self.ecx); self.end_tag(); } @@ -796,7 +796,7 @@ fn encode_inherent_implementations(ecx: &mut EncodeContext, fn encode_stability(ecx: &mut EncodeContext, stab_opt: Option<&attr::Stability>) { stab_opt.map(|stab| { ecx.start_tag(tag_items_data_item_stability); - stab.encode(&mut ecx.opaque()).unwrap(); + stab.encode(ecx).unwrap(); ecx.end_tag(); }); } @@ -804,7 +804,7 @@ fn encode_stability(ecx: &mut EncodeContext, stab_opt: Option<&attr::Stability>) fn encode_deprecation(ecx: &mut EncodeContext, depr_opt: Option) { depr_opt.map(|depr| { ecx.start_tag(tag_items_data_item_deprecation); - depr.encode(&mut ecx.opaque()).unwrap(); + depr.encode(ecx).unwrap(); ecx.end_tag(); }); } @@ -1043,7 +1043,7 @@ impl<'a, 'b, 'tcx> ItemContentBuilder<'a, 'b, 'tcx> { { Some(&kind) => { self.start_tag(tag_impl_coerce_unsized_kind); - kind.encode(&mut self.opaque()); + kind.encode(self.ecx); self.end_tag(); } None => {} @@ -1361,7 +1361,7 @@ impl<'a, 'b, 'tcx> ItemContentBuilder<'a, 'b, 'tcx> { self.end_tag(); self.start_tag(tag_items_closure_kind); - tcx.closure_kind(def_id).encode(&mut self.opaque()).unwrap(); + tcx.closure_kind(def_id).encode(self.ecx).unwrap(); self.end_tag(); assert!(self.mir_map.map.contains_key(&def_id)); @@ -1403,7 +1403,7 @@ fn encode_item_index(ecx: &mut EncodeContext, index: IndexData) { fn encode_attributes(ecx: &mut EncodeContext, attrs: &[ast::Attribute]) { ecx.start_tag(tag_attributes); - attrs.encode(&mut ecx.opaque()).unwrap(); + attrs.encode(ecx).unwrap(); ecx.end_tag(); } @@ -1538,7 +1538,7 @@ fn encode_codemap(ecx: &mut EncodeContext) { } ecx.start_tag(tag_codemap_filemap); - filemap.encode(&mut ecx.opaque()).unwrap(); + filemap.encode(ecx).unwrap(); ecx.end_tag(); } diff --git a/src/librustc_metadata/rbml/reader.rs b/src/librustc_metadata/rbml/reader.rs index 02acfef612a1..d66ca38e6244 100644 --- a/src/librustc_metadata/rbml/reader.rs +++ b/src/librustc_metadata/rbml/reader.rs @@ -123,7 +123,6 @@ use std::str; use rustc_serialize as serialize; -use rbml::opaque; use rbml::Error; use rbml::Error::*; @@ -158,10 +157,6 @@ impl<'doc> Doc<'doc> { pub fn to_string(&self) -> String { self.as_str().to_string() } - - pub fn opaque(&self) -> opaque::Decoder<'doc> { - opaque::Decoder::new(self.data, self.start) - } } pub struct TaggedDoc<'a> { diff --git a/src/librustc_metadata/rbml/writer.rs b/src/librustc_metadata/rbml/writer.rs index db3a51187c60..f22a9d1cd003 100644 --- a/src/librustc_metadata/rbml/writer.rs +++ b/src/librustc_metadata/rbml/writer.rs @@ -254,15 +254,11 @@ impl Encoder { } } - pub fn opaque(&mut self) -> opaque::Encoder { - opaque::Encoder::new(&mut self.writer) - } - pub fn emit_opaque(&mut self, f: F) -> EncodeResult where F: FnOnce(&mut opaque::Encoder) -> EncodeResult { self.start_tag(EsOpaque as usize)?; - f(&mut self.opaque())?; + f(&mut opaque::Encoder::new(&mut self.writer))?; self.mark_stable_position(); self.end_tag() } From 02c4155d2cf0b17f526a126ad1f9dca944d9e85d Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Thu, 1 Sep 2016 10:21:12 +0300 Subject: [PATCH 414/443] rustc: remove hir::fold. --- src/librustc/hir/fold.rs | 1131 ------------------------ src/librustc/hir/mod.rs | 1 - src/librustc_const_eval/check_match.rs | 107 +-- src/librustdoc/clean/mod.rs | 120 ++- src/librustdoc/core.rs | 36 +- src/librustdoc/test.rs | 9 +- 6 files changed, 143 insertions(+), 1261 deletions(-) delete mode 100644 src/librustc/hir/fold.rs diff --git a/src/librustc/hir/fold.rs b/src/librustc/hir/fold.rs deleted file mode 100644 index 57b5599bd1d7..000000000000 --- a/src/librustc/hir/fold.rs +++ /dev/null @@ -1,1131 +0,0 @@ -// 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. - -//! A Folder represents an HIR->HIR fold; it accepts a HIR piece, -//! and returns a piece of the same type. - -use hir::*; -use syntax::ast::{Name, NodeId, DUMMY_NODE_ID, Attribute, Attribute_}; -use syntax::ast::{NestedMetaItem, NestedMetaItemKind, MetaItem, MetaItemKind}; -use hir; -use syntax_pos::Span; -use syntax::codemap::{respan, Spanned}; -use syntax::ptr::P; -use syntax::parse::token::keywords; -use syntax::util::move_map::MoveMap; - -pub trait Folder : Sized { - // Any additions to this trait should happen in form - // of a call to a public `noop_*` function that only calls - // out to the folder again, not other `noop_*` functions. - // - // This is a necessary API workaround to the problem of not - // being able to call out to the super default method - // in an overridden default method. - - fn fold_crate(&mut self, c: Crate) -> Crate { - noop_fold_crate(c, self) - } - - fn fold_meta_items(&mut self, meta_items: HirVec>) -> HirVec> { - noop_fold_meta_items(meta_items, self) - } - - fn fold_meta_list_item(&mut self, list_item: NestedMetaItem) -> NestedMetaItem { - noop_fold_meta_list_item(list_item, self) - } - - fn fold_meta_item(&mut self, meta_item: P) -> P { - noop_fold_meta_item(meta_item, self) - } - - fn fold_view_path(&mut self, view_path: P) -> P { - noop_fold_view_path(view_path, self) - } - - fn fold_foreign_item(&mut self, ni: ForeignItem) -> ForeignItem { - noop_fold_foreign_item(ni, self) - } - - fn fold_item(&mut self, i: Item) -> Item { - noop_fold_item(i, self) - } - - fn fold_item_id(&mut self, i: ItemId) -> ItemId { - noop_fold_item_id(i, self) - } - - fn fold_struct_field(&mut self, sf: StructField) -> StructField { - noop_fold_struct_field(sf, self) - } - - fn fold_item_underscore(&mut self, i: Item_) -> Item_ { - noop_fold_item_underscore(i, self) - } - - fn fold_trait_item(&mut self, i: TraitItem) -> TraitItem { - noop_fold_trait_item(i, self) - } - - fn fold_impl_item(&mut self, i: ImplItem) -> ImplItem { - noop_fold_impl_item(i, self) - } - - fn fold_fn_decl(&mut self, d: P) -> P { - noop_fold_fn_decl(d, self) - } - - fn fold_block(&mut self, b: P) -> P { - noop_fold_block(b, self) - } - - fn fold_stmt(&mut self, s: Stmt) -> Stmt { - noop_fold_stmt(s, self) - } - - fn fold_arm(&mut self, a: Arm) -> Arm { - noop_fold_arm(a, self) - } - - fn fold_pat(&mut self, p: P) -> P { - noop_fold_pat(p, self) - } - - fn fold_decl(&mut self, d: P) -> P { - noop_fold_decl(d, self) - } - - fn fold_expr(&mut self, e: P) -> P { - e.map(|e| noop_fold_expr(e, self)) - } - - fn fold_ty(&mut self, t: P) -> P { - noop_fold_ty(t, self) - } - - fn fold_ty_binding(&mut self, t: TypeBinding) -> TypeBinding { - noop_fold_ty_binding(t, self) - } - - fn fold_mod(&mut self, m: Mod) -> Mod { - noop_fold_mod(m, self) - } - - fn fold_foreign_mod(&mut self, nm: ForeignMod) -> ForeignMod { - noop_fold_foreign_mod(nm, self) - } - - fn fold_variant(&mut self, v: Variant) -> Variant { - noop_fold_variant(v, self) - } - - fn fold_name(&mut self, n: Name) -> Name { - noop_fold_name(n, self) - } - - fn fold_usize(&mut self, i: usize) -> usize { - noop_fold_usize(i, self) - } - - fn fold_path(&mut self, p: Path) -> Path { - noop_fold_path(p, self) - } - - fn fold_path_parameters(&mut self, p: PathParameters) -> PathParameters { - noop_fold_path_parameters(p, self) - } - - fn fold_angle_bracketed_parameter_data(&mut self, - p: AngleBracketedParameterData) - -> AngleBracketedParameterData { - noop_fold_angle_bracketed_parameter_data(p, self) - } - - fn fold_parenthesized_parameter_data(&mut self, - p: ParenthesizedParameterData) - -> ParenthesizedParameterData { - noop_fold_parenthesized_parameter_data(p, self) - } - - fn fold_local(&mut self, l: P) -> P { - noop_fold_local(l, self) - } - - fn fold_lifetime(&mut self, l: Lifetime) -> Lifetime { - noop_fold_lifetime(l, self) - } - - fn fold_lifetime_def(&mut self, l: LifetimeDef) -> LifetimeDef { - noop_fold_lifetime_def(l, self) - } - - fn fold_attribute(&mut self, at: Attribute) -> Option { - noop_fold_attribute(at, self) - } - - fn fold_arg(&mut self, a: Arg) -> Arg { - noop_fold_arg(a, self) - } - - fn fold_generics(&mut self, generics: Generics) -> Generics { - noop_fold_generics(generics, self) - } - - fn fold_trait_ref(&mut self, p: TraitRef) -> TraitRef { - noop_fold_trait_ref(p, self) - } - - fn fold_poly_trait_ref(&mut self, p: PolyTraitRef) -> PolyTraitRef { - noop_fold_poly_trait_ref(p, self) - } - - fn fold_variant_data(&mut self, vdata: VariantData) -> VariantData { - noop_fold_variant_data(vdata, self) - } - - fn fold_lifetimes(&mut self, lts: HirVec) -> HirVec { - noop_fold_lifetimes(lts, self) - } - - fn fold_lifetime_defs(&mut self, lts: HirVec) -> HirVec { - noop_fold_lifetime_defs(lts, self) - } - - fn fold_ty_param(&mut self, tp: TyParam) -> TyParam { - noop_fold_ty_param(tp, self) - } - - fn fold_ty_params(&mut self, tps: HirVec) -> HirVec { - noop_fold_ty_params(tps, self) - } - - fn fold_opt_lifetime(&mut self, o_lt: Option) -> Option { - noop_fold_opt_lifetime(o_lt, self) - } - - fn fold_opt_bounds(&mut self, - b: Option) - -> Option { - noop_fold_opt_bounds(b, self) - } - - fn fold_bounds(&mut self, b: TyParamBounds) -> TyParamBounds { - noop_fold_bounds(b, self) - } - - fn fold_ty_param_bound(&mut self, tpb: TyParamBound) -> TyParamBound { - noop_fold_ty_param_bound(tpb, self) - } - - fn fold_mt(&mut self, mt: MutTy) -> MutTy { - noop_fold_mt(mt, self) - } - - fn fold_field(&mut self, field: Field) -> Field { - noop_fold_field(field, self) - } - - fn fold_where_clause(&mut self, where_clause: WhereClause) -> WhereClause { - noop_fold_where_clause(where_clause, self) - } - - fn fold_where_predicate(&mut self, where_predicate: WherePredicate) -> WherePredicate { - noop_fold_where_predicate(where_predicate, self) - } - - /// called for the `id` on each declaration - fn new_id(&mut self, i: NodeId) -> NodeId { - i - } - - /// called for ids that are references (e.g., ItemDef) - fn map_id(&mut self, i: NodeId) -> NodeId { - i - } - - fn new_span(&mut self, sp: Span) -> Span { - sp - } -} - -pub fn noop_fold_meta_items(meta_items: HirVec>, - fld: &mut T) - -> HirVec> { - meta_items.move_map(|x| fld.fold_meta_item(x)) -} - -pub fn noop_fold_view_path(view_path: P, fld: &mut T) -> P { - view_path.map(|Spanned { node, span }| { - Spanned { - node: match node { - ViewPathSimple(name, path) => { - ViewPathSimple(name, fld.fold_path(path)) - } - ViewPathGlob(path) => { - ViewPathGlob(fld.fold_path(path)) - } - ViewPathList(path, path_list_idents) => { - ViewPathList(fld.fold_path(path), - path_list_idents.move_map(|path_list_ident| { - Spanned { - node: PathListItem_ { - id: fld.new_id(path_list_ident.node.id), - name: path_list_ident.node.name, - rename: path_list_ident.node.rename, - }, - span: fld.new_span(path_list_ident.span), - } - })) - } - }, - span: fld.new_span(span), - } - }) -} - -pub fn fold_attrs(attrs: T, fld: &mut F) -> T - where T: Into> + From>, - F: Folder, -{ - attrs.into().move_flat_map(|x| fld.fold_attribute(x)).into() -} - -pub fn noop_fold_arm(Arm { attrs, pats, guard, body }: Arm, fld: &mut T) -> Arm { - Arm { - attrs: fold_attrs(attrs, fld), - pats: pats.move_map(|x| fld.fold_pat(x)), - guard: guard.map(|x| fld.fold_expr(x)), - body: fld.fold_expr(body), - } -} - -pub fn noop_fold_decl(d: P, fld: &mut T) -> P { - d.map(|Spanned { node, span }| { - match node { - DeclLocal(l) => Spanned { - node: DeclLocal(fld.fold_local(l)), - span: fld.new_span(span), - }, - DeclItem(it) => Spanned { - node: DeclItem(fld.fold_item_id(it)), - span: fld.new_span(span), - }, - } - }) -} - -pub fn noop_fold_ty_binding(b: TypeBinding, fld: &mut T) -> TypeBinding { - TypeBinding { - id: fld.new_id(b.id), - name: b.name, - ty: fld.fold_ty(b.ty), - span: fld.new_span(b.span), - } -} - -pub fn noop_fold_ty(t: P, fld: &mut T) -> P { - t.map(|Ty { id, node, span }| { - Ty { - id: fld.new_id(id), - node: match node { - TyInfer => node, - TyVec(ty) => TyVec(fld.fold_ty(ty)), - TyPtr(mt) => TyPtr(fld.fold_mt(mt)), - TyRptr(region, mt) => { - TyRptr(fld.fold_opt_lifetime(region), fld.fold_mt(mt)) - } - TyBareFn(f) => { - TyBareFn(f.map(|BareFnTy { lifetimes, unsafety, abi, decl }| { - BareFnTy { - lifetimes: fld.fold_lifetime_defs(lifetimes), - unsafety: unsafety, - abi: abi, - decl: fld.fold_fn_decl(decl), - } - })) - } - TyNever => node, - TyTup(tys) => TyTup(tys.move_map(|ty| fld.fold_ty(ty))), - TyPath(qself, path) => { - let qself = qself.map(|QSelf { ty, position }| { - QSelf { - ty: fld.fold_ty(ty), - position: position, - } - }); - TyPath(qself, fld.fold_path(path)) - } - TyObjectSum(ty, bounds) => { - TyObjectSum(fld.fold_ty(ty), fld.fold_bounds(bounds)) - } - TyFixedLengthVec(ty, e) => { - TyFixedLengthVec(fld.fold_ty(ty), fld.fold_expr(e)) - } - TyTypeof(expr) => { - TyTypeof(fld.fold_expr(expr)) - } - TyPolyTraitRef(bounds) => { - TyPolyTraitRef(bounds.move_map(|b| fld.fold_ty_param_bound(b))) - } - TyImplTrait(bounds) => { - TyImplTrait(bounds.move_map(|b| fld.fold_ty_param_bound(b))) - } - }, - span: fld.new_span(span), - } - }) -} - -pub fn noop_fold_foreign_mod(ForeignMod { abi, items }: ForeignMod, - fld: &mut T) - -> ForeignMod { - ForeignMod { - abi: abi, - items: items.move_map(|x| fld.fold_foreign_item(x)), - } -} - -pub fn noop_fold_variant(v: Variant, fld: &mut T) -> Variant { - Spanned { - node: Variant_ { - name: v.node.name, - attrs: fold_attrs(v.node.attrs, fld), - data: fld.fold_variant_data(v.node.data), - disr_expr: v.node.disr_expr.map(|e| fld.fold_expr(e)), - }, - span: fld.new_span(v.span), - } -} - -pub fn noop_fold_name(n: Name, _: &mut T) -> Name { - n -} - -pub fn noop_fold_usize(i: usize, _: &mut T) -> usize { - i -} - -pub fn noop_fold_path(Path { global, segments, span }: Path, fld: &mut T) -> Path { - Path { - global: global, - segments: segments.move_map(|PathSegment { name, parameters }| { - PathSegment { - name: fld.fold_name(name), - parameters: fld.fold_path_parameters(parameters), - } - }), - span: fld.new_span(span), - } -} - -pub fn noop_fold_path_parameters(path_parameters: PathParameters, - fld: &mut T) - -> PathParameters { - match path_parameters { - AngleBracketedParameters(data) => - AngleBracketedParameters(fld.fold_angle_bracketed_parameter_data(data)), - ParenthesizedParameters(data) => - ParenthesizedParameters(fld.fold_parenthesized_parameter_data(data)), - } -} - -pub fn noop_fold_angle_bracketed_parameter_data(data: AngleBracketedParameterData, - fld: &mut T) - -> AngleBracketedParameterData { - let AngleBracketedParameterData { lifetimes, types, bindings } = data; - AngleBracketedParameterData { - lifetimes: fld.fold_lifetimes(lifetimes), - types: types.move_map(|ty| fld.fold_ty(ty)), - bindings: bindings.move_map(|b| fld.fold_ty_binding(b)), - } -} - -pub fn noop_fold_parenthesized_parameter_data(data: ParenthesizedParameterData, - fld: &mut T) - -> ParenthesizedParameterData { - let ParenthesizedParameterData { inputs, output, span } = data; - ParenthesizedParameterData { - inputs: inputs.move_map(|ty| fld.fold_ty(ty)), - output: output.map(|ty| fld.fold_ty(ty)), - span: fld.new_span(span), - } -} - -pub fn noop_fold_local(l: P, fld: &mut T) -> P { - l.map(|Local { id, pat, ty, init, span, attrs }| { - Local { - id: fld.new_id(id), - ty: ty.map(|t| fld.fold_ty(t)), - pat: fld.fold_pat(pat), - init: init.map(|e| fld.fold_expr(e)), - span: fld.new_span(span), - attrs: fold_attrs(attrs, fld), - } - }) -} - -pub fn noop_fold_attribute(at: Attribute, fld: &mut T) -> Option { - let Spanned {node: Attribute_ {id, style, value, is_sugared_doc}, span} = at; - Some(Spanned { - node: Attribute_ { - id: id, - style: style, - value: fld.fold_meta_item(value), - is_sugared_doc: is_sugared_doc, - }, - span: fld.new_span(span), - }) -} - -pub fn noop_fold_meta_list_item(li: NestedMetaItem, fld: &mut T) - -> NestedMetaItem { - Spanned { - node: match li.node { - NestedMetaItemKind::MetaItem(mi) => { - NestedMetaItemKind::MetaItem(fld.fold_meta_item(mi)) - }, - NestedMetaItemKind::Literal(lit) => NestedMetaItemKind::Literal(lit) - }, - span: fld.new_span(li.span) - } -} - -pub fn noop_fold_meta_item(mi: P, fld: &mut T) -> P { - mi.map(|Spanned { node, span }| { - Spanned { - node: match node { - MetaItemKind::Word(id) => MetaItemKind::Word(id), - MetaItemKind::List(id, mis) => { - MetaItemKind::List(id, mis.move_map(|e| fld.fold_meta_list_item(e))) - } - MetaItemKind::NameValue(id, s) => MetaItemKind::NameValue(id, s), - }, - span: fld.new_span(span), - } - }) -} - -pub fn noop_fold_arg(Arg { id, pat, ty }: Arg, fld: &mut T) -> Arg { - Arg { - id: fld.new_id(id), - pat: fld.fold_pat(pat), - ty: fld.fold_ty(ty), - } -} - -pub fn noop_fold_fn_decl(decl: P, fld: &mut T) -> P { - decl.map(|FnDecl { inputs, output, variadic }| { - FnDecl { - inputs: inputs.move_map(|x| fld.fold_arg(x)), - output: match output { - Return(ty) => Return(fld.fold_ty(ty)), - DefaultReturn(span) => DefaultReturn(span), - }, - variadic: variadic, - } - }) -} - -pub fn noop_fold_ty_param_bound(tpb: TyParamBound, fld: &mut T) -> TyParamBound - where T: Folder -{ - match tpb { - TraitTyParamBound(ty, modifier) => TraitTyParamBound(fld.fold_poly_trait_ref(ty), modifier), - RegionTyParamBound(lifetime) => RegionTyParamBound(fld.fold_lifetime(lifetime)), - } -} - -pub fn noop_fold_ty_param(tp: TyParam, fld: &mut T) -> TyParam { - let TyParam {id, name, bounds, default, span} = tp; - TyParam { - id: fld.new_id(id), - name: name, - bounds: fld.fold_bounds(bounds), - default: default.map(|x| fld.fold_ty(x)), - span: span, - } -} - -pub fn noop_fold_ty_params(tps: HirVec, - fld: &mut T) - -> HirVec { - tps.move_map(|tp| fld.fold_ty_param(tp)) -} - -pub fn noop_fold_lifetime(l: Lifetime, fld: &mut T) -> Lifetime { - Lifetime { - id: fld.new_id(l.id), - name: l.name, - span: fld.new_span(l.span), - } -} - -pub fn noop_fold_lifetime_def(l: LifetimeDef, fld: &mut T) -> LifetimeDef { - LifetimeDef { - lifetime: fld.fold_lifetime(l.lifetime), - bounds: fld.fold_lifetimes(l.bounds), - } -} - -pub fn noop_fold_lifetimes(lts: HirVec, fld: &mut T) -> HirVec { - lts.move_map(|l| fld.fold_lifetime(l)) -} - -pub fn noop_fold_lifetime_defs(lts: HirVec, - fld: &mut T) - -> HirVec { - lts.move_map(|l| fld.fold_lifetime_def(l)) -} - -pub fn noop_fold_opt_lifetime(o_lt: Option, fld: &mut T) -> Option { - o_lt.map(|lt| fld.fold_lifetime(lt)) -} - -pub fn noop_fold_generics(Generics {ty_params, lifetimes, where_clause, span}: Generics, - fld: &mut T) - -> Generics { - Generics { - ty_params: fld.fold_ty_params(ty_params), - lifetimes: fld.fold_lifetime_defs(lifetimes), - where_clause: fld.fold_where_clause(where_clause), - span: fld.new_span(span), - } -} - -pub fn noop_fold_where_clause(WhereClause { id, predicates }: WhereClause, - fld: &mut T) - -> WhereClause { - WhereClause { - id: fld.new_id(id), - predicates: predicates.move_map(|predicate| fld.fold_where_predicate(predicate)), - } -} - -pub fn noop_fold_where_predicate(pred: WherePredicate, fld: &mut T) -> WherePredicate { - match pred { - hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate{bound_lifetimes, - bounded_ty, - bounds, - span}) => { - hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate { - bound_lifetimes: fld.fold_lifetime_defs(bound_lifetimes), - bounded_ty: fld.fold_ty(bounded_ty), - bounds: bounds.move_map(|x| fld.fold_ty_param_bound(x)), - span: fld.new_span(span), - }) - } - hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate{lifetime, - bounds, - span}) => { - hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate { - span: fld.new_span(span), - lifetime: fld.fold_lifetime(lifetime), - bounds: bounds.move_map(|bound| fld.fold_lifetime(bound)), - }) - } - hir::WherePredicate::EqPredicate(hir::WhereEqPredicate{id, - path, - ty, - span}) => { - hir::WherePredicate::EqPredicate(hir::WhereEqPredicate { - id: fld.new_id(id), - path: fld.fold_path(path), - ty: fld.fold_ty(ty), - span: fld.new_span(span), - }) - } - } -} - -pub fn noop_fold_variant_data(vdata: VariantData, fld: &mut T) -> VariantData { - match vdata { - VariantData::Struct(fields, id) => { - VariantData::Struct(fields.move_map(|f| fld.fold_struct_field(f)), - fld.new_id(id)) - } - VariantData::Tuple(fields, id) => { - VariantData::Tuple(fields.move_map(|f| fld.fold_struct_field(f)), - fld.new_id(id)) - } - VariantData::Unit(id) => VariantData::Unit(fld.new_id(id)), - } -} - -pub fn noop_fold_trait_ref(p: TraitRef, fld: &mut T) -> TraitRef { - let id = fld.new_id(p.ref_id); - let TraitRef { - path, - ref_id: _, - } = p; - hir::TraitRef { - path: fld.fold_path(path), - ref_id: id, - } -} - -pub fn noop_fold_poly_trait_ref(p: PolyTraitRef, fld: &mut T) -> PolyTraitRef { - hir::PolyTraitRef { - bound_lifetimes: fld.fold_lifetime_defs(p.bound_lifetimes), - trait_ref: fld.fold_trait_ref(p.trait_ref), - span: fld.new_span(p.span), - } -} - -pub fn noop_fold_struct_field(f: StructField, fld: &mut T) -> StructField { - StructField { - span: fld.new_span(f.span), - id: fld.new_id(f.id), - name: f.name, - vis: f.vis, - ty: fld.fold_ty(f.ty), - attrs: fold_attrs(f.attrs, fld), - } -} - -pub fn noop_fold_field(Field { name, expr, span }: Field, folder: &mut T) -> Field { - Field { - name: respan(folder.new_span(name.span), folder.fold_name(name.node)), - expr: folder.fold_expr(expr), - span: folder.new_span(span), - } -} - -pub fn noop_fold_mt(MutTy { ty, mutbl }: MutTy, folder: &mut T) -> MutTy { - MutTy { - ty: folder.fold_ty(ty), - mutbl: mutbl, - } -} - -pub fn noop_fold_opt_bounds(b: Option, - folder: &mut T) - -> Option { - b.map(|bounds| folder.fold_bounds(bounds)) -} - -fn noop_fold_bounds(bounds: TyParamBounds, folder: &mut T) -> TyParamBounds { - bounds.move_map(|bound| folder.fold_ty_param_bound(bound)) -} - -pub fn noop_fold_block(b: P, folder: &mut T) -> P { - b.map(|Block { id, stmts, expr, rules, span }| { - Block { - id: folder.new_id(id), - stmts: stmts.move_map(|s| folder.fold_stmt(s)), - expr: expr.map(|x| folder.fold_expr(x)), - rules: rules, - span: folder.new_span(span), - } - }) -} - -pub fn noop_fold_item_underscore(i: Item_, folder: &mut T) -> Item_ { - match i { - ItemExternCrate(string) => ItemExternCrate(string), - ItemUse(view_path) => { - ItemUse(folder.fold_view_path(view_path)) - } - ItemStatic(t, m, e) => { - ItemStatic(folder.fold_ty(t), m, folder.fold_expr(e)) - } - ItemConst(t, e) => { - ItemConst(folder.fold_ty(t), folder.fold_expr(e)) - } - ItemFn(decl, unsafety, constness, abi, generics, body) => { - ItemFn(folder.fold_fn_decl(decl), - unsafety, - constness, - abi, - folder.fold_generics(generics), - folder.fold_block(body)) - } - ItemMod(m) => ItemMod(folder.fold_mod(m)), - ItemForeignMod(nm) => ItemForeignMod(folder.fold_foreign_mod(nm)), - ItemTy(t, generics) => { - ItemTy(folder.fold_ty(t), folder.fold_generics(generics)) - } - ItemEnum(enum_definition, generics) => { - ItemEnum(hir::EnumDef { - variants: enum_definition.variants.move_map(|x| folder.fold_variant(x)), - }, - folder.fold_generics(generics)) - } - ItemStruct(struct_def, generics) => { - let struct_def = folder.fold_variant_data(struct_def); - ItemStruct(struct_def, folder.fold_generics(generics)) - } - ItemUnion(struct_def, generics) => { - let struct_def = folder.fold_variant_data(struct_def); - ItemUnion(struct_def, folder.fold_generics(generics)) - } - ItemDefaultImpl(unsafety, ref trait_ref) => { - ItemDefaultImpl(unsafety, folder.fold_trait_ref((*trait_ref).clone())) - } - ItemImpl(unsafety, polarity, generics, ifce, ty, impl_items) => { - let new_impl_items = impl_items - .move_map(|item| folder.fold_impl_item(item)); - let ifce = match ifce { - None => None, - Some(ref trait_ref) => { - Some(folder.fold_trait_ref((*trait_ref).clone())) - } - }; - ItemImpl(unsafety, - polarity, - folder.fold_generics(generics), - ifce, - folder.fold_ty(ty), - new_impl_items) - } - ItemTrait(unsafety, generics, bounds, items) => { - let bounds = folder.fold_bounds(bounds); - let items = items.move_map(|item| folder.fold_trait_item(item)); - ItemTrait(unsafety, folder.fold_generics(generics), bounds, items) - } - } -} - -pub fn noop_fold_trait_item(i: TraitItem, - folder: &mut T) - -> TraitItem { - TraitItem { - id: folder.new_id(i.id), - name: folder.fold_name(i.name), - attrs: fold_attrs(i.attrs, folder), - node: match i.node { - ConstTraitItem(ty, default) => { - ConstTraitItem(folder.fold_ty(ty), default.map(|x| folder.fold_expr(x))) - } - MethodTraitItem(sig, body) => { - MethodTraitItem(noop_fold_method_sig(sig, folder), - body.map(|x| folder.fold_block(x))) - } - TypeTraitItem(bounds, default) => { - TypeTraitItem(folder.fold_bounds(bounds), - default.map(|x| folder.fold_ty(x))) - } - }, - span: folder.new_span(i.span), - } -} - -pub fn noop_fold_impl_item(i: ImplItem, folder: &mut T) -> ImplItem { - ImplItem { - id: folder.new_id(i.id), - name: folder.fold_name(i.name), - attrs: fold_attrs(i.attrs, folder), - vis: i.vis, - defaultness: i.defaultness, - node: match i.node { - ImplItemKind::Const(ty, expr) => { - ImplItemKind::Const(folder.fold_ty(ty), folder.fold_expr(expr)) - } - ImplItemKind::Method(sig, body) => { - ImplItemKind::Method(noop_fold_method_sig(sig, folder), folder.fold_block(body)) - } - ImplItemKind::Type(ty) => ImplItemKind::Type(folder.fold_ty(ty)), - }, - span: folder.new_span(i.span), - } -} - -pub fn noop_fold_mod(Mod { inner, item_ids }: Mod, folder: &mut T) -> Mod { - Mod { - inner: folder.new_span(inner), - item_ids: item_ids.move_map(|x| folder.fold_item_id(x)), - } -} - -pub fn noop_fold_crate(Crate { module, attrs, config, span, - exported_macros, items }: Crate, - folder: &mut T) - -> Crate { - let config = folder.fold_meta_items(config); - - let crate_mod = folder.fold_item(hir::Item { - name: keywords::Invalid.name(), - attrs: attrs, - id: DUMMY_NODE_ID, - vis: hir::Public, - span: span, - node: hir::ItemMod(module), - }); - - let (module, attrs, span) = match crate_mod { - hir::Item { attrs, span, node, .. } => { - match node { - hir::ItemMod(m) => (m, attrs, span), - _ => panic!("fold converted a module to not a module"), - } - } - }; - - let items = items.into_iter() - .map(|(id, item)| (id, folder.fold_item(item))) - .collect(); - - Crate { - module: module, - attrs: attrs, - config: config, - span: span, - exported_macros: exported_macros, - items: items, - } -} - -pub fn noop_fold_item_id(i: ItemId, folder: &mut T) -> ItemId { - let id = folder.map_id(i.id); - ItemId { id: id } -} - -// fold one item into one item -pub fn noop_fold_item(item: Item, folder: &mut T) -> Item { - let Item { id, name, attrs, node, vis, span } = item; - let id = folder.new_id(id); - let node = folder.fold_item_underscore(node); - - Item { - id: id, - name: folder.fold_name(name), - attrs: fold_attrs(attrs, folder), - node: node, - vis: vis, - span: folder.new_span(span), - } -} - -pub fn noop_fold_foreign_item(ni: ForeignItem, folder: &mut T) -> ForeignItem { - ForeignItem { - id: folder.new_id(ni.id), - name: folder.fold_name(ni.name), - attrs: fold_attrs(ni.attrs, folder), - node: match ni.node { - ForeignItemFn(fdec, generics) => { - ForeignItemFn(folder.fold_fn_decl(fdec), folder.fold_generics(generics)) - } - ForeignItemStatic(t, m) => { - ForeignItemStatic(folder.fold_ty(t), m) - } - }, - vis: ni.vis, - span: folder.new_span(ni.span), - } -} - -pub fn noop_fold_method_sig(sig: MethodSig, folder: &mut T) -> MethodSig { - MethodSig { - generics: folder.fold_generics(sig.generics), - abi: sig.abi, - unsafety: sig.unsafety, - constness: sig.constness, - decl: folder.fold_fn_decl(sig.decl), - } -} - -pub fn noop_fold_pat(p: P, folder: &mut T) -> P { - p.map(|Pat { id, node, span }| { - Pat { - id: folder.new_id(id), - node: match node { - PatKind::Wild => PatKind::Wild, - PatKind::Binding(binding_mode, pth1, sub) => { - PatKind::Binding(binding_mode, - Spanned { - span: folder.new_span(pth1.span), - node: folder.fold_name(pth1.node), - }, - sub.map(|x| folder.fold_pat(x))) - } - PatKind::Lit(e) => PatKind::Lit(folder.fold_expr(e)), - PatKind::TupleStruct(pth, pats, ddpos) => { - PatKind::TupleStruct(folder.fold_path(pth), - pats.move_map(|x| folder.fold_pat(x)), ddpos) - } - PatKind::Path(opt_qself, pth) => { - let opt_qself = opt_qself.map(|qself| { - QSelf { ty: folder.fold_ty(qself.ty), position: qself.position } - }); - PatKind::Path(opt_qself, folder.fold_path(pth)) - } - PatKind::Struct(pth, fields, etc) => { - let pth = folder.fold_path(pth); - let fs = fields.move_map(|f| { - Spanned { - span: folder.new_span(f.span), - node: hir::FieldPat { - name: f.node.name, - pat: folder.fold_pat(f.node.pat), - is_shorthand: f.node.is_shorthand, - }, - } - }); - PatKind::Struct(pth, fs, etc) - } - PatKind::Tuple(elts, ddpos) => { - PatKind::Tuple(elts.move_map(|x| folder.fold_pat(x)), ddpos) - } - PatKind::Box(inner) => PatKind::Box(folder.fold_pat(inner)), - PatKind::Ref(inner, mutbl) => PatKind::Ref(folder.fold_pat(inner), mutbl), - PatKind::Range(e1, e2) => { - PatKind::Range(folder.fold_expr(e1), folder.fold_expr(e2)) - } - PatKind::Vec(before, slice, after) => { - PatKind::Vec(before.move_map(|x| folder.fold_pat(x)), - slice.map(|x| folder.fold_pat(x)), - after.move_map(|x| folder.fold_pat(x))) - } - }, - span: folder.new_span(span), - } - }) -} - -pub fn noop_fold_expr(Expr { id, node, span, attrs }: Expr, folder: &mut T) -> Expr { - Expr { - id: folder.new_id(id), - node: match node { - ExprBox(e) => { - ExprBox(folder.fold_expr(e)) - } - ExprVec(exprs) => { - ExprVec(exprs.move_map(|x| folder.fold_expr(x))) - } - ExprRepeat(expr, count) => { - ExprRepeat(folder.fold_expr(expr), folder.fold_expr(count)) - } - ExprTup(elts) => ExprTup(elts.move_map(|x| folder.fold_expr(x))), - ExprCall(f, args) => { - ExprCall(folder.fold_expr(f), args.move_map(|x| folder.fold_expr(x))) - } - ExprMethodCall(name, tps, args) => { - ExprMethodCall(respan(folder.new_span(name.span), folder.fold_name(name.node)), - tps.move_map(|x| folder.fold_ty(x)), - args.move_map(|x| folder.fold_expr(x))) - } - ExprBinary(binop, lhs, rhs) => { - ExprBinary(binop, folder.fold_expr(lhs), folder.fold_expr(rhs)) - } - ExprUnary(binop, ohs) => { - ExprUnary(binop, folder.fold_expr(ohs)) - } - ExprLit(l) => ExprLit(l), - ExprCast(expr, ty) => { - ExprCast(folder.fold_expr(expr), folder.fold_ty(ty)) - } - ExprType(expr, ty) => { - ExprType(folder.fold_expr(expr), folder.fold_ty(ty)) - } - ExprAddrOf(m, ohs) => ExprAddrOf(m, folder.fold_expr(ohs)), - ExprIf(cond, tr, fl) => { - ExprIf(folder.fold_expr(cond), - folder.fold_block(tr), - fl.map(|x| folder.fold_expr(x))) - } - ExprWhile(cond, body, opt_name) => { - ExprWhile(folder.fold_expr(cond), - folder.fold_block(body), - opt_name.map(|label| { - respan(folder.new_span(label.span), folder.fold_name(label.node)) - })) - } - ExprLoop(body, opt_name) => { - ExprLoop(folder.fold_block(body), - opt_name.map(|label| { - respan(folder.new_span(label.span), folder.fold_name(label.node)) - })) - } - ExprMatch(expr, arms, source) => { - ExprMatch(folder.fold_expr(expr), - arms.move_map(|x| folder.fold_arm(x)), - source) - } - ExprClosure(capture_clause, decl, body, fn_decl_span) => { - ExprClosure(capture_clause, - folder.fold_fn_decl(decl), - folder.fold_block(body), - folder.new_span(fn_decl_span)) - } - ExprBlock(blk) => ExprBlock(folder.fold_block(blk)), - ExprAssign(el, er) => { - ExprAssign(folder.fold_expr(el), folder.fold_expr(er)) - } - ExprAssignOp(op, el, er) => { - ExprAssignOp(op, folder.fold_expr(el), folder.fold_expr(er)) - } - ExprField(el, name) => { - ExprField(folder.fold_expr(el), - respan(folder.new_span(name.span), folder.fold_name(name.node))) - } - ExprTupField(el, index) => { - ExprTupField(folder.fold_expr(el), - respan(folder.new_span(index.span), folder.fold_usize(index.node))) - } - ExprIndex(el, er) => { - ExprIndex(folder.fold_expr(el), folder.fold_expr(er)) - } - ExprPath(qself, path) => { - let qself = qself.map(|QSelf { ty, position }| { - QSelf { - ty: folder.fold_ty(ty), - position: position, - } - }); - ExprPath(qself, folder.fold_path(path)) - } - ExprBreak(opt_name) => ExprBreak(opt_name.map(|label| { - respan(folder.new_span(label.span), folder.fold_name(label.node)) - })), - ExprAgain(opt_name) => ExprAgain(opt_name.map(|label| { - respan(folder.new_span(label.span), folder.fold_name(label.node)) - })), - ExprRet(e) => ExprRet(e.map(|x| folder.fold_expr(x))), - ExprInlineAsm(asm, outputs, inputs) => { - ExprInlineAsm(asm, - outputs.move_map(|x| folder.fold_expr(x)), - inputs.move_map(|x| folder.fold_expr(x))) - } - ExprStruct(path, fields, maybe_expr) => { - ExprStruct(folder.fold_path(path), - fields.move_map(|x| folder.fold_field(x)), - maybe_expr.map(|x| folder.fold_expr(x))) - } - }, - span: folder.new_span(span), - attrs: fold_attrs(attrs, folder), - } -} - -pub fn noop_fold_stmt(stmt: Stmt, folder: &mut T) -> Stmt { - let span = folder.new_span(stmt.span); - match stmt.node { - StmtDecl(d, id) => { - let id = folder.new_id(id); - Spanned { - node: StmtDecl(folder.fold_decl(d), id), - span: span - } - } - StmtExpr(e, id) => { - let id = folder.new_id(id); - Spanned { - node: StmtExpr(folder.fold_expr(e), id), - span: span, - } - } - StmtSemi(e, id) => { - let id = folder.new_id(id); - Spanned { - node: StmtSemi(folder.fold_expr(e), id), - span: span, - } - } - } -} diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index e22c9869ab17..0cfdbae1a50b 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -67,7 +67,6 @@ macro_rules! hir_vec { pub mod check_attr; pub mod def; pub mod def_id; -pub mod fold; pub mod intravisit; pub mod lowering; pub mod map; diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs index 5d2b266ec4b7..dda72ce57b4f 100644 --- a/src/librustc_const_eval/check_match.rs +++ b/src/librustc_const_eval/check_match.rs @@ -40,11 +40,10 @@ use rustc_back::slice; use syntax::ast::{self, DUMMY_NODE_ID, NodeId}; use syntax::codemap::Spanned; use syntax_pos::{Span, DUMMY_SP}; -use rustc::hir::fold::{Folder, noop_fold_pat}; use rustc::hir::print::pat_to_string; use syntax::ptr::P; +use syntax::util::move_map::MoveMap; use rustc::util::common::ErrorReported; -use rustc::util::nodemap::FnvHashMap; pub const DUMMY_WILD_PAT: &'static Pat = &Pat { id: DUMMY_NODE_ID, @@ -182,7 +181,7 @@ fn check_expr(cx: &mut MatchCheckCtxt, ex: &hir::Expr) { } } - let mut static_inliner = StaticInliner::new(cx.tcx, None); + let mut static_inliner = StaticInliner::new(cx.tcx); let inlined_arms = arms.iter().map(|arm| { (arm.pats.iter().map(|pat| { static_inliner.fold_pat((*pat).clone()) @@ -467,53 +466,30 @@ fn const_val_to_expr(value: &ConstVal) -> P { }) } -pub struct StaticInliner<'a, 'tcx: 'a> { - pub tcx: TyCtxt<'a, 'tcx, 'tcx>, - pub failed: bool, - pub renaming_map: Option<&'a mut FnvHashMap<(NodeId, Span), NodeId>>, +struct StaticInliner<'a, 'tcx: 'a> { + tcx: TyCtxt<'a, 'tcx, 'tcx>, + failed: bool } impl<'a, 'tcx> StaticInliner<'a, 'tcx> { - pub fn new<'b>(tcx: TyCtxt<'b, 'tcx, 'tcx>, - renaming_map: Option<&'b mut FnvHashMap<(NodeId, Span), NodeId>>) - -> StaticInliner<'b, 'tcx> { + pub fn new<'b>(tcx: TyCtxt<'b, 'tcx, 'tcx>) -> StaticInliner<'b, 'tcx> { StaticInliner { tcx: tcx, - failed: false, - renaming_map: renaming_map + failed: false } } } -struct RenamingRecorder<'map> { - substituted_node_id: NodeId, - origin_span: Span, - renaming_map: &'map mut FnvHashMap<(NodeId, Span), NodeId> -} - -impl<'v, 'map> Visitor<'v> for RenamingRecorder<'map> { - fn visit_id(&mut self, node_id: NodeId) { - let key = (node_id, self.origin_span); - self.renaming_map.insert(key, self.substituted_node_id); - } -} - -impl<'a, 'tcx> Folder for StaticInliner<'a, 'tcx> { +impl<'a, 'tcx> StaticInliner<'a, 'tcx> { fn fold_pat(&mut self, pat: P) -> P { - return match pat.node { + match pat.node { PatKind::Path(..) => { match self.tcx.expect_def(pat.id) { Def::AssociatedConst(did) | Def::Const(did) => { let substs = Some(self.tcx.node_id_item_substs(pat.id).substs); if let Some((const_expr, _)) = lookup_const_by_id(self.tcx, did, substs) { match const_expr_to_pat(self.tcx, const_expr, pat.id, pat.span) { - Ok(new_pat) => { - if let Some(ref mut map) = self.renaming_map { - // Record any renamings we do here - record_renamings(const_expr, &pat, map); - } - new_pat - } + Ok(new_pat) => return new_pat, Err(def_id) => { self.failed = true; self.tcx.sess.span_err( @@ -521,33 +497,62 @@ impl<'a, 'tcx> Folder for StaticInliner<'a, 'tcx> { &format!("constants of the type `{}` \ cannot be used in patterns", self.tcx.item_path_str(def_id))); - pat } } } else { self.failed = true; span_err!(self.tcx.sess, pat.span, E0158, "statics cannot be referenced in patterns"); - pat } } - _ => noop_fold_pat(pat, self) + _ => {} } } - _ => noop_fold_pat(pat, self) - }; - - fn record_renamings(const_expr: &hir::Expr, - substituted_pat: &hir::Pat, - renaming_map: &mut FnvHashMap<(NodeId, Span), NodeId>) { - let mut renaming_recorder = RenamingRecorder { - substituted_node_id: substituted_pat.id, - origin_span: substituted_pat.span, - renaming_map: renaming_map, - }; - - renaming_recorder.visit_expr(const_expr); + _ => {} } + + pat.map(|Pat { id, node, span }| { + let node = match node { + PatKind::Binding(binding_mode, pth1, sub) => { + PatKind::Binding(binding_mode, pth1, sub.map(|x| self.fold_pat(x))) + } + PatKind::TupleStruct(pth, pats, ddpos) => { + PatKind::TupleStruct(pth, pats.move_map(|x| self.fold_pat(x)), ddpos) + } + PatKind::Struct(pth, fields, etc) => { + let fs = fields.move_map(|f| { + Spanned { + span: f.span, + node: hir::FieldPat { + name: f.node.name, + pat: self.fold_pat(f.node.pat), + is_shorthand: f.node.is_shorthand, + }, + } + }); + PatKind::Struct(pth, fs, etc) + } + PatKind::Tuple(elts, ddpos) => { + PatKind::Tuple(elts.move_map(|x| self.fold_pat(x)), ddpos) + } + PatKind::Box(inner) => PatKind::Box(self.fold_pat(inner)), + PatKind::Ref(inner, mutbl) => PatKind::Ref(self.fold_pat(inner), mutbl), + PatKind::Vec(before, slice, after) => { + PatKind::Vec(before.move_map(|x| self.fold_pat(x)), + slice.map(|x| self.fold_pat(x)), + after.move_map(|x| self.fold_pat(x))) + } + PatKind::Wild | + PatKind::Lit(_) | + PatKind::Range(..) | + PatKind::Path(..) => node + }; + Pat { + id: id, + node: node, + span: span + } + }) } } @@ -1047,7 +1052,7 @@ pub fn specialize<'a, 'b, 'tcx>( fn check_local(cx: &mut MatchCheckCtxt, loc: &hir::Local) { intravisit::walk_local(cx, loc); - let pat = StaticInliner::new(cx.tcx, None).fold_pat(loc.pat.clone()); + let pat = StaticInliner::new(cx.tcx).fold_pat(loc.pat.clone()); check_irrefutable(cx, &pat, false); // Check legality of move bindings and `@` patterns. diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 3983c098f306..7eb7b24015e1 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -38,7 +38,6 @@ use rustc::middle::privacy::AccessLevels; use rustc::middle::resolve_lifetime::DefRegion::*; use rustc::hir::def::Def; use rustc::hir::def_id::{self, DefId, DefIndex, CRATE_DEF_INDEX}; -use rustc::hir::fold::Folder; use rustc::hir::print as pprust; use rustc::ty::subst::Substs; use rustc::ty::{self, AdtKind}; @@ -774,7 +773,20 @@ impl Lifetime { } impl Clean for hir::Lifetime { - fn clean(&self, _: &DocContext) -> Lifetime { + fn clean(&self, cx: &DocContext) -> Lifetime { + if let Some(tcx) = cx.tcx_opt() { + let def = tcx.named_region_map.defs.get(&self.id).cloned(); + match def { + Some(DefEarlyBoundRegion(_, node_id)) | + Some(DefLateBoundRegion(_, node_id)) | + Some(DefFreeRegion(_, node_id)) => { + if let Some(lt) = cx.lt_substs.borrow().get(&node_id).cloned() { + return lt; + } + } + _ => {} + } + } Lifetime(self.name.to_string()) } } @@ -1629,42 +1641,6 @@ impl From for PrimitiveType { } } -// Poor man's type parameter substitution at HIR level. -// Used to replace private type aliases in public signatures with their aliased types. -struct SubstAlias<'a, 'tcx: 'a> { - tcx: &'a ty::TyCtxt<'a, 'tcx, 'tcx>, - // Table type parameter definition -> substituted type - ty_substs: FnvHashMap, - // Table node id of lifetime parameter definition -> substituted lifetime - lt_substs: FnvHashMap, -} - -impl<'a, 'tcx: 'a, 'b: 'tcx> Folder for SubstAlias<'a, 'tcx> { - fn fold_ty(&mut self, ty: P) -> P { - if let hir::TyPath(..) = ty.node { - let def = self.tcx.expect_def(ty.id); - if let Some(new_ty) = self.ty_substs.get(&def).cloned() { - return P(new_ty); - } - } - hir::fold::noop_fold_ty(ty, self) - } - fn fold_lifetime(&mut self, lt: hir::Lifetime) -> hir::Lifetime { - let def = self.tcx.named_region_map.defs.get(<.id).cloned(); - match def { - Some(DefEarlyBoundRegion(_, node_id)) | - Some(DefLateBoundRegion(_, node_id)) | - Some(DefFreeRegion(_, node_id)) => { - if let Some(lt) = self.lt_substs.get(&node_id).cloned() { - return lt; - } - } - _ => {} - } - hir::fold::noop_fold_lifetime(lt, self) - } -} - impl Clean for hir::Ty { fn clean(&self, cx: &DocContext) -> Type { use rustc::hir::*; @@ -1696,43 +1672,47 @@ impl Clean for hir::Ty { }, TyTup(ref tys) => Tuple(tys.clean(cx)), TyPath(None, ref path) => { - if let Some(tcx) = cx.tcx_opt() { - // Substitute private type aliases - let def = tcx.expect_def(self.id); + let tcx_and_def = cx.tcx_opt().map(|tcx| (tcx, tcx.expect_def(self.id))); + if let Some((_, def)) = tcx_and_def { + if let Some(new_ty) = cx.ty_substs.borrow().get(&def).cloned() { + return new_ty; + } + } + + let tcx_and_alias = tcx_and_def.and_then(|(tcx, def)| { if let Def::TyAlias(def_id) = def { - if let Some(node_id) = tcx.map.as_local_node_id(def_id) { + // Substitute private type aliases + tcx.map.as_local_node_id(def_id).and_then(|node_id| { if !cx.access_levels.borrow().is_exported(def_id) { - let item = tcx.map.expect_item(node_id); - if let hir::ItemTy(ref ty, ref generics) = item.node { - let provided_params = &path.segments.last().unwrap().parameters; - let mut ty_substs = FnvHashMap(); - let mut lt_substs = FnvHashMap(); - for (i, ty_param) in generics.ty_params.iter().enumerate() { - let ty_param_def = tcx.expect_def(ty_param.id); - if let Some(ty) = provided_params.types().get(i).cloned() - .cloned() { - ty_substs.insert(ty_param_def, ty.unwrap()); - } else if let Some(default) = ty_param.default.clone() { - ty_substs.insert(ty_param_def, default.unwrap()); - } - } - for (i, lt_param) in generics.lifetimes.iter().enumerate() { - if let Some(lt) = provided_params.lifetimes().get(i) - .cloned() - .cloned() { - lt_substs.insert(lt_param.lifetime.id, lt); - } - } - let mut subst_alias = SubstAlias { - tcx: &tcx, - ty_substs: ty_substs, - lt_substs: lt_substs - }; - return subst_alias.fold_ty(ty.clone()).clean(cx); - } + Some((tcx, &tcx.map.expect_item(node_id).node)) + } else { + None } + }) + } else { + None + } + }); + if let Some((tcx, &hir::ItemTy(ref ty, ref generics))) = tcx_and_alias { + let provided_params = &path.segments.last().unwrap().parameters; + let mut ty_substs = FnvHashMap(); + let mut lt_substs = FnvHashMap(); + for (i, ty_param) in generics.ty_params.iter().enumerate() { + let ty_param_def = tcx.expect_def(ty_param.id); + if let Some(ty) = provided_params.types().get(i).cloned() + .cloned() { + ty_substs.insert(ty_param_def, ty.unwrap().clean(cx)); + } else if let Some(default) = ty_param.default.clone() { + ty_substs.insert(ty_param_def, default.unwrap().clean(cx)); } } + for (i, lt_param) in generics.lifetimes.iter().enumerate() { + if let Some(lt) = provided_params.lifetimes().get(i).cloned() + .cloned() { + lt_substs.insert(lt_param.lifetime.id, lt.clean(cx)); + } + } + return cx.enter_alias(ty_substs, lt_substs, || ty.clean(cx)); } resolve_type(cx, path.clean(cx), self.id) } diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index ab6858a09310..399702003ea4 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -14,6 +14,7 @@ use rustc_driver::{driver, target_features, abort_on_err}; use rustc::dep_graph::DepGraph; use rustc::session::{self, config}; use rustc::hir::def_id::{CrateNum, DefId}; +use rustc::hir::def::Def; use rustc::middle::privacy::AccessLevels; use rustc::ty::{self, TyCtxt}; use rustc::hir::map as hir_map; @@ -23,12 +24,13 @@ use rustc_trans::back::link; use rustc_resolve as resolve; use rustc_metadata::cstore::CStore; -use syntax::codemap; +use syntax::{ast, codemap}; use syntax::feature_gate::UnstableFeatures; use errors; use errors::emitter::ColorConfig; use std::cell::{RefCell, Cell}; +use std::mem; use std::rc::Rc; use visit_ast::RustdocVisitor; @@ -63,6 +65,14 @@ pub struct DocContext<'a, 'tcx: 'a> { pub renderinfo: RefCell, /// Later on moved through `clean::Crate` into `html::render::CACHE_KEY` pub external_traits: RefCell>, + + // The current set of type and lifetime substitutions, + // for expanding type aliases at the HIR level: + + /// Table type parameter definition -> substituted type + pub ty_substs: RefCell>, + /// Table node id of lifetime parameter definition -> substituted lifetime + pub lt_substs: RefCell>, } impl<'b, 'tcx> DocContext<'b, 'tcx> { @@ -84,6 +94,22 @@ impl<'b, 'tcx> DocContext<'b, 'tcx> { let tcx_opt = self.tcx_opt(); tcx_opt.expect("tcx not present") } + + /// Call the closure with the given parameters set as + /// the substitutions for a type alias' RHS. + pub fn enter_alias(&self, + ty_substs: FnvHashMap, + lt_substs: FnvHashMap, + f: F) -> R + where F: FnOnce() -> R { + let (old_tys, old_lts) = + (mem::replace(&mut *self.ty_substs.borrow_mut(), ty_substs), + mem::replace(&mut *self.lt_substs.borrow_mut(), lt_substs)); + let r = f(); + *self.ty_substs.borrow_mut() = old_tys; + *self.lt_substs.borrow_mut() = old_lts; + r + } } pub trait DocAccessLevels { @@ -179,12 +205,14 @@ pub fn run_core(search_paths: SearchPaths, map: &tcx.map, maybe_typed: Typed(tcx), input: input, - populated_crate_impls: RefCell::new(FnvHashSet()), + populated_crate_impls: Default::default(), deref_trait_did: Cell::new(None), deref_mut_trait_did: Cell::new(None), access_levels: RefCell::new(access_levels), - external_traits: RefCell::new(FnvHashMap()), - renderinfo: RefCell::new(Default::default()), + external_traits: Default::default(), + renderinfo: Default::default(), + ty_substs: Default::default(), + lt_substs: Default::default(), }; debug!("crate: {:?}", ctxt.map.krate()); diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 851cf95f9968..3d2caeda1468 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::cell::{RefCell, Cell}; +use std::cell::Cell; use std::env; use std::ffi::OsString; use std::io::prelude::*; @@ -28,7 +28,6 @@ use rustc::session::{self, config}; use rustc::session::config::{get_unstable_features_setting, OutputType, OutputTypes, Externs}; use rustc::session::search_paths::{SearchPaths, PathKind}; -use rustc::util::nodemap::{FnvHashMap, FnvHashSet}; use rustc_back::dynamic_lib::DynamicLibrary; use rustc_back::tempdir::TempDir; use rustc_driver::{driver, Compilation}; @@ -107,12 +106,14 @@ pub fn run(input: &str, map: &map, maybe_typed: core::NotTyped(&sess), input: input, - external_traits: RefCell::new(FnvHashMap()), - populated_crate_impls: RefCell::new(FnvHashSet()), + external_traits: Default::default(), + populated_crate_impls: Default::default(), deref_trait_did: Cell::new(None), deref_mut_trait_did: Cell::new(None), access_levels: Default::default(), renderinfo: Default::default(), + ty_substs: Default::default(), + lt_substs: Default::default(), }; let mut v = RustdocVisitor::new(&ctx); From 2ce0e6d4e7a8150c4bb1019b7a8276d373c9a307 Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Thu, 1 Sep 2016 11:04:21 +0300 Subject: [PATCH 415/443] rustc_trans: use the TypeId hashing mechanism instead of metadata. --- src/librustc/middle/cstore.rs | 12 ------- src/librustc/ty/util.rs | 28 +++++++++------ src/librustc_metadata/csearch.rs | 8 ----- src/librustc_metadata/encoder.rs | 17 +-------- src/librustc_trans/back/symbol_names.rs | 47 ++++++++++++++----------- 5 files changed, 45 insertions(+), 67 deletions(-) diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 55a895b37ee3..513fa30861ad 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -258,11 +258,6 @@ pub trait CrateStore<'tcx> { // utility functions fn metadata_filename(&self) -> &str; fn metadata_section_name(&self, target: &Target) -> &str; - fn encode_type<'a>(&self, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - ty: Ty<'tcx>, - def_id_to_string: for<'b> fn(TyCtxt<'b, 'tcx, 'tcx>, DefId) -> String) - -> Vec; fn used_crates(&self, prefer: LinkagePreference) -> Vec<(CrateNum, Option)>; fn used_crate_source(&self, cnum: CrateNum) -> CrateSource; fn extern_mod_stmt_cnum(&self, emod_id: ast::NodeId) -> Option; @@ -469,13 +464,6 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { // utility functions fn metadata_filename(&self) -> &str { bug!("metadata_filename") } fn metadata_section_name(&self, target: &Target) -> &str { bug!("metadata_section_name") } - fn encode_type<'a>(&self, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - ty: Ty<'tcx>, - def_id_to_string: for<'b> fn(TyCtxt<'b, 'tcx, 'tcx>, DefId) -> String) - -> Vec { - bug!("encode_type") - } fn used_crates(&self, prefer: LinkagePreference) -> Vec<(CrateNum, Option)> { vec![] } fn used_crate_source(&self, cnum: CrateNum) -> CrateSource { bug!("used_crate_source") } diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 2090877fb3c9..5c71f348b992 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -352,12 +352,9 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// Creates a hash of the type `Ty` which will be the same no matter what crate /// context it's calculated within. This is used by the `type_id` intrinsic. pub fn type_id_hash(self, ty: Ty<'tcx>) -> u64 { - let mut hasher = TypeIdHasher { - tcx: self, - state: SipHasher::new() - }; + let mut hasher = TypeIdHasher::new(self, SipHasher::new()); hasher.visit_ty(ty); - hasher.state.finish() + hasher.finish() } /// Returns true if this ADT is a dtorck type. @@ -391,16 +388,27 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } } -struct TypeIdHasher<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { +pub struct TypeIdHasher<'a, 'gcx: 'a+'tcx, 'tcx: 'a, H> { tcx: TyCtxt<'a, 'gcx, 'tcx>, - state: SipHasher + state: H } -impl<'a, 'gcx, 'tcx> TypeIdHasher<'a, 'gcx, 'tcx> { - fn hash(&mut self, x: T) { +impl<'a, 'gcx, 'tcx, H: Hasher> TypeIdHasher<'a, 'gcx, 'tcx, H> { + pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>, state: H) -> Self { + TypeIdHasher { + tcx: tcx, + state: state + } + } + + pub fn hash(&mut self, x: T) { x.hash(&mut self.state); } + pub fn finish(self) -> u64 { + self.state.finish() + } + fn hash_discriminant_u8(&mut self, x: &T) { let v = unsafe { intrinsics::discriminant_value(x) @@ -419,7 +427,7 @@ impl<'a, 'gcx, 'tcx> TypeIdHasher<'a, 'gcx, 'tcx> { } } -impl<'a, 'gcx, 'tcx> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tcx> { +impl<'a, 'gcx, 'tcx, H: Hasher> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tcx, H> { fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool { // Distinguish between the Ty variants uniformly. self.hash_discriminant_u8(&ty.sty); diff --git a/src/librustc_metadata/csearch.rs b/src/librustc_metadata/csearch.rs index a30a5743c34f..aae87005bf42 100644 --- a/src/librustc_metadata/csearch.rs +++ b/src/librustc_metadata/csearch.rs @@ -677,14 +677,6 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { { loader::meta_section_name(target) } - fn encode_type<'a>(&self, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - ty: Ty<'tcx>, - def_id_to_string: for<'b> fn(TyCtxt<'b, 'tcx, 'tcx>, DefId) -> String) - -> Vec - { - encoder::encoded_ty(tcx, ty, def_id_to_string) - } fn used_crates(&self, prefer: LinkagePreference) -> Vec<(CrateNum, Option)> { diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 9773823c77de..409982289d81 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -36,9 +36,8 @@ use rustc::session::config::{self, PanicStrategy, CrateTypeRustcMacro}; use rustc::util::nodemap::{FnvHashMap, NodeSet}; use rustc_serialize::{Encodable, SpecializedEncoder}; -use std::cell::RefCell; use std::io::prelude::*; -use std::io::{Cursor, SeekFrom}; +use std::io::SeekFrom; use std::ops::{Deref, DerefMut}; use std::rc::Rc; use std::u32; @@ -1891,17 +1890,3 @@ fn encode_metadata_inner(ecx: &mut EncodeContext, krate: &hir::Crate) { println!(" total bytes: {}", stats.total_bytes); } } - -// Get the encoded string for a type -pub fn encoded_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - t: Ty<'tcx>, - def_id_to_string: for<'b> fn(TyCtxt<'b, 'tcx, 'tcx>, DefId) -> String) - -> Vec { - let mut wr = Cursor::new(Vec::new()); - tyencode::enc_ty(&mut wr, &tyencode::ctxt { - ds: def_id_to_string, - tcx: tcx, - abbrevs: &RefCell::new(FnvHashMap()) - }, t); - wr.into_inner() -} diff --git a/src/librustc_trans/back/symbol_names.rs b/src/librustc_trans/back/symbol_names.rs index ab1474c23513..500e9edebf3f 100644 --- a/src/librustc_trans/back/symbol_names.rs +++ b/src/librustc_trans/back/symbol_names.rs @@ -102,9 +102,10 @@ use monomorphize::Instance; use util::sha2::{Digest, Sha256}; use rustc::middle::weak_lang_items; -use rustc::hir::def_id::{DefId, LOCAL_CRATE}; +use rustc::hir::def_id::LOCAL_CRATE; use rustc::hir::map as hir_map; -use rustc::ty::{Ty, TyCtxt, TypeFoldable}; +use rustc::ty::{self, Ty, TypeFoldable}; +use rustc::ty::fold::TypeVisitor; use rustc::ty::item_path::{self, ItemPathBuffer, RootMode}; use rustc::ty::subst::Substs; use rustc::hir::map::definitions::{DefPath, DefPathData}; @@ -114,9 +115,18 @@ use syntax::attr; use syntax::parse::token::{self, InternedString}; use serialize::hex::ToHex; -pub fn def_id_to_string<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> String { - let def_path = tcx.def_path(def_id); - def_path.to_string(tcx) +use std::hash::Hasher; + +struct Sha256Hasher<'a>(&'a mut Sha256); + +impl<'a> Hasher for Sha256Hasher<'a> { + fn write(&mut self, msg: &[u8]) { + self.0.input(msg) + } + + fn finish(&self) -> u64 { + bug!("Sha256Hasher::finish should not be called"); + } } fn get_symbol_hash<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, @@ -132,48 +142,43 @@ fn get_symbol_hash<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, // values for generic type parameters, // if any. - substs: Option<&Substs<'tcx>>) + substs: Option<&'tcx Substs<'tcx>>) -> String { debug!("get_symbol_hash(def_path={:?}, parameters={:?})", def_path, substs); let tcx = scx.tcx(); - return record_time(&tcx.sess.perf_stats.symbol_hash_time, || { - let mut hash_state = scx.symbol_hasher().borrow_mut(); - + let mut hash_state = scx.symbol_hasher().borrow_mut(); + record_time(&tcx.sess.perf_stats.symbol_hash_time, || { hash_state.reset(); + let mut hasher = ty::util::TypeIdHasher::new(tcx, Sha256Hasher(&mut hash_state)); // the main symbol name is not necessarily unique; hash in the // compiler's internal def-path, guaranteeing each symbol has a // truly unique path - hash_state.input_str(&def_path.to_string(tcx)); + hasher.hash(def_path.to_string(tcx)); // Include the main item-type. Note that, in this case, the // assertions about `needs_subst` may not hold, but this item-type // ought to be the same for every reference anyway. assert!(!item_type.has_erasable_regions()); - let encoded_item_type = tcx.sess.cstore.encode_type(tcx, item_type, def_id_to_string); - hash_state.input(&encoded_item_type[..]); + hasher.visit_ty(item_type); // also include any type parameters (for generic items) if let Some(substs) = substs { - for t in substs.types() { - assert!(!t.has_erasable_regions()); - assert!(!t.needs_subst()); - let encoded_type = tcx.sess.cstore.encode_type(tcx, t, def_id_to_string); - hash_state.input(&encoded_type[..]); - } + assert!(!substs.has_erasable_regions()); + assert!(!substs.needs_subst()); + substs.visit_with(&mut hasher); } - - format!("h{}", truncated_hash_result(&mut *hash_state)) }); - fn truncated_hash_result(symbol_hasher: &mut Sha256) -> String { let output = symbol_hasher.result_bytes(); // 64 bits should be enough to avoid collisions. output[.. 8].to_hex() } + + format!("h{}", truncated_hash_result(&mut hash_state)) } impl<'a, 'tcx> Instance<'tcx> { From 0863012fb9b709aee34190d902f0fce5d34eef9e Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Thu, 1 Sep 2016 16:55:33 +0300 Subject: [PATCH 416/443] Remove librbml and the RBML-tagged auto-encoder/decoder. --- mk/crates.mk | 9 +- mk/tests.mk | 2 +- src/librbml/Cargo.toml | 13 - src/librbml/lib.rs | 63 --- src/librustc/Cargo.toml | 1 - src/librustc/lib.rs | 1 - src/librustc/middle/cstore.rs | 6 +- src/librustc_incremental/Cargo.toml | 3 +- src/librustc_incremental/lib.rs | 1 - src/librustc_incremental/persist/hash.rs | 5 +- src/librustc_incremental/persist/load.rs | 5 +- src/librustc_incremental/persist/save.rs | 2 +- src/librustc_metadata/Cargo.toml | 1 - src/librustc_metadata/astencode.rs | 2 +- src/librustc_metadata/common.rs | 9 +- src/librustc_metadata/csearch.rs | 19 +- src/librustc_metadata/decoder.rs | 59 ++- src/librustc_metadata/encoder.rs | 246 +++++---- src/librustc_metadata/index.rs | 6 +- src/librustc_metadata/index_builder.rs | 13 +- src/librustc_metadata/lib.rs | 3 - src/librustc_metadata/rbml/reader.rs | 595 ++-------------------- src/librustc_metadata/rbml/writer.rs | 379 ++------------ src/librustc_metadata/tydecode.rs | 2 +- src/librustc_metadata/tyencode.rs | 5 +- src/librustc_trans/base.rs | 3 +- src/{librbml => libserialize}/leb128.rs | 0 src/libserialize/lib.rs | 3 + src/{librbml => libserialize}/opaque.rs | 260 +--------- src/libserialize/serialize.rs | 194 ++++--- src/rustc/Cargo.lock | 11 - src/test/run-pass-fulldeps/issue-11881.rs | 6 +- 32 files changed, 411 insertions(+), 1516 deletions(-) delete mode 100644 src/librbml/Cargo.toml delete mode 100644 src/librbml/lib.rs rename src/{librbml => libserialize}/leb128.rs (100%) rename src/{librbml => libserialize}/opaque.rs (64%) diff --git a/mk/crates.mk b/mk/crates.mk index d2c79441d866..86bb3a8ca0cc 100644 --- a/mk/crates.mk +++ b/mk/crates.mk @@ -61,7 +61,7 @@ RUSTC_CRATES := rustc rustc_typeck rustc_mir rustc_borrowck rustc_resolve rustc_ rustc_plugin rustc_metadata rustc_passes rustc_save_analysis \ rustc_const_eval rustc_const_math rustc_incremental rustc_macro HOST_CRATES := syntax syntax_ext proc_macro syntax_pos $(RUSTC_CRATES) rustdoc fmt_macros \ - flate arena graphviz rbml log serialize + flate arena graphviz log serialize TOOLS := compiletest rustdoc rustc rustbook error_index_generator DEPS_core := @@ -96,7 +96,6 @@ DEPS_getopts := std DEPS_graphviz := std DEPS_log := std DEPS_num := std -DEPS_rbml := std log serialize DEPS_serialize := std log DEPS_term := std DEPS_test := std getopts term native:rust_test_helpers @@ -110,7 +109,7 @@ DEPS_rustc_const_math := std syntax log serialize DEPS_rustc_const_eval := rustc_const_math rustc syntax log serialize \ rustc_back graphviz syntax_pos -DEPS_rustc := syntax fmt_macros flate arena serialize getopts rbml \ +DEPS_rustc := syntax fmt_macros flate arena serialize getopts \ log graphviz rustc_llvm rustc_back rustc_data_structures\ rustc_const_math syntax_pos rustc_errors DEPS_rustc_back := std syntax flate log libc @@ -126,7 +125,7 @@ DEPS_rustc_errors := log libc serialize syntax_pos DEPS_rustc_lint := rustc log syntax syntax_pos rustc_const_eval DEPS_rustc_llvm := native:rustllvm libc std rustc_bitflags DEPS_rustc_macro := std syntax -DEPS_rustc_metadata := rustc syntax syntax_pos rustc_errors rbml rustc_const_math \ +DEPS_rustc_metadata := rustc syntax syntax_pos rustc_errors rustc_const_math \ rustc_macro syntax_ext DEPS_rustc_passes := syntax syntax_pos rustc core rustc_const_eval rustc_errors DEPS_rustc_mir := rustc syntax syntax_pos rustc_const_math rustc_const_eval rustc_bitflags @@ -137,7 +136,7 @@ DEPS_rustc_privacy := rustc log syntax syntax_pos DEPS_rustc_trans := arena flate getopts graphviz libc rustc rustc_back \ log syntax serialize rustc_llvm rustc_platform_intrinsics \ rustc_const_math rustc_const_eval rustc_incremental rustc_errors syntax_pos -DEPS_rustc_incremental := rbml rustc syntax_pos serialize rustc_data_structures +DEPS_rustc_incremental := rustc syntax_pos serialize rustc_data_structures DEPS_rustc_save_analysis := rustc log syntax syntax_pos serialize DEPS_rustc_typeck := rustc syntax syntax_pos rustc_platform_intrinsics rustc_const_math \ rustc_const_eval rustc_errors diff --git a/mk/tests.mk b/mk/tests.mk index c135aa9b8fb9..fc1f4b5561a7 100644 --- a/mk/tests.mk +++ b/mk/tests.mk @@ -27,7 +27,7 @@ TEST_TARGET_CRATES = $(filter-out core rustc_unicode alloc_system libc \ panic_abort,$(TARGET_CRATES)) \ collectionstest coretest TEST_DOC_CRATES = $(DOC_CRATES) arena flate fmt_macros getopts graphviz \ - log rand rbml serialize syntax term test + log rand serialize syntax term test TEST_HOST_CRATES = $(filter-out rustc_typeck rustc_borrowck rustc_resolve \ rustc_trans rustc_lint,\ $(HOST_CRATES)) diff --git a/src/librbml/Cargo.toml b/src/librbml/Cargo.toml deleted file mode 100644 index ab89ac2b7a1e..000000000000 --- a/src/librbml/Cargo.toml +++ /dev/null @@ -1,13 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rbml" -version = "0.0.0" - -[lib] -name = "rbml" -path = "lib.rs" -crate-type = ["dylib"] - -[dependencies] -log = { path = "../liblog" } -serialize = { path = "../libserialize" } diff --git a/src/librbml/lib.rs b/src/librbml/lib.rs deleted file mode 100644 index 65259f903a99..000000000000 --- a/src/librbml/lib.rs +++ /dev/null @@ -1,63 +0,0 @@ -// 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. - -//! Skeleton of RBML (Really Bad Markup Language). -//! See `src/librustc_metadata/reader.rs` for more details. - -#![crate_name = "rbml"] -#![unstable(feature = "rustc_private", issue = "27812")] -#![crate_type = "rlib"] -#![crate_type = "dylib"] -#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", - html_favicon_url = "https://doc.rust-lang.org/favicon.ico", - html_root_url = "https://doc.rust-lang.org/nightly/", - html_playground_url = "https://play.rust-lang.org/", - test(attr(deny(warnings))))] -#![cfg_attr(not(stage0), deny(warnings))] - -#![feature(rustc_private)] -#![feature(staged_api)] -#![feature(question_mark)] - -#![cfg_attr(test, feature(test))] - -extern crate serialize; - -#[cfg(test)] -extern crate serialize as rustc_serialize; // Used by RustcEncodable - -#[macro_use] -extern crate log; - -#[cfg(test)] -extern crate test; - -pub mod opaque; -pub mod leb128; - -pub use self::Error::*; - -use std::fmt; - -#[derive(Debug)] -pub enum Error { - IntTooBig(usize), - InvalidTag(usize), - Expected(String), - IoError(std::io::Error), - ApplicationError(String), -} - -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - // FIXME: this should be a more useful display form - fmt::Debug::fmt(self, f) - } -} diff --git a/src/librustc/Cargo.toml b/src/librustc/Cargo.toml index aaef8e8423cb..578ef68b0038 100644 --- a/src/librustc/Cargo.toml +++ b/src/librustc/Cargo.toml @@ -14,7 +14,6 @@ flate = { path = "../libflate" } fmt_macros = { path = "../libfmt_macros" } graphviz = { path = "../libgraphviz" } log = { path = "../liblog" } -rbml = { path = "../librbml" } rustc_back = { path = "../librustc_back" } rustc_bitflags = { path = "../librustc_bitflags" } rustc_const_math = { path = "../librustc_const_math" } diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index d2a2f8a972d9..c34286f0195b 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -50,7 +50,6 @@ extern crate fmt_macros; extern crate getopts; extern crate graphviz; extern crate libc; -extern crate rbml; extern crate rustc_llvm as llvm; extern crate rustc_back; extern crate rustc_data_structures; diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 513fa30861ad..1d6047579f6c 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -265,8 +265,7 @@ pub trait CrateStore<'tcx> { reexports: &def::ExportMap, link_meta: &LinkMeta, reachable: &NodeSet, - mir_map: &MirMap<'tcx>, - krate: &hir::Crate) -> Vec; + mir_map: &MirMap<'tcx>) -> Vec; fn metadata_encoding_version(&self) -> &[u8]; } @@ -472,8 +471,7 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { reexports: &def::ExportMap, link_meta: &LinkMeta, reachable: &NodeSet, - mir_map: &MirMap<'tcx>, - krate: &hir::Crate) -> Vec { vec![] } + mir_map: &MirMap<'tcx>) -> Vec { vec![] } fn metadata_encoding_version(&self) -> &[u8] { bug!("metadata_encoding_version") } } diff --git a/src/librustc_incremental/Cargo.toml b/src/librustc_incremental/Cargo.toml index 7db1a6348b27..e3ee75275450 100644 --- a/src/librustc_incremental/Cargo.toml +++ b/src/librustc_incremental/Cargo.toml @@ -10,10 +10,9 @@ crate-type = ["dylib"] [dependencies] graphviz = { path = "../libgraphviz" } -rbml = { path = "../librbml" } rustc = { path = "../librustc" } rustc_data_structures = { path = "../librustc_data_structures" } serialize = { path = "../libserialize" } log = { path = "../liblog" } syntax = { path = "../libsyntax" } -syntax_pos = { path = "../libsyntax_pos" } \ No newline at end of file +syntax_pos = { path = "../libsyntax_pos" } diff --git a/src/librustc_incremental/lib.rs b/src/librustc_incremental/lib.rs index 1f823eedda0d..42b5657e212b 100644 --- a/src/librustc_incremental/lib.rs +++ b/src/librustc_incremental/lib.rs @@ -27,7 +27,6 @@ #![feature(core_intrinsics)] extern crate graphviz; -extern crate rbml; #[macro_use] extern crate rustc; extern crate rustc_data_structures; extern crate serialize as rustc_serialize; diff --git a/src/librustc_incremental/persist/hash.rs b/src/librustc_incremental/persist/hash.rs index 6dcf2c288914..5a4716e45f6e 100644 --- a/src/librustc_incremental/persist/hash.rs +++ b/src/librustc_incremental/persist/hash.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use rbml::Error; -use rbml::opaque::Decoder; use rustc::dep_graph::DepNode; use rustc::hir::def_id::{CrateNum, DefId}; use rustc::hir::svh::Svh; @@ -17,6 +15,7 @@ use rustc::ty::TyCtxt; use rustc_data_structures::fnv::FnvHashMap; use rustc_data_structures::flock; use rustc_serialize::Decodable; +use rustc_serialize::opaque::Decoder; use std::io::{ErrorKind, Read}; use std::fs::File; @@ -188,7 +187,7 @@ impl<'a, 'tcx> HashContext<'a, 'tcx> { fn load_from_data(&mut self, cnum: CrateNum, data: &[u8], - expected_svh: Svh) -> Result<(), Error> { + expected_svh: Svh) -> Result<(), String> { debug!("load_from_data(cnum={})", cnum); // Load up the hashes for the def-ids from this crate. diff --git a/src/librustc_incremental/persist/load.rs b/src/librustc_incremental/persist/load.rs index 6e6464e49683..b051e6c5ab73 100644 --- a/src/librustc_incremental/persist/load.rs +++ b/src/librustc_incremental/persist/load.rs @@ -10,14 +10,13 @@ //! Code to save/load the dep-graph from files. -use rbml::Error; -use rbml::opaque::Decoder; use rustc::dep_graph::DepNode; use rustc::hir::def_id::DefId; use rustc::session::Session; use rustc::ty::TyCtxt; use rustc_data_structures::fnv::FnvHashSet; use rustc_serialize::Decodable as RustcDecodable; +use rustc_serialize::opaque::Decoder; use std::io::Read; use std::fs::{self, File}; use std::path::{Path}; @@ -121,7 +120,7 @@ pub fn decode_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, incremental_hashes_map: &IncrementalHashesMap, dep_graph_data: &[u8], work_products_data: &[u8]) - -> Result<(), Error> + -> Result<(), String> { // Decode the list of work_products let mut work_product_decoder = Decoder::new(work_products_data, 0); diff --git a/src/librustc_incremental/persist/save.rs b/src/librustc_incremental/persist/save.rs index 41212d8e138d..5b45874840f5 100644 --- a/src/librustc_incremental/persist/save.rs +++ b/src/librustc_incremental/persist/save.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use rbml::opaque::Encoder; use rustc::dep_graph::DepNode; use rustc::hir::def_id::DefId; use rustc::hir::svh::Svh; @@ -16,6 +15,7 @@ use rustc::session::Session; use rustc::ty::TyCtxt; use rustc_data_structures::fnv::FnvHashMap; use rustc_serialize::Encodable as RustcEncodable; +use rustc_serialize::opaque::Encoder; use std::hash::{Hash, Hasher, SipHasher}; use std::io::{self, Cursor, Write}; use std::fs::{self, File}; diff --git a/src/librustc_metadata/Cargo.toml b/src/librustc_metadata/Cargo.toml index d70510896b96..fede6f663418 100644 --- a/src/librustc_metadata/Cargo.toml +++ b/src/librustc_metadata/Cargo.toml @@ -11,7 +11,6 @@ crate-type = ["dylib"] [dependencies] flate = { path = "../libflate" } log = { path = "../liblog" } -rbml = { path = "../librbml" } rustc = { path = "../librustc" } rustc_back = { path = "../librustc_back" } rustc_bitflags = { path = "../librustc_bitflags" } diff --git a/src/librustc_metadata/astencode.rs b/src/librustc_metadata/astencode.rs index ce15ec6a29d2..f00c4b82a851 100644 --- a/src/librustc_metadata/astencode.rs +++ b/src/librustc_metadata/astencode.rs @@ -217,7 +217,7 @@ fn encode_side_tables_for_id(ecx: &mut EncodeContext, id: ast::NodeId) { } fn decode_side_tables(dcx: &mut DecodeContext, ast_doc: rbml::Doc) { - while dcx.position() < ast_doc.end { + while dcx.opaque.position() < ast_doc.end { let table = Decodable::decode(dcx).unwrap(); let id = Decodable::decode(dcx).unwrap(); debug!("decode_side_tables: entry for id={}, table={:?}", id, table); diff --git a/src/librustc_metadata/common.rs b/src/librustc_metadata/common.rs index 512f4ca6584c..3b63ee6b5fa8 100644 --- a/src/librustc_metadata/common.rs +++ b/src/librustc_metadata/common.rs @@ -10,12 +10,9 @@ #![allow(non_camel_case_types, non_upper_case_globals)] -// RBML enum definitions and utils shared by the encoder and decoder -// -// 0x00..0x1f: reserved for RBML generic type tags -// 0x20..0xef: free for use, preferred for frequent tags -// 0xf0..0xff: internally used by RBML to encode 0x100..0xfff in two bytes -// 0x100..0xfff: free for use, preferred for infrequent tags +pub const tag_opaque: usize = 0x00; + +// GAP 0x01...0x19 pub const tag_items: usize = 0x100; // top-level only diff --git a/src/librustc_metadata/csearch.rs b/src/librustc_metadata/csearch.rs index aae87005bf42..b291c4927aa3 100644 --- a/src/librustc_metadata/csearch.rs +++ b/src/librustc_metadata/csearch.rs @@ -13,7 +13,6 @@ use common; use decoder; use encoder; use loader; -use rbml; use middle::cstore::{InlinedItem, CrateStore, CrateSource, ChildItem, ExternCrate, DefLike}; use middle::cstore::{NativeLibraryKind, LinkMeta, LinkagePreference}; @@ -30,7 +29,6 @@ use rustc::mir::mir_map::MirMap; use rustc::util::nodemap::{FnvHashMap, NodeSet, DefIdMap}; use rustc::session::config::PanicStrategy; -use std::cell::RefCell; use std::rc::Rc; use std::path::PathBuf; use syntax::ast; @@ -697,22 +695,9 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { reexports: &def::ExportMap, link_meta: &LinkMeta, reachable: &NodeSet, - mir_map: &MirMap<'tcx>, - krate: &hir::Crate) -> Vec + mir_map: &MirMap<'tcx>) -> Vec { - let type_abbrevs = RefCell::new(FnvHashMap()); - let ecx = encoder::EncodeContext { - rbml_w: rbml::writer::Encoder::new(), - tcx: tcx, - reexports: reexports, - link_meta: link_meta, - cstore: self, - reachable: reachable, - mir_map: mir_map, - type_abbrevs: &type_abbrevs, - }; - encoder::encode_metadata(ecx, krate) - + encoder::encode_metadata(tcx, self, reexports, link_meta, reachable, mir_map) } fn metadata_encoding_version(&self) -> &[u8] diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 1bec365e472b..ba593e5be998 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -45,14 +45,14 @@ use rustc_const_math::ConstInt; use rustc::mir::repr::Mir; use std::io; -use std::ops::{Deref, DerefMut}; use std::rc::Rc; use std::str; use std::u32; use rbml::reader; use rbml; -use rustc_serialize::{Decodable, SpecializedDecoder}; +use rustc_serialize::{Decodable, SpecializedDecoder, opaque}; +use rustc_serialize as serialize; use syntax::attr; use syntax::parse::token; use syntax::ast::{self, NodeId}; @@ -60,7 +60,7 @@ use syntax::print::pprust; use syntax_pos::{self, Span, BytePos, NO_EXPANSION}; pub struct DecodeContext<'a, 'tcx: 'a> { - rbml_r: rbml::reader::Decoder<'a>, + pub opaque: opaque::Decoder<'a>, pub tcx: Option>, pub cdata: Option<&'a cstore::CrateMetadata>, pub from_id_range: IdRange, @@ -76,7 +76,7 @@ impl<'doc> rbml::Doc<'doc> { max: NodeId::from_u32(u32::MAX) }; DecodeContext { - rbml_r: reader::Decoder::new(self), + opaque: opaque::Decoder::new(self.data, self.start), cdata: None, tcx: None, from_id_range: id_range, @@ -98,24 +98,49 @@ impl<'a, 'tcx> DecodeContext<'a, 'tcx> { fn read_ty_encoded(&mut self, op: F) -> R where F: for<'x> FnOnce(&mut TyDecoder<'x,'tcx>) -> R { - self.read_opaque(|this, doc| { - Ok(op(&mut TyDecoder::with_doc( - this.tcx(), this.cdata().cnum, doc, - &mut |d| translate_def_id(this.cdata(), d)))) - }).unwrap() + let pos = self.opaque.position(); + let doc = rbml::Doc::at(self.opaque.data, pos); + self.opaque.advance(doc.end - pos); + op(&mut TyDecoder::with_doc(self.tcx(), self.cdata().cnum, doc, + &mut |d| translate_def_id(self.cdata(), d))) } } -impl<'a, 'tcx> Deref for DecodeContext<'a, 'tcx> { - type Target = rbml::reader::Decoder<'a>; - fn deref(&self) -> &Self::Target { - &self.rbml_r +macro_rules! decoder_methods { + ($($name:ident -> $ty:ty;)*) => { + $(fn $name(&mut self) -> Result<$ty, Self::Error> { + self.opaque.$name() + })* } } -impl<'a, 'tcx> DerefMut for DecodeContext<'a, 'tcx> { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.rbml_r +impl<'doc, 'tcx> serialize::Decoder for ::decoder::DecodeContext<'doc, 'tcx> { + type Error = as serialize::Decoder>::Error; + + decoder_methods! { + read_nil -> (); + + read_u64 -> u64; + read_u32 -> u32; + read_u16 -> u16; + read_u8 -> u8; + read_usize -> usize; + + read_i64 -> i64; + read_i32 -> i32; + read_i16 -> i16; + read_i8 -> i8; + read_isize -> isize; + + read_bool -> bool; + read_f64 -> f64; + read_f32 -> f32; + read_char -> char; + read_str -> String; + } + + fn error(&mut self, err: &str) -> Self::Error { + self.opaque.error(err) } } @@ -256,7 +281,7 @@ pub type Cmd<'a> = &'a CrateMetadata; impl CrateMetadata { fn get_item(&self, item_id: DefIndex) -> Option { self.index.lookup_item(self.data(), item_id).map(|pos| { - reader::doc_at(self.data(), pos as usize).unwrap().doc + rbml::Doc::at(self.data(), pos as usize) }) } diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 409982289d81..4b603fcb1055 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -35,9 +35,10 @@ use rustc::mir::mir_map::MirMap; use rustc::session::config::{self, PanicStrategy, CrateTypeRustcMacro}; use rustc::util::nodemap::{FnvHashMap, NodeSet}; -use rustc_serialize::{Encodable, SpecializedEncoder}; +use rustc_serialize::{Encodable, SpecializedEncoder, opaque}; +use rustc_serialize as serialize; use std::io::prelude::*; -use std::io::SeekFrom; +use std::io::Cursor; use std::ops::{Deref, DerefMut}; use std::rc::Rc; use std::u32; @@ -55,7 +56,7 @@ use rustc::hir::map::DefKey; use super::index_builder::{FromId, IndexBuilder, ItemContentBuilder, Untracked, XRef}; pub struct EncodeContext<'a, 'tcx: 'a> { - pub rbml_w: rbml::writer::Encoder, + pub rbml_w: rbml::writer::Encoder<'a>, pub tcx: TyCtxt<'a, 'tcx, 'tcx>, pub reexports: &'a def::ExportMap, pub link_meta: &'a LinkMeta, @@ -66,7 +67,7 @@ pub struct EncodeContext<'a, 'tcx: 'a> { } impl<'a, 'tcx> Deref for EncodeContext<'a, 'tcx> { - type Target = rbml::writer::Encoder; + type Target = rbml::writer::Encoder<'a>; fn deref(&self) -> &Self::Target { &self.rbml_w } @@ -78,21 +79,61 @@ impl<'a, 'tcx> DerefMut for EncodeContext<'a, 'tcx> { } } +macro_rules! encoder_methods { + ($($name:ident($ty:ty);)*) => { + $(fn $name(&mut self, value: $ty) -> Result<(), Self::Error> { + self.opaque.$name(value) + })* + } +} + +impl<'a, 'tcx> serialize::Encoder for ::encoder::EncodeContext<'a, 'tcx> { + type Error = as serialize::Encoder>::Error; + + fn emit_nil(&mut self) -> Result<(), Self::Error> { + Ok(()) + } + + encoder_methods! { + emit_usize(usize); + emit_u64(u64); + emit_u32(u32); + emit_u16(u16); + emit_u8(u8); + + emit_isize(isize); + emit_i64(i64); + emit_i32(i32); + emit_i16(i16); + emit_i8(i8); + + emit_bool(bool); + emit_f64(f64); + emit_f32(f32); + emit_char(char); + emit_str(&str); + } +} + impl<'a, 'tcx> SpecializedEncoder> for EncodeContext<'a, 'tcx> { fn specialized_encode(&mut self, ty: &Ty<'tcx>) -> Result<(), Self::Error> { let cx = self.ty_str_ctxt(); - self.emit_opaque(|opaque_encoder| { - Ok(tyencode::enc_ty(opaque_encoder.cursor, &cx, ty)) - }) + + self.start_tag(tag_opaque)?; + tyencode::enc_ty(&mut self.rbml_w.opaque.cursor, &cx, ty); + self.mark_stable_position(); + self.end_tag() } } impl<'a, 'tcx> SpecializedEncoder<&'tcx Substs<'tcx>> for EncodeContext<'a, 'tcx> { fn specialized_encode(&mut self, substs: &&'tcx Substs<'tcx>) -> Result<(), Self::Error> { let cx = self.ty_str_ctxt(); - self.emit_opaque(|opaque_encoder| { - Ok(tyencode::enc_substs(opaque_encoder.cursor, &cx, substs)) - }) + + self.start_tag(tag_opaque)?; + tyencode::enc_substs(&mut self.rbml_w.opaque.cursor, &cx, substs); + self.mark_stable_position(); + self.end_tag() } } @@ -124,7 +165,7 @@ fn encode_trait_ref<'a, 'tcx>(ecx: &mut EncodeContext<'a, 'tcx>, tag: usize) { let cx = ecx.ty_str_ctxt(); ecx.start_tag(tag); - tyencode::enc_trait_ref(&mut ecx.writer, &cx, trait_ref); + tyencode::enc_trait_ref(&mut ecx.opaque.cursor, &cx, trait_ref); ecx.mark_stable_position(); ecx.end_tag(); } @@ -173,7 +214,7 @@ fn encode_variant_id(ecx: &mut EncodeContext, vid: DefId) { fn write_closure_type<'a, 'tcx>(ecx: &mut EncodeContext<'a, 'tcx>, closure_type: &ty::ClosureTy<'tcx>) { let cx = ecx.ty_str_ctxt(); - tyencode::enc_closure_ty(&mut ecx.writer, &cx, closure_type); + tyencode::enc_closure_ty(&mut ecx.opaque.cursor, &cx, closure_type); ecx.mark_stable_position(); } @@ -181,7 +222,7 @@ impl<'a, 'b, 'tcx> ItemContentBuilder<'a, 'b, 'tcx> { fn encode_type(&mut self, typ: Ty<'tcx>) { let cx = self.ty_str_ctxt(); self.start_tag(tag_items_data_item_type); - tyencode::enc_ty(&mut self.writer, &cx, typ); + tyencode::enc_ty(&mut self.opaque.cursor, &cx, typ); self.mark_stable_position(); self.end_tag(); } @@ -480,7 +521,7 @@ impl<'a, 'b, 'tcx> ItemContentBuilder<'a, 'b, 'tcx> { { let cx = self.ty_str_ctxt(); self.start_tag(tag_item_generics); - tyencode::enc_generics(&mut self.writer, &cx, generics); + tyencode::enc_generics(&mut self.opaque.cursor, &cx, generics); self.mark_stable_position(); self.end_tag(); self.encode_predicates(predicates, tag_item_predicates); @@ -829,7 +870,7 @@ fn encode_xrefs<'a, 'tcx>(ecx: &mut EncodeContext<'a, 'tcx>, xref_positions[id as usize] = ecx.mark_stable_position() as u32; match xref { XRef::Predicate(p) => { - tyencode::enc_predicate(&mut ecx.writer, &cx, &p) + tyencode::enc_predicate(&mut ecx.opaque.cursor, &cx, &p) } } } @@ -837,7 +878,7 @@ fn encode_xrefs<'a, 'tcx>(ecx: &mut EncodeContext<'a, 'tcx>, ecx.end_tag(); ecx.start_tag(tag_xref_index); - index::write_dense_index(xref_positions, &mut ecx.writer); + index::write_dense_index(xref_positions, &mut ecx.opaque.cursor); ecx.end_tag(); } @@ -1396,7 +1437,7 @@ fn encode_info_for_items<'a, 'tcx>(ecx: &mut EncodeContext<'a, 'tcx>) fn encode_item_index(ecx: &mut EncodeContext, index: IndexData) { ecx.start_tag(tag_index); - index.write_index(&mut ecx.writer); + index.write_index(&mut ecx.opaque.cursor); ecx.end_tag(); } @@ -1710,15 +1751,33 @@ fn encode_panic_strategy(ecx: &mut EncodeContext) { } } -pub fn encode_metadata(mut ecx: EncodeContext, krate: &hir::Crate) -> Vec { - encode_metadata_inner(&mut ecx, krate); +pub fn encode_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + cstore: &cstore::CStore, + reexports: &def::ExportMap, + link_meta: &LinkMeta, + reachable: &NodeSet, + mir_map: &MirMap<'tcx>) -> Vec { + let mut cursor = Cursor::new(vec![]); + cursor.write_all(&[0, 0, 0, 0]).unwrap(); + cursor.write_all(metadata_encoding_version).unwrap(); + // Will be filed with the length after encoding the crate. + cursor.write_all(&[0, 0, 0, 0]).unwrap(); + + encode_metadata_inner(&mut EncodeContext { + rbml_w: rbml::writer::Encoder::new(&mut cursor), + tcx: tcx, + reexports: reexports, + link_meta: link_meta, + cstore: cstore, + reachable: reachable, + mir_map: mir_map, + type_abbrevs: &Default::default(), + }); // RBML compacts the encoded bytes whenever appropriate, // so there are some garbages left after the end of the data. - let metalen = ecx.rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() as usize; - let mut v = ecx.rbml_w.writer.into_inner(); - v.truncate(metalen); - assert_eq!(v.len(), metalen); + let meta_len = cursor.position() as usize; + cursor.get_mut().truncate(meta_len); // And here we run into yet another obscure archive bug: in which metadata // loaded from archives may have trailing garbage bytes. Awhile back one of @@ -1744,55 +1803,17 @@ pub fn encode_metadata(mut ecx: EncodeContext, krate: &hir::Crate) -> Vec { // this metadata, there are 4 zero bytes at the start, which are // treated as a length of 0 by old compilers. - let len = v.len(); - let mut result = vec![]; - result.push(0); - result.push(0); - result.push(0); - result.push(0); - result.extend(metadata_encoding_version.iter().cloned()); - result.push((len >> 24) as u8); - result.push((len >> 16) as u8); - result.push((len >> 8) as u8); - result.push((len >> 0) as u8); - result.extend(v); + let meta_start = 8 + ::common::metadata_encoding_version.len(); + let len = meta_len - meta_start; + let mut result = cursor.into_inner(); + result[meta_start - 4] = (len >> 24) as u8; + result[meta_start - 3] = (len >> 16) as u8; + result[meta_start - 2] = (len >> 8) as u8; + result[meta_start - 1] = (len >> 0) as u8; result } -fn encode_metadata_inner(ecx: &mut EncodeContext, krate: &hir::Crate) { - struct Stats { - attr_bytes: u64, - dep_bytes: u64, - lang_item_bytes: u64, - native_lib_bytes: u64, - plugin_registrar_fn_bytes: u64, - codemap_bytes: u64, - macro_defs_bytes: u64, - impl_bytes: u64, - reachable_bytes: u64, - item_bytes: u64, - index_bytes: u64, - xref_bytes: u64, - zero_bytes: u64, - total_bytes: u64, - } - let mut stats = Stats { - attr_bytes: 0, - dep_bytes: 0, - lang_item_bytes: 0, - native_lib_bytes: 0, - plugin_registrar_fn_bytes: 0, - codemap_bytes: 0, - macro_defs_bytes: 0, - impl_bytes: 0, - reachable_bytes: 0, - item_bytes: 0, - index_bytes: 0, - xref_bytes: 0, - zero_bytes: 0, - total_bytes: 0, - }; - +fn encode_metadata_inner(ecx: &mut EncodeContext) { encode_rustc_version(ecx); let tcx = ecx.tcx; @@ -1804,89 +1825,92 @@ fn encode_metadata_inner(ecx: &mut EncodeContext, krate: &hir::Crate) { encode_dylib_dependency_formats(ecx); encode_panic_strategy(ecx); - let mut i = ecx.writer.seek(SeekFrom::Current(0)).unwrap(); - encode_attributes(ecx, &krate.attrs); - stats.attr_bytes = ecx.writer.seek(SeekFrom::Current(0)).unwrap() - i; + let krate = tcx.map.krate(); - i = ecx.writer.seek(SeekFrom::Current(0)).unwrap(); + let mut i = ecx.position(); + encode_attributes(ecx, &krate.attrs); + let attr_bytes = ecx.position() - i; + + i = ecx.position(); encode_crate_deps(ecx, ecx.cstore); - stats.dep_bytes = ecx.writer.seek(SeekFrom::Current(0)).unwrap() - i; + let dep_bytes = ecx.position() - i; // Encode the language items. - i = ecx.writer.seek(SeekFrom::Current(0)).unwrap(); + i = ecx.position(); encode_lang_items(ecx); - stats.lang_item_bytes = ecx.writer.seek(SeekFrom::Current(0)).unwrap() - i; + let lang_item_bytes = ecx.position() - i; // Encode the native libraries used - i = ecx.writer.seek(SeekFrom::Current(0)).unwrap(); + i = ecx.position(); encode_native_libraries(ecx); - stats.native_lib_bytes = ecx.writer.seek(SeekFrom::Current(0)).unwrap() - i; + let native_lib_bytes = ecx.position() - i; // Encode the plugin registrar function - i = ecx.writer.seek(SeekFrom::Current(0)).unwrap(); + i = ecx.position(); encode_plugin_registrar_fn(ecx); - stats.plugin_registrar_fn_bytes = ecx.writer.seek(SeekFrom::Current(0)).unwrap() - i; + let plugin_registrar_fn_bytes = ecx.position() - i; // Encode codemap - i = ecx.writer.seek(SeekFrom::Current(0)).unwrap(); + i = ecx.position(); encode_codemap(ecx); - stats.codemap_bytes = ecx.writer.seek(SeekFrom::Current(0)).unwrap() - i; + let codemap_bytes = ecx.position() - i; // Encode macro definitions - i = ecx.writer.seek(SeekFrom::Current(0)).unwrap(); + i = ecx.position(); encode_macro_defs(ecx, krate); - stats.macro_defs_bytes = ecx.writer.seek(SeekFrom::Current(0)).unwrap() - i; + let macro_defs_bytes = ecx.position() - i; // Encode the def IDs of impls, for coherence checking. - i = ecx.writer.seek(SeekFrom::Current(0)).unwrap(); + i = ecx.position(); encode_impls(ecx, krate); - stats.impl_bytes = ecx.writer.seek(SeekFrom::Current(0)).unwrap() - i; + let impl_bytes = ecx.position() - i; // Encode reachability info. - i = ecx.writer.seek(SeekFrom::Current(0)).unwrap(); + i = ecx.position(); encode_reachable(ecx); - stats.reachable_bytes = ecx.writer.seek(SeekFrom::Current(0)).unwrap() - i; + let reachable_bytes = ecx.position() - i; // Encode and index the items. ecx.start_tag(tag_items); - i = ecx.writer.seek(SeekFrom::Current(0)).unwrap(); + i = ecx.position(); let (items, xrefs) = encode_info_for_items(ecx); - stats.item_bytes = ecx.writer.seek(SeekFrom::Current(0)).unwrap() - i; + let item_bytes = ecx.position() - i; ecx.end_tag(); - i = ecx.writer.seek(SeekFrom::Current(0)).unwrap(); + i = ecx.position(); encode_item_index(ecx, items); - stats.index_bytes = ecx.writer.seek(SeekFrom::Current(0)).unwrap() - i; + let index_bytes = ecx.position() - i; - i = ecx.writer.seek(SeekFrom::Current(0)).unwrap(); + i = ecx.position(); encode_xrefs(ecx, xrefs); - stats.xref_bytes = ecx.writer.seek(SeekFrom::Current(0)).unwrap() - i; + let xref_bytes = ecx.position() - i; encode_struct_field_attrs(ecx, krate); - stats.total_bytes = ecx.writer.seek(SeekFrom::Current(0)).unwrap(); + let total_bytes = ecx.position(); if ecx.tcx.sess.meta_stats() { - for e in ecx.writer.get_ref() { + let mut zero_bytes = 0; + for e in ecx.opaque.cursor.get_ref() { if *e == 0 { - stats.zero_bytes += 1; + zero_bytes += 1; } } println!("metadata stats:"); - println!(" attribute bytes: {}", stats.attr_bytes); - println!(" dep bytes: {}", stats.dep_bytes); - println!(" lang item bytes: {}", stats.lang_item_bytes); - println!(" native bytes: {}", stats.native_lib_bytes); - println!("plugin registrar bytes: {}", stats.plugin_registrar_fn_bytes); - println!(" codemap bytes: {}", stats.codemap_bytes); - println!(" macro def bytes: {}", stats.macro_defs_bytes); - println!(" impl bytes: {}", stats.impl_bytes); - println!(" reachable bytes: {}", stats.reachable_bytes); - println!(" item bytes: {}", stats.item_bytes); - println!(" index bytes: {}", stats.index_bytes); - println!(" xref bytes: {}", stats.xref_bytes); - println!(" zero bytes: {}", stats.zero_bytes); - println!(" total bytes: {}", stats.total_bytes); + println!(" attribute bytes: {}", attr_bytes); + println!(" dep bytes: {}", dep_bytes); + println!(" lang item bytes: {}", lang_item_bytes); + println!(" native bytes: {}", native_lib_bytes); + println!("plugin registrar bytes: {}", plugin_registrar_fn_bytes); + println!(" codemap bytes: {}", codemap_bytes); + println!(" macro def bytes: {}", macro_defs_bytes); + println!(" impl bytes: {}", impl_bytes); + println!(" reachable bytes: {}", reachable_bytes); + println!(" item bytes: {}", item_bytes); + println!(" index bytes: {}", index_bytes); + println!(" xref bytes: {}", xref_bytes); + println!(" zero bytes: {}", zero_bytes); + println!(" total bytes: {}", total_bytes); } } diff --git a/src/librustc_metadata/index.rs b/src/librustc_metadata/index.rs index b850073462f5..63d7f1b58bb0 100644 --- a/src/librustc_metadata/index.rs +++ b/src/librustc_metadata/index.rs @@ -73,15 +73,15 @@ impl IndexData { } } - pub fn record(&mut self, def_id: DefId, position: u64) { + pub fn record(&mut self, def_id: DefId, position: usize) { assert!(def_id.is_local()); self.record_index(def_id.index, position); } - pub fn record_index(&mut self, item: DefIndex, position: u64) { + pub fn record_index(&mut self, item: DefIndex, position: usize) { let item = item.as_usize(); - assert!(position < (u32::MAX as u64)); + assert!(position < (u32::MAX as usize)); let position = position as u32; assert!(self.positions[item] == u32::MAX, diff --git a/src/librustc_metadata/index_builder.rs b/src/librustc_metadata/index_builder.rs index de2f1c4fb0c8..fd25128575f1 100644 --- a/src/librustc_metadata/index_builder.rs +++ b/src/librustc_metadata/index_builder.rs @@ -28,10 +28,9 @@ //! incremental compilation purposes. //! //! The `IndexBuilder` facilitates both of these. It is created -//! with an RBML encoder isntance (`rbml_w`) along with an -//! `EncodingContext` (`ecx`), which it encapsulates. It has one main -//! method, `record()`. You invoke `record` like so to create a new -//! `data_item` element in the list: +//! with an `EncodingContext` (`ecx`), which it encapsulates. +//! It has one main method, `record()`. You invoke `record` +//! like so to create a new `data_item` element in the list: //! //! ``` //! index.record(some_def_id, callback_fn, data) @@ -43,9 +42,9 @@ //! returns, the `common::data_item` tag will be closed. //! //! The `ItemContentBuilder` is another type that just offers access -//! to the `ecx` and `rbml_w` that were given in, as well as -//! maintaining a list of `xref` instances, which are used to extract -//! common data so it is not re-serialized. +//! to the `ecx` that was given in, as well as maintaining a list of +//! `xref` instances, which are used to extract common data so it is +//! not re-serialized. //! //! `ItemContentBuilder` is a distinct type which does not offer the //! `record` method, so that we can ensure that `common::data_item` elements diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs index 428b33f2bfa6..7205a88618fc 100644 --- a/src/librustc_metadata/lib.rs +++ b/src/librustc_metadata/lib.rs @@ -51,9 +51,6 @@ extern crate rustc_const_math; extern crate test; pub mod rbml { - pub extern crate rbml as rbml_crate; - pub use self::rbml_crate::{Error, leb128, opaque}; - pub mod writer; pub mod reader; pub use self::reader::Doc; diff --git a/src/librustc_metadata/rbml/reader.rs b/src/librustc_metadata/rbml/reader.rs index d66ca38e6244..9bbeb73ce3ec 100644 --- a/src/librustc_metadata/rbml/reader.rs +++ b/src/librustc_metadata/rbml/reader.rs @@ -45,87 +45,13 @@ //! **Data** can be either binary bytes or zero or more nested RBML documents. //! Nested documents cannot overflow, and should be entirely contained //! within a parent document. -//! -//! # Predefined Tags -//! -//! Most RBML tags are defined by the application. -//! (For the rust object metadata, see also `rustc::metadata::common`.) -//! RBML itself does define a set of predefined tags however, -//! intended for the auto-serialization implementation. -//! -//! Predefined tags with an implicit length: -//! -//! - `U8` (`00`): 1-byte unsigned integer. -//! - `U16` (`01`): 2-byte big endian unsigned integer. -//! - `U32` (`02`): 4-byte big endian unsigned integer. -//! - `U64` (`03`): 8-byte big endian unsigned integer. -//! Any of `U*` tags can be used to encode primitive unsigned integer types, -//! as long as it is no greater than the actual size. -//! For example, `u8` can only be represented via the `U8` tag. -//! -//! - `I8` (`04`): 1-byte signed integer. -//! - `I16` (`05`): 2-byte big endian signed integer. -//! - `I32` (`06`): 4-byte big endian signed integer. -//! - `I64` (`07`): 8-byte big endian signed integer. -//! Similar to `U*` tags. Always uses two's complement encoding. -//! -//! - `Bool` (`08`): 1-byte boolean value, `00` for false and `01` for true. -//! -//! - `Char` (`09`): 4-byte big endian Unicode scalar value. -//! Surrogate pairs or out-of-bound values are invalid. -//! -//! - `F32` (`0a`): 4-byte big endian unsigned integer representing -//! IEEE 754 binary32 floating-point format. -//! - `F64` (`0b`): 8-byte big endian unsigned integer representing -//! IEEE 754 binary64 floating-point format. -//! -//! - `Sub8` (`0c`): 1-byte unsigned integer for supplementary information. -//! - `Sub32` (`0d`): 4-byte unsigned integer for supplementary information. -//! Those two tags normally occur as the first subdocument of certain tags, -//! namely `Enum`, `Vec` and `Map`, to provide a variant or size information. -//! They can be used interchangeably. -//! -//! Predefined tags with an explicit length: -//! -//! - `Str` (`10`): A UTF-8-encoded string. -//! -//! - `Enum` (`11`): An enum. -//! The first subdocument should be `Sub*` tags with a variant ID. -//! Subsequent subdocuments, if any, encode variant arguments. -//! -//! - `Vec` (`12`): A vector (sequence). -//! - `VecElt` (`13`): A vector element. -//! The first subdocument should be `Sub*` tags with the number of elements. -//! Subsequent subdocuments should be `VecElt` tag per each element. -//! -//! - `Map` (`14`): A map (associated array). -//! - `MapKey` (`15`): A key part of the map entry. -//! - `MapVal` (`16`): A value part of the map entry. -//! The first subdocument should be `Sub*` tags with the number of entries. -//! Subsequent subdocuments should be an alternating sequence of -//! `MapKey` and `MapVal` tags per each entry. -//! -//! - `Opaque` (`17`): An opaque, custom-format tag. -//! Used to wrap ordinary custom tags or data in the auto-serialized context. -//! Rustc typically uses this to encode type information. -//! -//! First 0x20 tags are reserved by RBML; custom tags start at 0x20. #[cfg(test)] use test::Bencher; -pub use self::EbmlEncoderTag::*; - -use std::char; -use std::isize; -use std::mem::transmute; +use std::fmt; use std::str; -use rustc_serialize as serialize; - -use rbml::Error; -use rbml::Error::*; - #[derive(Clone, Copy)] pub struct Doc<'a> { pub data: &'a [u8], @@ -142,6 +68,17 @@ impl<'doc> Doc<'doc> { } } + pub fn at(data: &'doc [u8], start: usize) -> Doc<'doc> { + let elt_tag = tag_at(data, start).unwrap(); + let elt_size = tag_len_at(data, elt_tag.next).unwrap(); + let end = elt_size.next + elt_size.val; + Doc { + data: data, + start: elt_size.next, + end: end, + } + } + pub fn get(&self, tag: usize) -> Doc<'doc> { get_doc(*self, tag) } @@ -159,54 +96,19 @@ impl<'doc> Doc<'doc> { } } -pub struct TaggedDoc<'a> { - tag: usize, - pub doc: Doc<'a>, +#[derive(Debug)] +pub enum Error { + IntTooBig(usize), + InvalidTag(usize) } -pub type DecodeResult = Result; - -#[derive(Copy, Clone, Debug)] -pub enum EbmlEncoderTag { - // tags 00..1f are reserved for auto-serialization. - // first NUM_IMPLICIT_TAGS tags are implicitly sized and lengths are not encoded. - EsU8 = 0x00, // + 1 byte - EsU16 = 0x01, // + 2 bytes - EsU32 = 0x02, // + 4 bytes - EsU64 = 0x03, // + 8 bytes - EsI8 = 0x04, // + 1 byte - EsI16 = 0x05, // + 2 bytes - EsI32 = 0x06, // + 4 bytes - EsI64 = 0x07, // + 8 bytes - EsBool = 0x08, // + 1 byte - EsChar = 0x09, // + 4 bytes - EsF32 = 0x0a, // + 4 bytes - EsF64 = 0x0b, // + 8 bytes - EsSub8 = 0x0c, // + 1 byte - EsSub32 = 0x0d, // + 4 bytes - // 0x0e and 0x0f are reserved - EsStr = 0x10, - EsEnum = 0x11, // encodes the variant id as the first EsSub* - EsVec = 0x12, // encodes the # of elements as the first EsSub* - EsVecElt = 0x13, - EsMap = 0x14, // encodes the # of pairs as the first EsSub* - EsMapKey = 0x15, - EsMapVal = 0x16, - EsOpaque = 0x17, +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + // FIXME: this should be a more useful display form + fmt::Debug::fmt(self, f) + } } -pub const NUM_IMPLICIT_TAGS: usize = 0x0e; - -#[cfg_attr(rustfmt, rustfmt_skip)] -static TAG_IMPLICIT_LEN: [i8; NUM_IMPLICIT_TAGS] = [ - 1, 2, 4, 8, // EsU* - 1, 2, 4, 8, // ESI* - 1, // EsBool - 4, // EsChar - 4, 8, // EsF* - 1, 4, // EsSub* -]; - // rbml reading macro_rules! try_or { @@ -227,7 +129,7 @@ pub struct Res { pub next: usize, } -pub fn tag_at(data: &[u8], start: usize) -> DecodeResult { +pub fn tag_at(data: &[u8], start: usize) -> Result { let v = data[start] as usize; if v < 0xf0 { Ok(Res { @@ -241,12 +143,12 @@ pub fn tag_at(data: &[u8], start: usize) -> DecodeResult { }) } else { // every tag starting with byte 0xf0 is an overlong form, which is prohibited. - Err(InvalidTag(v)) + Err(Error::InvalidTag(v)) } } #[inline(never)] -fn vuint_at_slow(data: &[u8], start: usize) -> DecodeResult { +fn vuint_at_slow(data: &[u8], start: usize) -> Result { let a = data[start]; if a & 0x80 != 0 { return Ok(Res { @@ -275,10 +177,10 @@ fn vuint_at_slow(data: &[u8], start: usize) -> DecodeResult { next: start + 4, }); } - Err(IntTooBig(a as usize)) + Err(Error::IntTooBig(a as usize)) } -pub fn vuint_at(data: &[u8], start: usize) -> DecodeResult { +pub fn vuint_at(data: &[u8], start: usize) -> Result { if data.len() - start < 4 { return vuint_at_slow(data, start); } @@ -332,36 +234,15 @@ pub fn vuint_at(data: &[u8], start: usize) -> DecodeResult { } } -pub fn tag_len_at(data: &[u8], tag: Res) -> DecodeResult { - if tag.val < NUM_IMPLICIT_TAGS && TAG_IMPLICIT_LEN[tag.val] >= 0 { - Ok(Res { - val: TAG_IMPLICIT_LEN[tag.val] as usize, - next: tag.next, - }) - } else { - vuint_at(data, tag.next) - } -} - -pub fn doc_at<'a>(data: &'a [u8], start: usize) -> DecodeResult> { - let elt_tag = tag_at(data, start)?; - let elt_size = tag_len_at(data, elt_tag)?; - let end = elt_size.next + elt_size.val; - Ok(TaggedDoc { - tag: elt_tag.val, - doc: Doc { - data: data, - start: elt_size.next, - end: end, - }, - }) +pub fn tag_len_at(data: &[u8], next: usize) -> Result { + vuint_at(data, next) } pub fn maybe_get_doc<'a>(d: Doc<'a>, tg: usize) -> Option> { let mut pos = d.start; while pos < d.end { let elt_tag = try_or!(tag_at(d.data, pos), None); - let elt_size = try_or!(tag_len_at(d.data, elt_tag), None); + let elt_size = try_or!(tag_len_at(d.data, elt_tag.next), None); pos = elt_size.next + elt_size.val; if elt_tag.val == tg { return Some(Doc { @@ -378,8 +259,7 @@ pub fn get_doc<'a>(d: Doc<'a>, tg: usize) -> Doc<'a> { match maybe_get_doc(d, tg) { Some(d) => d, None => { - error!("failed to find block with tag {:?}", tg); - panic!(); + bug!("failed to find block with tag {:?}", tg); } } } @@ -404,7 +284,7 @@ impl<'a> Iterator for DocsIterator<'a> { self.d.start = self.d.end; None }); - let elt_size = try_or!(tag_len_at(self.d.data, elt_tag), { + let elt_size = try_or!(tag_len_at(self.d.data, elt_tag.next), { self.d.start = self.d.end; None }); @@ -509,419 +389,6 @@ pub fn doc_as_i64(d: Doc) -> i64 { doc_as_u64(d) as i64 } -pub struct Decoder<'a> { - parent: Doc<'a>, - pos: usize, -} - -impl<'doc> Decoder<'doc> { - pub fn new(d: Doc<'doc>) -> Decoder<'doc> { - Decoder { - parent: d, - pos: d.start, - } - } - - fn next_doc(&mut self, exp_tag: EbmlEncoderTag) -> DecodeResult> { - debug!(". next_doc(exp_tag={:?})", exp_tag); - if self.pos >= self.parent.end { - return Err(Expected(format!("no more documents in current node!"))); - } - let TaggedDoc { tag: r_tag, doc: r_doc } = doc_at(self.parent.data, self.pos)?; - debug!("self.parent={:?}-{:?} self.pos={:?} r_tag={:?} r_doc={:?}-{:?}", - self.parent.start, - self.parent.end, - self.pos, - r_tag, - r_doc.start, - r_doc.end); - if r_tag != (exp_tag as usize) { - return Err(Expected(format!("expected EBML doc with tag {:?} but found tag {:?}", - exp_tag, - r_tag))); - } - if r_doc.end > self.parent.end { - return Err(Expected(format!("invalid EBML, child extends to {:#x}, parent to \ - {:#x}", - r_doc.end, - self.parent.end))); - } - self.pos = r_doc.end; - Ok(r_doc) - } - - fn _next_sub(&mut self) -> DecodeResult { - // empty vector/map optimization - if self.parent.is_empty() { - return Ok(0); - } - - let TaggedDoc { tag: r_tag, doc: r_doc } = doc_at(self.parent.data, self.pos)?; - let r = if r_tag == (EsSub8 as usize) { - doc_as_u8(r_doc) as usize - } else if r_tag == (EsSub32 as usize) { - doc_as_u32(r_doc) as usize - } else { - return Err(Expected(format!("expected EBML doc with tag {:?} or {:?} but found \ - tag {:?}", - EsSub8, - EsSub32, - r_tag))); - }; - if r_doc.end > self.parent.end { - return Err(Expected(format!("invalid EBML, child extends to {:#x}, parent to \ - {:#x}", - r_doc.end, - self.parent.end))); - } - self.pos = r_doc.end; - debug!("_next_sub result={:?}", r); - Ok(r) - } - - // variable-length unsigned integer with different tags. - // `last_tag` should be the largest allowed unsigned integer tag. - // all tags between them should be valid, in the order of u8, u16, u32 and u64. - fn next_uint(&mut self, - last_tag: EbmlEncoderTag) - -> DecodeResult { - if self.pos >= self.parent.end { - return Err(Expected(format!("no more documents in current node!"))); - } - - let TaggedDoc { tag: r_tag, doc: r_doc } = doc_at(self.parent.data, self.pos)?; - let r = if EsU8 as usize <= r_tag && r_tag <= last_tag as usize { - match r_tag - EsU8 as usize { - 0 => doc_as_u8(r_doc) as u64, - 1 => doc_as_u16(r_doc) as u64, - 2 => doc_as_u32(r_doc) as u64, - 3 => doc_as_u64(r_doc), - _ => unreachable!(), - } - } else { - return Err(Expected(format!("expected EBML doc with tag EsU8 through {:?} but \ - found tag {:?}", - last_tag, - r_tag))); - }; - if r_doc.end > self.parent.end { - return Err(Expected(format!("invalid EBML, child extends to {:#x}, parent to \ - {:#x}", - r_doc.end, - self.parent.end))); - } - self.pos = r_doc.end; - debug!("next_uint({:?}) result={:?}", last_tag, r); - Ok(r) - } - - // variable-length signed integer with different tags. - // `last_tag` should be the largest allowed signed integer tag. - // all tags between them should be valid, in the order of i8, i16, i32 and i64. - fn next_int(&mut self, - last_tag: EbmlEncoderTag) - -> DecodeResult { - if self.pos >= self.parent.end { - return Err(Expected(format!("no more documents in current node!"))); - } - - let TaggedDoc { tag: r_tag, doc: r_doc } = doc_at(self.parent.data, self.pos)?; - let r = if EsI8 as usize <= r_tag && r_tag <= last_tag as usize { - match r_tag - EsI8 as usize { - 0 => doc_as_i8(r_doc) as i64, - 1 => doc_as_i16(r_doc) as i64, - 2 => doc_as_i32(r_doc) as i64, - 3 => doc_as_i64(r_doc), - _ => unreachable!(), - } - } else { - return Err(Expected(format!("expected EBML doc with tag EsI8 through {:?} but \ - found tag {:?}", - last_tag, - r_tag))); - }; - if r_doc.end > self.parent.end { - return Err(Expected(format!("invalid EBML, child extends to {:#x}, parent to \ - {:#x}", - r_doc.end, - self.parent.end))); - } - self.pos = r_doc.end; - debug!("next_int({:?}) result={:?}", last_tag, r); - Ok(r) - } - - pub fn position(&self) -> usize { - self.pos - } - - pub fn advance(&mut self, bytes: usize) { - self.pos += bytes; - } -} - -impl<'doc, 'tcx> ::decoder::DecodeContext<'doc, 'tcx> { - pub fn read_opaque(&mut self, op: F) -> DecodeResult - where F: FnOnce(&mut Self, Doc) -> DecodeResult - { - let doc = self.next_doc(EsOpaque)?; - op(self, doc) - } - - fn push_doc(&mut self, exp_tag: EbmlEncoderTag, f: F) -> DecodeResult - where F: FnOnce(&mut Self) -> DecodeResult - { - let d = self.next_doc(exp_tag)?; - let old_parent = self.parent; - let old_pos = self.pos; - self.parent = d; - self.pos = d.start; - let r = f(self)?; - self.parent = old_parent; - self.pos = old_pos; - Ok(r) - } -} - -impl<'doc, 'tcx> serialize::Decoder for ::decoder::DecodeContext<'doc, 'tcx> { - type Error = Error; - fn read_nil(&mut self) -> DecodeResult<()> { - Ok(()) - } - - fn read_u64(&mut self) -> DecodeResult { - self.next_uint(EsU64) - } - fn read_u32(&mut self) -> DecodeResult { - Ok(self.next_uint(EsU32)? as u32) - } - fn read_u16(&mut self) -> DecodeResult { - Ok(self.next_uint(EsU16)? as u16) - } - fn read_u8(&mut self) -> DecodeResult { - Ok(doc_as_u8(self.next_doc(EsU8)?)) - } - fn read_usize(&mut self) -> DecodeResult { - let v = self.read_u64()?; - if v > (::std::usize::MAX as u64) { - Err(IntTooBig(v as usize)) - } else { - Ok(v as usize) - } - } - - fn read_i64(&mut self) -> DecodeResult { - Ok(self.next_int(EsI64)? as i64) - } - fn read_i32(&mut self) -> DecodeResult { - Ok(self.next_int(EsI32)? as i32) - } - fn read_i16(&mut self) -> DecodeResult { - Ok(self.next_int(EsI16)? as i16) - } - fn read_i8(&mut self) -> DecodeResult { - Ok(doc_as_u8(self.next_doc(EsI8)?) as i8) - } - fn read_isize(&mut self) -> DecodeResult { - let v = self.next_int(EsI64)? as i64; - if v > (isize::MAX as i64) || v < (isize::MIN as i64) { - debug!("FIXME \\#6122: Removing this makes this function miscompile"); - Err(IntTooBig(v as usize)) - } else { - Ok(v as isize) - } - } - - fn read_bool(&mut self) -> DecodeResult { - Ok(doc_as_u8(self.next_doc(EsBool)?) != 0) - } - - fn read_f64(&mut self) -> DecodeResult { - let bits = doc_as_u64(self.next_doc(EsF64)?); - Ok(unsafe { transmute(bits) }) - } - fn read_f32(&mut self) -> DecodeResult { - let bits = doc_as_u32(self.next_doc(EsF32)?); - Ok(unsafe { transmute(bits) }) - } - fn read_char(&mut self) -> DecodeResult { - Ok(char::from_u32(doc_as_u32(self.next_doc(EsChar)?)).unwrap()) - } - fn read_str(&mut self) -> DecodeResult { - Ok(self.next_doc(EsStr)?.to_string()) - } - - // Compound types: - fn read_enum(&mut self, name: &str, f: F) -> DecodeResult - where F: FnOnce(&mut Self) -> DecodeResult - { - debug!("read_enum({})", name); - - let doc = self.next_doc(EsEnum)?; - - let (old_parent, old_pos) = (self.parent, self.pos); - self.parent = doc; - self.pos = self.parent.start; - - let result = f(self)?; - - self.parent = old_parent; - self.pos = old_pos; - Ok(result) - } - - fn read_enum_variant(&mut self, _: &[&str], mut f: F) -> DecodeResult - where F: FnMut(&mut Self, usize) -> DecodeResult - { - debug!("read_enum_variant()"); - let idx = self._next_sub()?; - debug!(" idx={}", idx); - - f(self, idx) - } - - fn read_enum_variant_arg(&mut self, idx: usize, f: F) -> DecodeResult - where F: FnOnce(&mut Self) -> DecodeResult - { - debug!("read_enum_variant_arg(idx={})", idx); - f(self) - } - - fn read_enum_struct_variant(&mut self, _: &[&str], mut f: F) -> DecodeResult - where F: FnMut(&mut Self, usize) -> DecodeResult - { - debug!("read_enum_struct_variant()"); - let idx = self._next_sub()?; - debug!(" idx={}", idx); - - f(self, idx) - } - - fn read_enum_struct_variant_field(&mut self, - name: &str, - idx: usize, - f: F) - -> DecodeResult - where F: FnOnce(&mut Self) -> DecodeResult - { - debug!("read_enum_struct_variant_arg(name={}, idx={})", name, idx); - f(self) - } - - fn read_struct(&mut self, name: &str, _: usize, f: F) -> DecodeResult - where F: FnOnce(&mut Self) -> DecodeResult - { - debug!("read_struct(name={})", name); - f(self) - } - - fn read_struct_field(&mut self, name: &str, idx: usize, f: F) -> DecodeResult - where F: FnOnce(&mut Self) -> DecodeResult - { - debug!("read_struct_field(name={}, idx={})", name, idx); - f(self) - } - - fn read_tuple(&mut self, tuple_len: usize, f: F) -> DecodeResult - where F: FnOnce(&mut Self) -> DecodeResult - { - debug!("read_tuple()"); - self.read_seq(move |d, len| { - if len == tuple_len { - f(d) - } else { - Err(Expected(format!("Expected tuple of length `{}`, found tuple of length \ - `{}`", - tuple_len, - len))) - } - }) - } - - fn read_tuple_arg(&mut self, idx: usize, f: F) -> DecodeResult - where F: FnOnce(&mut Self) -> DecodeResult - { - debug!("read_tuple_arg(idx={})", idx); - self.read_seq_elt(idx, f) - } - - fn read_tuple_struct(&mut self, name: &str, len: usize, f: F) -> DecodeResult - where F: FnOnce(&mut Self) -> DecodeResult - { - debug!("read_tuple_struct(name={})", name); - self.read_tuple(len, f) - } - - fn read_tuple_struct_arg(&mut self, idx: usize, f: F) -> DecodeResult - where F: FnOnce(&mut Self) -> DecodeResult - { - debug!("read_tuple_struct_arg(idx={})", idx); - self.read_tuple_arg(idx, f) - } - - fn read_option(&mut self, mut f: F) -> DecodeResult - where F: FnMut(&mut Self, bool) -> DecodeResult - { - debug!("read_option()"); - self.read_enum("Option", move |this| { - this.read_enum_variant(&["None", "Some"], move |this, idx| { - match idx { - 0 => f(this, false), - 1 => f(this, true), - _ => Err(Expected(format!("Expected None or Some"))), - } - }) - }) - } - - fn read_seq(&mut self, f: F) -> DecodeResult - where F: FnOnce(&mut Self, usize) -> DecodeResult - { - debug!("read_seq()"); - self.push_doc(EsVec, move |d| { - let len = d._next_sub()?; - debug!(" len={}", len); - f(d, len) - }) - } - - fn read_seq_elt(&mut self, idx: usize, f: F) -> DecodeResult - where F: FnOnce(&mut Self) -> DecodeResult - { - debug!("read_seq_elt(idx={})", idx); - self.push_doc(EsVecElt, f) - } - - fn read_map(&mut self, f: F) -> DecodeResult - where F: FnOnce(&mut Self, usize) -> DecodeResult - { - debug!("read_map()"); - self.push_doc(EsMap, move |d| { - let len = d._next_sub()?; - debug!(" len={}", len); - f(d, len) - }) - } - - fn read_map_elt_key(&mut self, idx: usize, f: F) -> DecodeResult - where F: FnOnce(&mut Self) -> DecodeResult - { - debug!("read_map_elt_key(idx={})", idx); - self.push_doc(EsMapKey, f) - } - - fn read_map_elt_val(&mut self, idx: usize, f: F) -> DecodeResult - where F: FnOnce(&mut Self) -> DecodeResult - { - debug!("read_map_elt_val(idx={})", idx); - self.push_doc(EsMapVal, f) - } - - fn error(&mut self, err: &str) -> Error { - ApplicationError(err.to_string()) - } -} - #[test] fn test_vuint_at() { let data = &[ diff --git a/src/librustc_metadata/rbml/writer.rs b/src/librustc_metadata/rbml/writer.rs index f22a9d1cd003..94e9b394f1f9 100644 --- a/src/librustc_metadata/rbml/writer.rs +++ b/src/librustc_metadata/rbml/writer.rs @@ -12,19 +12,15 @@ use std::mem; use std::io::prelude::*; use std::io::{self, SeekFrom, Cursor}; -use rbml::opaque; -use rbml::reader::EbmlEncoderTag::*; -use rbml::reader::NUM_IMPLICIT_TAGS; - -use rustc_serialize as serialize; +use rustc_serialize::opaque; pub type EncodeResult = io::Result<()>; // rbml writing -pub struct Encoder { - pub writer: Cursor>, - size_positions: Vec, - relax_limit: u64, // do not move encoded bytes before this position +pub struct Encoder<'a> { + pub opaque: opaque::Encoder<'a>, + size_positions: Vec, + relax_limit: usize, // do not move encoded bytes before this position } const NUM_TAGS: usize = 0x1000; @@ -65,10 +61,10 @@ pub fn write_vuint(w: &mut W, n: usize) -> EncodeResult { Err(io::Error::new(io::ErrorKind::Other, &format!("isize too big: {}", n)[..])) } -impl Encoder { - pub fn new() -> Encoder { +impl<'a> Encoder<'a> { + pub fn new(cursor: &'a mut Cursor>) -> Encoder<'a> { Encoder { - writer: Cursor::new(vec![]), + opaque: opaque::Encoder::new(cursor), size_positions: vec![], relax_limit: 0, } @@ -76,23 +72,21 @@ impl Encoder { pub fn start_tag(&mut self, tag_id: usize) -> EncodeResult { debug!("Start tag {:?}", tag_id); - assert!(tag_id >= NUM_IMPLICIT_TAGS); // Write the enum ID: - write_tag(&mut self.writer, tag_id)?; + write_tag(&mut self.opaque.cursor, tag_id)?; // Write a placeholder four-byte size. - let cur_pos = self.writer.seek(SeekFrom::Current(0))?; + let cur_pos = self.position(); self.size_positions.push(cur_pos); - let zeroes: &[u8] = &[0, 0, 0, 0]; - self.writer.write_all(zeroes) + self.opaque.cursor.write_all(&[0, 0, 0, 0]) } pub fn end_tag(&mut self) -> EncodeResult { let last_size_pos = self.size_positions.pop().unwrap(); - let cur_pos = self.writer.seek(SeekFrom::Current(0))?; - self.writer.seek(SeekFrom::Start(last_size_pos))?; - let size = (cur_pos - last_size_pos - 4) as usize; + let cur_pos = self.position(); + self.opaque.cursor.seek(SeekFrom::Start(last_size_pos as u64))?; + let size = cur_pos - last_size_pos - 4; // relax the size encoding for small tags (bigger tags are costly to move). // we should never try to move the stable positions, however. @@ -101,18 +95,17 @@ impl Encoder { // we can't alter the buffer in place, so have a temporary buffer let mut buf = [0u8; RELAX_MAX_SIZE]; { - let last_size_pos = last_size_pos as usize; - let data = &self.writer.get_ref()[last_size_pos + 4..cur_pos as usize]; + let data = &self.opaque.cursor.get_ref()[last_size_pos + 4..cur_pos]; buf[..size].copy_from_slice(data); } // overwrite the size and data and continue - write_vuint(&mut self.writer, size)?; - self.writer.write_all(&buf[..size])?; + write_vuint(&mut self.opaque.cursor, size)?; + self.opaque.cursor.write_all(&buf[..size])?; } else { // overwrite the size with an overlong encoding and skip past the data - write_sized_vuint(&mut self.writer, size, 4)?; - self.writer.seek(SeekFrom::Start(cur_pos))?; + write_sized_vuint(&mut self.opaque.cursor, size, 4)?; + self.opaque.cursor.seek(SeekFrom::Start(cur_pos as u64))?; } debug!("End tag (size = {:?})", size); @@ -128,10 +121,9 @@ impl Encoder { } pub fn wr_tagged_bytes(&mut self, tag_id: usize, b: &[u8]) -> EncodeResult { - assert!(tag_id >= NUM_IMPLICIT_TAGS); - write_tag(&mut self.writer, tag_id)?; - write_vuint(&mut self.writer, b.len())?; - self.writer.write_all(b) + write_tag(&mut self.opaque.cursor, tag_id)?; + write_vuint(&mut self.opaque.cursor, b.len())?; + self.opaque.cursor.write_all(b) } pub fn wr_tagged_u64(&mut self, tag_id: usize, v: u64) -> EncodeResult { @@ -147,344 +139,37 @@ impl Encoder { self.wr_tagged_u64(tag_id, v as u64) } - #[inline] - pub fn wr_tagged_u16(&mut self, tag_id: usize, v: u16) -> EncodeResult { - self.wr_tagged_u64(tag_id, v as u64) - } - #[inline] pub fn wr_tagged_u8(&mut self, tag_id: usize, v: u8) -> EncodeResult { self.wr_tagged_bytes(tag_id, &[v]) } - #[inline] - pub fn wr_tagged_i64(&mut self, tag_id: usize, v: i64) -> EncodeResult { - self.wr_tagged_u64(tag_id, v as u64) - } - - #[inline] - pub fn wr_tagged_i32(&mut self, tag_id: usize, v: i32) -> EncodeResult { - self.wr_tagged_u32(tag_id, v as u32) - } - - #[inline] - pub fn wr_tagged_i16(&mut self, tag_id: usize, v: i16) -> EncodeResult { - self.wr_tagged_u16(tag_id, v as u16) - } - - #[inline] - pub fn wr_tagged_i8(&mut self, tag_id: usize, v: i8) -> EncodeResult { - self.wr_tagged_bytes(tag_id, &[v as u8]) - } - pub fn wr_tagged_str(&mut self, tag_id: usize, v: &str) -> EncodeResult { self.wr_tagged_bytes(tag_id, v.as_bytes()) } - // for auto-serialization - fn wr_tagged_raw_bytes(&mut self, tag_id: usize, b: &[u8]) -> EncodeResult { - write_tag(&mut self.writer, tag_id)?; - self.writer.write_all(b) - } - - fn wr_tagged_raw_u64(&mut self, tag_id: usize, v: u64) -> EncodeResult { - let bytes: [u8; 8] = unsafe { mem::transmute(v.to_be()) }; - self.wr_tagged_raw_bytes(tag_id, &bytes) - } - - fn wr_tagged_raw_u32(&mut self, tag_id: usize, v: u32) -> EncodeResult { - let bytes: [u8; 4] = unsafe { mem::transmute(v.to_be()) }; - self.wr_tagged_raw_bytes(tag_id, &bytes) - } - - fn wr_tagged_raw_u16(&mut self, tag_id: usize, v: u16) -> EncodeResult { - let bytes: [u8; 2] = unsafe { mem::transmute(v.to_be()) }; - self.wr_tagged_raw_bytes(tag_id, &bytes) - } - - fn wr_tagged_raw_u8(&mut self, tag_id: usize, v: u8) -> EncodeResult { - self.wr_tagged_raw_bytes(tag_id, &[v]) - } - - fn wr_tagged_raw_i64(&mut self, tag_id: usize, v: i64) -> EncodeResult { - self.wr_tagged_raw_u64(tag_id, v as u64) - } - - fn wr_tagged_raw_i32(&mut self, tag_id: usize, v: i32) -> EncodeResult { - self.wr_tagged_raw_u32(tag_id, v as u32) - } - - fn wr_tagged_raw_i16(&mut self, tag_id: usize, v: i16) -> EncodeResult { - self.wr_tagged_raw_u16(tag_id, v as u16) - } - - fn wr_tagged_raw_i8(&mut self, tag_id: usize, v: i8) -> EncodeResult { - self.wr_tagged_raw_bytes(tag_id, &[v as u8]) - } - pub fn wr_bytes(&mut self, b: &[u8]) -> EncodeResult { debug!("Write {:?} bytes", b.len()); - self.writer.write_all(b) + self.opaque.cursor.write_all(b) } pub fn wr_str(&mut self, s: &str) -> EncodeResult { debug!("Write str: {:?}", s); - self.writer.write_all(s.as_bytes()) + self.opaque.cursor.write_all(s.as_bytes()) + } + + pub fn position(&mut self) -> usize { + self.opaque.position() as usize } /// Returns the current position while marking it stable, i.e. /// generated bytes so far wouldn't be affected by relaxation. - pub fn mark_stable_position(&mut self) -> u64 { - let pos = self.writer.seek(SeekFrom::Current(0)).unwrap(); + pub fn mark_stable_position(&mut self) -> usize { + let pos = self.position(); if self.relax_limit < pos { self.relax_limit = pos; } - pos - } - - // used internally to emit things like the vector length and so on - fn _emit_tagged_sub(&mut self, v: usize) -> EncodeResult { - if v as u8 as usize == v { - self.wr_tagged_raw_u8(EsSub8 as usize, v as u8) - } else if v as u32 as usize == v { - self.wr_tagged_raw_u32(EsSub32 as usize, v as u32) - } else { - Err(io::Error::new(io::ErrorKind::Other, - &format!("length or variant id too big: {}", v)[..])) - } - } - - pub fn emit_opaque(&mut self, f: F) -> EncodeResult - where F: FnOnce(&mut opaque::Encoder) -> EncodeResult - { - self.start_tag(EsOpaque as usize)?; - f(&mut opaque::Encoder::new(&mut self.writer))?; - self.mark_stable_position(); - self.end_tag() - } -} - -impl<'a, 'tcx> serialize::Encoder for ::encoder::EncodeContext<'a, 'tcx> { - type Error = io::Error; - - fn emit_nil(&mut self) -> EncodeResult { - Ok(()) - } - - fn emit_usize(&mut self, v: usize) -> EncodeResult { - self.emit_u64(v as u64) - } - fn emit_u64(&mut self, v: u64) -> EncodeResult { - if v as u32 as u64 == v { - self.emit_u32(v as u32) - } else { - self.wr_tagged_raw_u64(EsU64 as usize, v) - } - } - fn emit_u32(&mut self, v: u32) -> EncodeResult { - if v as u16 as u32 == v { - self.emit_u16(v as u16) - } else { - self.wr_tagged_raw_u32(EsU32 as usize, v) - } - } - fn emit_u16(&mut self, v: u16) -> EncodeResult { - if v as u8 as u16 == v { - self.emit_u8(v as u8) - } else { - self.wr_tagged_raw_u16(EsU16 as usize, v) - } - } - fn emit_u8(&mut self, v: u8) -> EncodeResult { - self.wr_tagged_raw_u8(EsU8 as usize, v) - } - - fn emit_isize(&mut self, v: isize) -> EncodeResult { - self.emit_i64(v as i64) - } - fn emit_i64(&mut self, v: i64) -> EncodeResult { - if v as i32 as i64 == v { - self.emit_i32(v as i32) - } else { - self.wr_tagged_raw_i64(EsI64 as usize, v) - } - } - fn emit_i32(&mut self, v: i32) -> EncodeResult { - if v as i16 as i32 == v { - self.emit_i16(v as i16) - } else { - self.wr_tagged_raw_i32(EsI32 as usize, v) - } - } - fn emit_i16(&mut self, v: i16) -> EncodeResult { - if v as i8 as i16 == v { - self.emit_i8(v as i8) - } else { - self.wr_tagged_raw_i16(EsI16 as usize, v) - } - } - fn emit_i8(&mut self, v: i8) -> EncodeResult { - self.wr_tagged_raw_i8(EsI8 as usize, v) - } - - fn emit_bool(&mut self, v: bool) -> EncodeResult { - self.wr_tagged_raw_u8(EsBool as usize, v as u8) - } - - fn emit_f64(&mut self, v: f64) -> EncodeResult { - let bits = unsafe { mem::transmute(v) }; - self.wr_tagged_raw_u64(EsF64 as usize, bits) - } - fn emit_f32(&mut self, v: f32) -> EncodeResult { - let bits = unsafe { mem::transmute(v) }; - self.wr_tagged_raw_u32(EsF32 as usize, bits) - } - fn emit_char(&mut self, v: char) -> EncodeResult { - self.wr_tagged_raw_u32(EsChar as usize, v as u32) - } - - fn emit_str(&mut self, v: &str) -> EncodeResult { - self.wr_tagged_str(EsStr as usize, v) - } - - fn emit_enum(&mut self, _name: &str, f: F) -> EncodeResult - where F: FnOnce(&mut Self) -> EncodeResult - { - self.start_tag(EsEnum as usize)?; - f(self)?; - self.end_tag() - } - - fn emit_enum_variant(&mut self, _: &str, v_id: usize, _: usize, f: F) -> EncodeResult - where F: FnOnce(&mut Self) -> EncodeResult - { - self._emit_tagged_sub(v_id)?; - f(self) - } - - fn emit_enum_variant_arg(&mut self, _: usize, f: F) -> EncodeResult - where F: FnOnce(&mut Self) -> EncodeResult - { - f(self) - } - - fn emit_enum_struct_variant(&mut self, - v_name: &str, - v_id: usize, - cnt: usize, - f: F) - -> EncodeResult - where F: FnOnce(&mut Self) -> EncodeResult - { - self.emit_enum_variant(v_name, v_id, cnt, f) - } - - fn emit_enum_struct_variant_field(&mut self, _: &str, idx: usize, f: F) -> EncodeResult - where F: FnOnce(&mut Self) -> EncodeResult - { - self.emit_enum_variant_arg(idx, f) - } - - fn emit_struct(&mut self, _: &str, _len: usize, f: F) -> EncodeResult - where F: FnOnce(&mut Self) -> EncodeResult - { - f(self) - } - - fn emit_struct_field(&mut self, _name: &str, _: usize, f: F) -> EncodeResult - where F: FnOnce(&mut Self) -> EncodeResult - { - f(self) - } - - fn emit_tuple(&mut self, len: usize, f: F) -> EncodeResult - where F: FnOnce(&mut Self) -> EncodeResult - { - self.emit_seq(len, f) - } - fn emit_tuple_arg(&mut self, idx: usize, f: F) -> EncodeResult - where F: FnOnce(&mut Self) -> EncodeResult - { - self.emit_seq_elt(idx, f) - } - - fn emit_tuple_struct(&mut self, _: &str, len: usize, f: F) -> EncodeResult - where F: FnOnce(&mut Self) -> EncodeResult - { - self.emit_seq(len, f) - } - fn emit_tuple_struct_arg(&mut self, idx: usize, f: F) -> EncodeResult - where F: FnOnce(&mut Self) -> EncodeResult - { - self.emit_seq_elt(idx, f) - } - - fn emit_option(&mut self, f: F) -> EncodeResult - where F: FnOnce(&mut Self) -> EncodeResult - { - self.emit_enum("Option", f) - } - fn emit_option_none(&mut self) -> EncodeResult { - self.emit_enum_variant("None", 0, 0, |_| Ok(())) - } - fn emit_option_some(&mut self, f: F) -> EncodeResult - where F: FnOnce(&mut Self) -> EncodeResult - { - - self.emit_enum_variant("Some", 1, 1, f) - } - - fn emit_seq(&mut self, len: usize, f: F) -> EncodeResult - where F: FnOnce(&mut Self) -> EncodeResult - { - if len == 0 { - // empty vector optimization - return self.wr_tagged_bytes(EsVec as usize, &[]); - } - - self.start_tag(EsVec as usize)?; - self._emit_tagged_sub(len)?; - f(self)?; - self.end_tag() - } - - fn emit_seq_elt(&mut self, _idx: usize, f: F) -> EncodeResult - where F: FnOnce(&mut Self) -> EncodeResult - { - - self.start_tag(EsVecElt as usize)?; - f(self)?; - self.end_tag() - } - - fn emit_map(&mut self, len: usize, f: F) -> EncodeResult - where F: FnOnce(&mut Self) -> EncodeResult - { - if len == 0 { - // empty map optimization - return self.wr_tagged_bytes(EsMap as usize, &[]); - } - - self.start_tag(EsMap as usize)?; - self._emit_tagged_sub(len)?; - f(self)?; - self.end_tag() - } - - fn emit_map_elt_key(&mut self, _idx: usize, f: F) -> EncodeResult - where F: FnOnce(&mut Self) -> EncodeResult - { - - self.start_tag(EsMapKey as usize)?; - f(self)?; - self.end_tag() - } - - fn emit_map_elt_val(&mut self, _idx: usize, f: F) -> EncodeResult - where F: FnOnce(&mut Self) -> EncodeResult - { - self.start_tag(EsMapVal as usize)?; - f(self)?; - self.end_tag() + let meta_start = 8 + ::common::metadata_encoding_version.len(); + pos - meta_start } } diff --git a/src/librustc_metadata/tydecode.rs b/src/librustc_metadata/tydecode.rs index 6d3b8571d3c3..28e7b8852b30 100644 --- a/src/librustc_metadata/tydecode.rs +++ b/src/librustc_metadata/tydecode.rs @@ -24,7 +24,7 @@ use rustc::ty::subst::{Kind, Substs}; use rustc::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable}; use rbml; -use rbml::leb128; +use rustc_serialize::leb128; use std::str; use syntax::abi; use syntax::ast; diff --git a/src/librustc_metadata/tyencode.rs b/src/librustc_metadata/tyencode.rs index 73996518a156..8cd18d1bfc7e 100644 --- a/src/librustc_metadata/tyencode.rs +++ b/src/librustc_metadata/tyencode.rs @@ -28,7 +28,7 @@ use rustc::hir; use syntax::abi::Abi; use syntax::ast; -use rbml::leb128; +use rustc_serialize::leb128; use encoder; pub struct ctxt<'a, 'tcx: 'a> { @@ -186,9 +186,10 @@ pub fn enc_ty<'a, 'tcx>(w: &mut Cursor>, cx: &ctxt<'a, 'tcx>, t: Ty<'tcx abbrev.write_all(b"#"); { let start_position = abbrev.position() as usize; + let meta_start = 8 + ::common::metadata_encoding_version.len() as u64; let bytes_written = leb128::write_unsigned_leb128(abbrev.get_mut(), start_position, - pos); + pos - meta_start); abbrev.set_position((start_position + bytes_written) as u64); } diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index a6581ae605b5..a10f8c77ac05 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -1346,8 +1346,7 @@ fn write_metadata(cx: &SharedCrateContext, cx.export_map(), cx.link_meta(), reachable_ids, - cx.mir_map(), - cx.tcx().map.krate()); + cx.mir_map()); let mut compressed = cstore.metadata_encoding_version().to_vec(); compressed.extend_from_slice(&flate::deflate_bytes(&metadata)); diff --git a/src/librbml/leb128.rs b/src/libserialize/leb128.rs similarity index 100% rename from src/librbml/leb128.rs rename to src/libserialize/leb128.rs diff --git a/src/libserialize/lib.rs b/src/libserialize/lib.rs index 7082ee5d292d..7cb02e2412c6 100644 --- a/src/libserialize/lib.rs +++ b/src/libserialize/lib.rs @@ -56,6 +56,9 @@ mod collection_impls; pub mod hex; pub mod json; +pub mod opaque; +pub mod leb128; + mod rustc_serialize { pub use serialize::*; } diff --git a/src/librbml/opaque.rs b/src/libserialize/opaque.rs similarity index 64% rename from src/librbml/opaque.rs rename to src/libserialize/opaque.rs index 55ab2afe4454..e97834f63cee 100644 --- a/src/librbml/opaque.rs +++ b/src/libserialize/opaque.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use Error as DecodeError; use leb128::{read_signed_leb128, read_unsigned_leb128, write_signed_leb128, write_unsigned_leb128}; use std::io::{self, Write}; use serialize; @@ -125,131 +124,6 @@ impl<'a> serialize::Encoder for Encoder<'a> { let _ = self.cursor.write_all(v.as_bytes()); Ok(()) } - - fn emit_enum(&mut self, _name: &str, f: F) -> EncodeResult - where F: FnOnce(&mut Self) -> EncodeResult - { - f(self) - } - - fn emit_enum_variant(&mut self, - _v_name: &str, - v_id: usize, - _len: usize, - f: F) - -> EncodeResult - where F: FnOnce(&mut Self) -> EncodeResult - { - self.emit_usize(v_id)?; - f(self) - } - - fn emit_enum_variant_arg(&mut self, _: usize, f: F) -> EncodeResult - where F: FnOnce(&mut Encoder<'a>) -> EncodeResult - { - f(self) - } - - fn emit_enum_struct_variant(&mut self, - v_name: &str, - v_id: usize, - cnt: usize, - f: F) - -> EncodeResult - where F: FnOnce(&mut Encoder<'a>) -> EncodeResult - { - self.emit_enum_variant(v_name, v_id, cnt, f) - } - - fn emit_enum_struct_variant_field(&mut self, _: &str, idx: usize, f: F) -> EncodeResult - where F: FnOnce(&mut Encoder<'a>) -> EncodeResult - { - self.emit_enum_variant_arg(idx, f) - } - - fn emit_struct(&mut self, _: &str, _len: usize, f: F) -> EncodeResult - where F: FnOnce(&mut Encoder<'a>) -> EncodeResult - { - f(self) - } - - fn emit_struct_field(&mut self, _name: &str, _: usize, f: F) -> EncodeResult - where F: FnOnce(&mut Encoder<'a>) -> EncodeResult - { - f(self) - } - - fn emit_tuple(&mut self, len: usize, f: F) -> EncodeResult - where F: FnOnce(&mut Encoder<'a>) -> EncodeResult - { - self.emit_seq(len, f) - } - - fn emit_tuple_arg(&mut self, idx: usize, f: F) -> EncodeResult - where F: FnOnce(&mut Encoder<'a>) -> EncodeResult - { - self.emit_seq_elt(idx, f) - } - - fn emit_tuple_struct(&mut self, _: &str, len: usize, f: F) -> EncodeResult - where F: FnOnce(&mut Encoder<'a>) -> EncodeResult - { - self.emit_seq(len, f) - } - - fn emit_tuple_struct_arg(&mut self, idx: usize, f: F) -> EncodeResult - where F: FnOnce(&mut Encoder<'a>) -> EncodeResult - { - self.emit_seq_elt(idx, f) - } - - fn emit_option(&mut self, f: F) -> EncodeResult - where F: FnOnce(&mut Encoder<'a>) -> EncodeResult - { - self.emit_enum("Option", f) - } - - fn emit_option_none(&mut self) -> EncodeResult { - self.emit_enum_variant("None", 0, 0, |_| Ok(())) - } - - fn emit_option_some(&mut self, f: F) -> EncodeResult - where F: FnOnce(&mut Encoder<'a>) -> EncodeResult - { - self.emit_enum_variant("Some", 1, 1, f) - } - - fn emit_seq(&mut self, len: usize, f: F) -> EncodeResult - where F: FnOnce(&mut Encoder<'a>) -> EncodeResult - { - self.emit_usize(len)?; - f(self) - } - - fn emit_seq_elt(&mut self, _idx: usize, f: F) -> EncodeResult - where F: FnOnce(&mut Encoder<'a>) -> EncodeResult - { - f(self) - } - - fn emit_map(&mut self, len: usize, f: F) -> EncodeResult - where F: FnOnce(&mut Encoder<'a>) -> EncodeResult - { - self.emit_usize(len)?; - f(self) - } - - fn emit_map_elt_key(&mut self, _idx: usize, f: F) -> EncodeResult - where F: FnOnce(&mut Encoder<'a>) -> EncodeResult - { - f(self) - } - - fn emit_map_elt_val(&mut self, _idx: usize, f: F) -> EncodeResult - where F: FnOnce(&mut Encoder<'a>) -> EncodeResult - { - f(self) - } } impl<'a> Encoder<'a> { @@ -302,7 +176,7 @@ macro_rules! read_sleb128 { impl<'a> serialize::Decoder for Decoder<'a> { - type Error = DecodeError; + type Error = String; fn read_nil(&mut self) -> Result<(), Self::Error> { Ok(()) @@ -379,138 +253,8 @@ impl<'a> serialize::Decoder for Decoder<'a> { Ok(s.to_string()) } - fn read_enum(&mut self, _name: &str, f: F) -> Result - where F: FnOnce(&mut Decoder<'a>) -> Result - { - f(self) - } - - fn read_enum_variant(&mut self, _: &[&str], mut f: F) -> Result - where F: FnMut(&mut Decoder<'a>, usize) -> Result - { - let disr = self.read_usize()?; - f(self, disr) - } - - fn read_enum_variant_arg(&mut self, _idx: usize, f: F) -> Result - where F: FnOnce(&mut Decoder<'a>) -> Result - { - f(self) - } - - fn read_enum_struct_variant(&mut self, _: &[&str], mut f: F) -> Result - where F: FnMut(&mut Decoder<'a>, usize) -> Result - { - let disr = self.read_usize()?; - f(self, disr) - } - - fn read_enum_struct_variant_field(&mut self, - _name: &str, - _idx: usize, - f: F) - -> Result - where F: FnOnce(&mut Decoder<'a>) -> Result - { - f(self) - } - - fn read_struct(&mut self, _name: &str, _: usize, f: F) -> Result - where F: FnOnce(&mut Decoder<'a>) -> Result - { - f(self) - } - - fn read_struct_field(&mut self, _name: &str, _idx: usize, f: F) -> Result - where F: FnOnce(&mut Decoder<'a>) -> Result - { - f(self) - } - - fn read_tuple(&mut self, tuple_len: usize, f: F) -> Result - where F: FnOnce(&mut Decoder<'a>) -> Result - { - self.read_seq(move |d, len| { - if len == tuple_len { - f(d) - } else { - let err = format!("Invalid tuple length. Expected {}, found {}", - tuple_len, - len); - Err(DecodeError::Expected(err)) - } - }) - } - - fn read_tuple_arg(&mut self, idx: usize, f: F) -> Result - where F: FnOnce(&mut Decoder<'a>) -> Result - { - self.read_seq_elt(idx, f) - } - - fn read_tuple_struct(&mut self, _name: &str, len: usize, f: F) -> Result - where F: FnOnce(&mut Decoder<'a>) -> Result - { - self.read_tuple(len, f) - } - - fn read_tuple_struct_arg(&mut self, idx: usize, f: F) -> Result - where F: FnOnce(&mut Decoder<'a>) -> Result - { - self.read_tuple_arg(idx, f) - } - - fn read_option(&mut self, mut f: F) -> Result - where F: FnMut(&mut Decoder<'a>, bool) -> Result - { - self.read_enum("Option", move |this| { - this.read_enum_variant(&["None", "Some"], move |this, idx| { - match idx { - 0 => f(this, false), - 1 => f(this, true), - _ => { - let msg = format!("Invalid Option index: {}", idx); - Err(DecodeError::Expected(msg)) - } - } - }) - }) - } - - fn read_seq(&mut self, f: F) -> Result - where F: FnOnce(&mut Decoder<'a>, usize) -> Result - { - let len = self.read_usize()?; - f(self, len) - } - - fn read_seq_elt(&mut self, _idx: usize, f: F) -> Result - where F: FnOnce(&mut Decoder<'a>) -> Result - { - f(self) - } - - fn read_map(&mut self, f: F) -> Result - where F: FnOnce(&mut Decoder<'a>, usize) -> Result - { - let len = self.read_usize()?; - f(self, len) - } - - fn read_map_elt_key(&mut self, _idx: usize, f: F) -> Result - where F: FnOnce(&mut Decoder<'a>) -> Result - { - f(self) - } - - fn read_map_elt_val(&mut self, _idx: usize, f: F) -> Result - where F: FnOnce(&mut Decoder<'a>) -> Result - { - f(self) - } - fn error(&mut self, err: &str) -> Self::Error { - DecodeError::ApplicationError(err.to_string()) + err.to_string() } } diff --git a/src/libserialize/serialize.rs b/src/libserialize/serialize.rs index ba6eefe82bbc..88f6c12e9804 100644 --- a/src/libserialize/serialize.rs +++ b/src/libserialize/serialize.rs @@ -42,66 +42,99 @@ pub trait Encoder { fn emit_str(&mut self, v: &str) -> Result<(), Self::Error>; // Compound types: - fn emit_enum(&mut self, name: &str, f: F) -> Result<(), Self::Error> - where F: FnOnce(&mut Self) -> Result<(), Self::Error>; + fn emit_enum(&mut self, _name: &str, f: F) -> Result<(), Self::Error> + where F: FnOnce(&mut Self) -> Result<(), Self::Error> { f(self) } - fn emit_enum_variant(&mut self, v_name: &str, + fn emit_enum_variant(&mut self, _v_name: &str, v_id: usize, - len: usize, + _len: usize, f: F) -> Result<(), Self::Error> - where F: FnOnce(&mut Self) -> Result<(), Self::Error>; - fn emit_enum_variant_arg(&mut self, a_idx: usize, f: F) + where F: FnOnce(&mut Self) -> Result<(), Self::Error> + { + self.emit_usize(v_id)?; + f(self) + } + fn emit_enum_variant_arg(&mut self, _a_idx: usize, f: F) -> Result<(), Self::Error> - where F: FnOnce(&mut Self) -> Result<(), Self::Error>; + where F: FnOnce(&mut Self) -> Result<(), Self::Error> { f(self) } fn emit_enum_struct_variant(&mut self, v_name: &str, v_id: usize, len: usize, f: F) -> Result<(), Self::Error> - where F: FnOnce(&mut Self) -> Result<(), Self::Error>; + where F: FnOnce(&mut Self) -> Result<(), Self::Error> + { + self.emit_enum_variant(v_name, v_id, len, f) + } fn emit_enum_struct_variant_field(&mut self, - f_name: &str, + _f_name: &str, f_idx: usize, f: F) -> Result<(), Self::Error> - where F: FnOnce(&mut Self) -> Result<(), Self::Error>; + where F: FnOnce(&mut Self) -> Result<(), Self::Error> + { + self.emit_enum_variant_arg(f_idx, f) + } - fn emit_struct(&mut self, name: &str, len: usize, f: F) + fn emit_struct(&mut self, _name: &str, _len: usize, f: F) -> Result<(), Self::Error> - where F: FnOnce(&mut Self) -> Result<(), Self::Error>; - fn emit_struct_field(&mut self, f_name: &str, f_idx: usize, f: F) + where F: FnOnce(&mut Self) -> Result<(), Self::Error> { f(self) } + fn emit_struct_field(&mut self, _f_name: &str, _f_idx: usize, f: F) -> Result<(), Self::Error> - where F: FnOnce(&mut Self) -> Result<(), Self::Error>; + where F: FnOnce(&mut Self) -> Result<(), Self::Error> { f(self) } - fn emit_tuple(&mut self, len: usize, f: F) -> Result<(), Self::Error> - where F: FnOnce(&mut Self) -> Result<(), Self::Error>; - fn emit_tuple_arg(&mut self, idx: usize, f: F) -> Result<(), Self::Error> - where F: FnOnce(&mut Self) -> Result<(), Self::Error>; + fn emit_tuple(&mut self, _len: usize, f: F) -> Result<(), Self::Error> + where F: FnOnce(&mut Self) -> Result<(), Self::Error> { f(self) } + fn emit_tuple_arg(&mut self, _idx: usize, f: F) -> Result<(), Self::Error> + where F: FnOnce(&mut Self) -> Result<(), Self::Error> { f(self) } - fn emit_tuple_struct(&mut self, name: &str, len: usize, f: F) + fn emit_tuple_struct(&mut self, _name: &str, len: usize, f: F) -> Result<(), Self::Error> - where F: FnOnce(&mut Self) -> Result<(), Self::Error>; + where F: FnOnce(&mut Self) -> Result<(), Self::Error> + { + self.emit_tuple(len, f) + } fn emit_tuple_struct_arg(&mut self, f_idx: usize, f: F) -> Result<(), Self::Error> - where F: FnOnce(&mut Self) -> Result<(), Self::Error>; + where F: FnOnce(&mut Self) -> Result<(), Self::Error> + { + self.emit_tuple_arg(f_idx, f) + } // Specialized types: fn emit_option(&mut self, f: F) -> Result<(), Self::Error> - where F: FnOnce(&mut Self) -> Result<(), Self::Error>; - fn emit_option_none(&mut self) -> Result<(), Self::Error>; + where F: FnOnce(&mut Self) -> Result<(), Self::Error> + { + self.emit_enum("Option", f) + } + fn emit_option_none(&mut self) -> Result<(), Self::Error> { + self.emit_enum_variant("None", 0, 0, |_| Ok(())) + } fn emit_option_some(&mut self, f: F) -> Result<(), Self::Error> - where F: FnOnce(&mut Self) -> Result<(), Self::Error>; + where F: FnOnce(&mut Self) -> Result<(), Self::Error> + { + + self.emit_enum_variant("Some", 1, 1, f) + } fn emit_seq(&mut self, len: usize, f: F) -> Result<(), Self::Error> - where F: FnOnce(&mut Self) -> Result<(), Self::Error>; - fn emit_seq_elt(&mut self, idx: usize, f: F) -> Result<(), Self::Error> - where F: FnOnce(&mut Self) -> Result<(), Self::Error>; + where F: FnOnce(&mut Self) -> Result<(), Self::Error> + { + self.emit_usize(len)?; + f(self) + } + fn emit_seq_elt(&mut self, _idx: usize, f: F) -> Result<(), Self::Error> + where F: FnOnce(&mut Self) -> Result<(), Self::Error> { f(self) } fn emit_map(&mut self, len: usize, f: F) -> Result<(), Self::Error> - where F: FnOnce(&mut Self) -> Result<(), Self::Error>; - fn emit_map_elt_key(&mut self, idx: usize, f: F) -> Result<(), Self::Error> - where F: FnOnce(&mut Self) -> Result<(), Self::Error>; - fn emit_map_elt_val(&mut self, idx: usize, f: F) -> Result<(), Self::Error> - where F: FnOnce(&mut Self) -> Result<(), Self::Error>; + where F: FnOnce(&mut Self) -> Result<(), Self::Error> + { + self.emit_usize(len)?; + f(self) + } + fn emit_map_elt_key(&mut self, _idx: usize, f: F) -> Result<(), Self::Error> + where F: FnOnce(&mut Self) -> Result<(), Self::Error> { f(self) } + fn emit_map_elt_val(&mut self, _idx: usize, f: F) -> Result<(), Self::Error> + where F: FnOnce(&mut Self) -> Result<(), Self::Error> { f(self) } } pub trait Decoder { @@ -126,66 +159,101 @@ pub trait Decoder { fn read_str(&mut self) -> Result; // Compound types: - fn read_enum(&mut self, name: &str, f: F) -> Result - where F: FnOnce(&mut Self) -> Result; + fn read_enum(&mut self, _name: &str, f: F) -> Result + where F: FnOnce(&mut Self) -> Result { f(self) } - fn read_enum_variant(&mut self, names: &[&str], f: F) + fn read_enum_variant(&mut self, _names: &[&str], mut f: F) -> Result - where F: FnMut(&mut Self, usize) -> Result; - fn read_enum_variant_arg(&mut self, a_idx: usize, f: F) + where F: FnMut(&mut Self, usize) -> Result + { + let disr = self.read_usize()?; + f(self, disr) + } + fn read_enum_variant_arg(&mut self, _a_idx: usize, f: F) -> Result - where F: FnOnce(&mut Self) -> Result; + where F: FnOnce(&mut Self) -> Result { f(self) } fn read_enum_struct_variant(&mut self, names: &[&str], f: F) -> Result - where F: FnMut(&mut Self, usize) -> Result; + where F: FnMut(&mut Self, usize) -> Result + { + self.read_enum_variant(names, f) + } fn read_enum_struct_variant_field(&mut self, - &f_name: &str, + _f_name: &str, f_idx: usize, f: F) -> Result - where F: FnOnce(&mut Self) -> Result; + where F: FnOnce(&mut Self) -> Result + { + self.read_enum_variant_arg(f_idx, f) + } - fn read_struct(&mut self, s_name: &str, len: usize, f: F) + fn read_struct(&mut self, _s_name: &str, _len: usize, f: F) -> Result - where F: FnOnce(&mut Self) -> Result; + where F: FnOnce(&mut Self) -> Result { f(self) } fn read_struct_field(&mut self, - f_name: &str, - f_idx: usize, + _f_name: &str, + _f_idx: usize, f: F) -> Result - where F: FnOnce(&mut Self) -> Result; + where F: FnOnce(&mut Self) -> Result { f(self) } - fn read_tuple(&mut self, len: usize, f: F) -> Result - where F: FnOnce(&mut Self) -> Result; - fn read_tuple_arg(&mut self, a_idx: usize, f: F) + fn read_tuple(&mut self, _len: usize, f: F) -> Result + where F: FnOnce(&mut Self) -> Result { f(self) } + fn read_tuple_arg(&mut self, _a_idx: usize, f: F) -> Result - where F: FnOnce(&mut Self) -> Result; + where F: FnOnce(&mut Self) -> Result { f(self) } - fn read_tuple_struct(&mut self, s_name: &str, len: usize, f: F) + fn read_tuple_struct(&mut self, _s_name: &str, len: usize, f: F) -> Result - where F: FnOnce(&mut Self) -> Result; + where F: FnOnce(&mut Self) -> Result + { + self.read_tuple(len, f) + } fn read_tuple_struct_arg(&mut self, a_idx: usize, f: F) -> Result - where F: FnOnce(&mut Self) -> Result; + where F: FnOnce(&mut Self) -> Result + { + self.read_tuple_arg(a_idx, f) + } // Specialized types: - fn read_option(&mut self, f: F) -> Result - where F: FnMut(&mut Self, bool) -> Result; + fn read_option(&mut self, mut f: F) -> Result + where F: FnMut(&mut Self, bool) -> Result + { + self.read_enum("Option", move |this| { + this.read_enum_variant(&["None", "Some"], move |this, idx| { + match idx { + 0 => f(this, false), + 1 => f(this, true), + _ => Err(this.error("read_option: expected 0 for None or 1 for Some")), + } + }) + }) + } fn read_seq(&mut self, f: F) -> Result - where F: FnOnce(&mut Self, usize) -> Result; - fn read_seq_elt(&mut self, idx: usize, f: F) -> Result - where F: FnOnce(&mut Self) -> Result; + where F: FnOnce(&mut Self, usize) -> Result + { + let len = self.read_usize()?; + f(self, len) + } + fn read_seq_elt(&mut self, _idx: usize, f: F) -> Result + where F: FnOnce(&mut Self) -> Result { f(self) } fn read_map(&mut self, f: F) -> Result - where F: FnOnce(&mut Self, usize) -> Result; - fn read_map_elt_key(&mut self, idx: usize, f: F) + where F: FnOnce(&mut Self, usize) -> Result + { + let len = self.read_usize()?; + f(self, len) + } + fn read_map_elt_key(&mut self, _idx: usize, f: F) -> Result - where F: FnOnce(&mut Self) -> Result; - fn read_map_elt_val(&mut self, idx: usize, f: F) + where F: FnOnce(&mut Self) -> Result { f(self) } + fn read_map_elt_val(&mut self, _idx: usize, f: F) -> Result - where F: FnOnce(&mut Self) -> Result; + where F: FnOnce(&mut Self) -> Result { f(self) } // Failure fn error(&mut self, err: &str) -> Self::Error; diff --git a/src/rustc/Cargo.lock b/src/rustc/Cargo.lock index 3377fc43d8a6..d8a02badceed 100644 --- a/src/rustc/Cargo.lock +++ b/src/rustc/Cargo.lock @@ -50,14 +50,6 @@ dependencies = [ "syntax_pos 0.0.0", ] -[[package]] -name = "rbml" -version = "0.0.0" -dependencies = [ - "log 0.0.0", - "serialize 0.0.0", -] - [[package]] name = "rustc" version = "0.0.0" @@ -67,7 +59,6 @@ dependencies = [ "fmt_macros 0.0.0", "graphviz 0.0.0", "log 0.0.0", - "rbml 0.0.0", "rustc_back 0.0.0", "rustc_bitflags 0.0.0", "rustc_const_math 0.0.0", @@ -185,7 +176,6 @@ version = "0.0.0" dependencies = [ "graphviz 0.0.0", "log 0.0.0", - "rbml 0.0.0", "rustc 0.0.0", "rustc_data_structures 0.0.0", "serialize 0.0.0", @@ -227,7 +217,6 @@ version = "0.0.0" dependencies = [ "flate 0.0.0", "log 0.0.0", - "rbml 0.0.0", "rustc 0.0.0", "rustc_back 0.0.0", "rustc_bitflags 0.0.0", diff --git a/src/test/run-pass-fulldeps/issue-11881.rs b/src/test/run-pass-fulldeps/issue-11881.rs index 9da04f723553..8369d08db36d 100644 --- a/src/test/run-pass-fulldeps/issue-11881.rs +++ b/src/test/run-pass-fulldeps/issue-11881.rs @@ -11,7 +11,6 @@ #![feature(rustc_private)] -extern crate rbml; extern crate serialize; use std::io::Cursor; @@ -21,8 +20,7 @@ use std::slice; use serialize::{Encodable, Encoder}; use serialize::json; - -use rbml::writer; +use serialize::opaque; #[derive(Encodable)] struct Foo { @@ -44,7 +42,7 @@ fn encode_json(val: &T, wr: &mut Cursor>) { write!(wr, "{}", json::as_json(val)); } fn encode_rbml(val: &T, wr: &mut Cursor>) { - let mut encoder = writer::Encoder::new(wr); + let mut encoder = opaque::Encoder::new(wr); val.encode(&mut encoder); } From bcbb4107a1a966ea8ad48d370f553dffde780392 Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Fri, 2 Sep 2016 00:49:29 +0300 Subject: [PATCH 417/443] rustc_metadata: side-step ty{en,de}code for everything but Ty. --- src/librustc/ty/mod.rs | 18 ++-- src/librustc/ty/sty.rs | 10 +- src/librustc/ty/subst.rs | 37 ++++++- src/librustc_metadata/decoder.rs | 65 ++++++------ src/librustc_metadata/encoder.rs | 39 +------ src/librustc_metadata/tydecode.rs | 164 ++---------------------------- src/librustc_metadata/tyencode.rs | 146 ++------------------------ 7 files changed, 99 insertions(+), 380 deletions(-) diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 6cabc25df6af..d4dd8298db3e 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -668,7 +668,7 @@ pub enum IntVarValue { /// from `T:'a` annotations appearing in the type definition. If /// this is `None`, then the default is inherited from the /// surrounding context. See RFC #599 for details. -#[derive(Copy, Clone)] +#[derive(Copy, Clone, RustcEncodable, RustcDecodable)] pub enum ObjectLifetimeDefault<'tcx> { /// Require an explicit annotation. Occurs when multiple /// `T:'a` constraints are found. @@ -681,7 +681,7 @@ pub enum ObjectLifetimeDefault<'tcx> { Specific(&'tcx Region), } -#[derive(Clone)] +#[derive(Clone, RustcEncodable, RustcDecodable)] pub struct TypeParameterDef<'tcx> { pub name: Name, pub def_id: DefId, @@ -691,7 +691,7 @@ pub struct TypeParameterDef<'tcx> { pub object_lifetime_default: ObjectLifetimeDefault<'tcx>, } -#[derive(Clone)] +#[derive(Clone, RustcEncodable, RustcDecodable)] pub struct RegionParameterDef<'tcx> { pub name: Name, pub def_id: DefId, @@ -719,7 +719,7 @@ impl<'tcx> RegionParameterDef<'tcx> { /// Information about the formal type/lifetime parameters associated /// with an item or method. Analogous to hir::Generics. -#[derive(Clone, Debug)] +#[derive(Clone, Debug, RustcEncodable, RustcDecodable)] pub struct Generics<'tcx> { pub parent: Option, pub parent_regions: u32, @@ -786,7 +786,7 @@ impl<'a, 'gcx, 'tcx> GenericPredicates<'tcx> { } } -#[derive(Clone, PartialEq, Eq, Hash)] +#[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] pub enum Predicate<'tcx> { /// Corresponds to `where Foo : Bar`. `Foo` here would be /// the `Self` type of the trait reference and `A`, `B`, and `C` @@ -910,7 +910,7 @@ impl<'a, 'gcx, 'tcx> Predicate<'tcx> { } } -#[derive(Clone, PartialEq, Eq, Hash)] +#[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] pub struct TraitPredicate<'tcx> { pub trait_ref: TraitRef<'tcx> } @@ -967,11 +967,11 @@ impl<'tcx> PolyTraitPredicate<'tcx> { } } -#[derive(Clone, PartialEq, Eq, Hash, Debug)] +#[derive(Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] pub struct EquatePredicate<'tcx>(pub Ty<'tcx>, pub Ty<'tcx>); // `0 == 1` pub type PolyEquatePredicate<'tcx> = ty::Binder>; -#[derive(Clone, PartialEq, Eq, Hash, Debug)] +#[derive(Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] pub struct OutlivesPredicate(pub A, pub B); // `A : B` pub type PolyOutlivesPredicate = ty::Binder>; pub type PolyRegionOutlivesPredicate<'tcx> = PolyOutlivesPredicate<&'tcx ty::Region, @@ -990,7 +990,7 @@ pub type PolyTypeOutlivesPredicate<'tcx> = PolyOutlivesPredicate, &'tcx /// equality between arbitrary types. Processing an instance of Form /// #2 eventually yields one of these `ProjectionPredicate` /// instances to normalize the LHS. -#[derive(Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] pub struct ProjectionPredicate<'tcx> { pub projection_ty: ProjectionTy<'tcx>, pub ty: Ty<'tcx>, diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 5176fb665fbf..0f2ff8a689fa 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -290,7 +290,7 @@ pub struct TraitObject<'tcx> { /// Note that a `TraitRef` introduces a level of region binding, to /// account for higher-ranked trait bounds like `T : for<'a> Foo<&'a /// U>` or higher-ranked object types. -#[derive(Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] pub struct TraitRef<'tcx> { pub def_id: DefId, pub substs: &'tcx Substs<'tcx>, @@ -366,7 +366,7 @@ impl<'tcx> PolyExistentialTraitRef<'tcx> { /// erase, or otherwise "discharge" these bound regions, we change the /// type from `Binder` to just `T` (see /// e.g. `liberate_late_bound_regions`). -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] pub struct Binder(pub T); impl Binder { @@ -414,7 +414,7 @@ impl fmt::Debug for TypeFlags { /// Represents the projection of an associated type. In explicit UFCS /// form this would be written `>::N`. -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] pub struct ProjectionTy<'tcx> { /// The trait reference `T as Trait<..>`. pub trait_ref: ty::TraitRef<'tcx>, @@ -430,7 +430,7 @@ pub struct BareFnTy<'tcx> { pub sig: PolyFnSig<'tcx>, } -#[derive(Clone, PartialEq, Eq, Hash)] +#[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] pub struct ClosureTy<'tcx> { pub unsafety: hir::Unsafety, pub abi: abi::Abi, @@ -443,7 +443,7 @@ pub struct ClosureTy<'tcx> { /// - `inputs` is the list of arguments and their modes. /// - `output` is the return type. /// - `variadic` indicates whether this is a variadic function. (only true for foreign fns) -#[derive(Clone, PartialEq, Eq, Hash)] +#[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] pub struct FnSig<'tcx> { pub inputs: Vec>, pub output: Ty<'tcx>, diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs index 6b493118bcfd..6911d2174260 100644 --- a/src/librustc/ty/subst.rs +++ b/src/librustc/ty/subst.rs @@ -14,7 +14,7 @@ use hir::def_id::DefId; use ty::{self, Ty, TyCtxt}; use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; -use serialize; +use serialize::{self, Encodable, Encoder, Decodable, Decoder}; use syntax_pos::{Span, DUMMY_SP}; use core::nonzero::NonZero; @@ -128,8 +128,40 @@ impl<'tcx> TypeFoldable<'tcx> for Kind<'tcx> { } } +impl<'tcx> Encodable for Kind<'tcx> { + fn encode(&self, e: &mut E) -> Result<(), E::Error> { + e.emit_enum("Kind", |e| { + if let Some(ty) = self.as_type() { + e.emit_enum_variant("Ty", TYPE_TAG, 1, |e| { + e.emit_enum_variant_arg(0, |e| ty.encode(e)) + }) + } else if let Some(r) = self.as_region() { + e.emit_enum_variant("Region", REGION_TAG, 1, |e| { + e.emit_enum_variant_arg(0, |e| r.encode(e)) + }) + } else { + bug!() + } + }) + } +} + +impl<'tcx> Decodable for Kind<'tcx> { + fn decode(d: &mut D) -> Result, D::Error> { + d.read_enum("Kind", |d| { + d.read_enum_variant(&["Ty", "Region"], |d, tag| { + match tag { + TYPE_TAG => Ty::decode(d).map(Kind::from), + REGION_TAG => <&ty::Region>::decode(d).map(Kind::from), + _ => Err(d.error("invalid Kind tag")) + } + }) + }) + } +} + /// A substitution mapping type/region parameters to new values. -#[derive(Clone, PartialEq, Eq, Debug, Hash)] +#[derive(Clone, PartialEq, Eq, Debug, Hash, RustcEncodable, RustcDecodable)] pub struct Substs<'tcx> { params: Vec> } @@ -297,7 +329,6 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx Substs<'tcx> { } } -impl<'tcx> serialize::UseSpecializedEncodable for &'tcx Substs<'tcx> {} impl<'tcx> serialize::UseSpecializedDecodable for &'tcx Substs<'tcx> {} /////////////////////////////////////////////////////////////////////////// diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index ba593e5be998..d3c04874a08e 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -94,16 +94,6 @@ impl<'a, 'tcx> DecodeContext<'a, 'tcx> { pub fn cdata(&self) -> &'a cstore::CrateMetadata { self.cdata.expect("missing CrateMetadata in DecodeContext") } - - fn read_ty_encoded(&mut self, op: F) -> R - where F: for<'x> FnOnce(&mut TyDecoder<'x,'tcx>) -> R - { - let pos = self.opaque.position(); - let doc = rbml::Doc::at(self.opaque.data, pos); - self.opaque.advance(doc.end - pos); - op(&mut TyDecoder::with_doc(self.tcx(), self.cdata().cnum, doc, - &mut |d| translate_def_id(self.cdata(), d))) - } } macro_rules! decoder_methods { @@ -243,13 +233,19 @@ impl<'a, 'tcx> SpecializedDecoder for DecodeContext<'a, 'tcx> { impl<'a, 'tcx> SpecializedDecoder> for DecodeContext<'a, 'tcx> { fn specialized_decode(&mut self) -> Result, Self::Error> { - Ok(self.read_ty_encoded(|d| d.parse_ty())) + let pos = self.opaque.position(); + let doc = rbml::Doc::at(self.opaque.data, pos); + self.opaque.advance(doc.end - pos); + Ok(TyDecoder::with_doc(self.tcx(), self.cdata().cnum, doc, + &mut |d| translate_def_id(self.cdata(), d)) + .parse_ty()) } } impl<'a, 'tcx> SpecializedDecoder<&'tcx Substs<'tcx>> for DecodeContext<'a, 'tcx> { fn specialized_decode(&mut self) -> Result<&'tcx Substs<'tcx>, Self::Error> { - Ok(self.read_ty_encoded(|d| d.parse_substs())) + let substs = Substs::decode(self)?; + Ok(self.tcx().mk_substs(substs)) } } @@ -469,26 +465,25 @@ fn variant_disr_val(d: rbml::Doc) -> u64 { } fn doc_type<'a, 'tcx>(doc: rbml::Doc, tcx: TyCtxt<'a, 'tcx, 'tcx>, cdata: Cmd) -> Ty<'tcx> { - let tp = reader::get_doc(doc, tag_items_data_item_type); - TyDecoder::with_doc(tcx, cdata.cnum, tp, - &mut |did| translate_def_id(cdata, did)) - .parse_ty() + maybe_doc_type(doc, tcx, cdata).expect("missing tag_items_data_item_type") } fn maybe_doc_type<'a, 'tcx>(doc: rbml::Doc, tcx: TyCtxt<'a, 'tcx, 'tcx>, cdata: Cmd) -> Option> { reader::maybe_get_doc(doc, tag_items_data_item_type).map(|tp| { - TyDecoder::with_doc(tcx, cdata.cnum, tp, - &mut |did| translate_def_id(cdata, did)) - .parse_ty() + let mut dcx = tp.decoder(); + dcx.tcx = Some(tcx); + dcx.cdata = Some(cdata); + Decodable::decode(&mut dcx).unwrap() }) } fn doc_trait_ref<'a, 'tcx>(doc: rbml::Doc, tcx: TyCtxt<'a, 'tcx, 'tcx>, cdata: Cmd) -> ty::TraitRef<'tcx> { - TyDecoder::with_doc(tcx, cdata.cnum, doc, - &mut |did| translate_def_id(cdata, did)) - .parse_trait_ref() + let mut dcx = doc.decoder(); + dcx.tcx = Some(tcx); + dcx.cdata = Some(cdata); + Decodable::decode(&mut dcx).unwrap() } fn item_trait_ref<'a, 'tcx>(doc: rbml::Doc, tcx: TyCtxt<'a, 'tcx, 'tcx>, cdata: Cmd) @@ -1628,10 +1623,10 @@ fn doc_generics<'a, 'tcx>(base_doc: rbml::Doc, cdata: Cmd) -> &'tcx ty::Generics<'tcx> { - let doc = reader::get_doc(base_doc, tag_item_generics); - TyDecoder::with_doc(tcx, cdata.cnum, doc, - &mut |did| translate_def_id(cdata, did)) - .parse_generics() + let mut dcx = reader::get_doc(base_doc, tag_item_generics).decoder(); + dcx.tcx = Some(tcx); + dcx.cdata = Some(cdata); + tcx.alloc_generics(Decodable::decode(&mut dcx).unwrap()) } fn doc_predicate<'a, 'tcx>(cdata: Cmd, @@ -1641,10 +1636,14 @@ fn doc_predicate<'a, 'tcx>(cdata: Cmd, { let predicate_pos = cdata.xref_index.lookup( cdata.data(), reader::doc_as_u32(doc)).unwrap() as usize; - TyDecoder::new( - cdata.data(), cdata.cnum, predicate_pos, tcx, - &mut |did| translate_def_id(cdata, did) - ).parse_predicate() + let mut dcx = rbml::Doc { + data: cdata.data(), + start: predicate_pos, + end: cdata.data().len(), + }.decoder(); + dcx.tcx = Some(tcx); + dcx.cdata = Some(cdata); + Decodable::decode(&mut dcx).unwrap() } fn doc_predicates<'a, 'tcx>(base_doc: rbml::Doc, @@ -1694,8 +1693,10 @@ pub fn closure_ty<'a, 'tcx>(cdata: Cmd, closure_id: DefIndex, tcx: TyCtxt<'a, 't -> ty::ClosureTy<'tcx> { let closure_doc = cdata.lookup_item(closure_id); let closure_ty_doc = reader::get_doc(closure_doc, tag_items_closure_ty); - TyDecoder::with_doc(tcx, cdata.cnum, closure_ty_doc, &mut |did| translate_def_id(cdata, did)) - .parse_closure_ty() + let mut dcx = closure_ty_doc.decoder(); + dcx.tcx = Some(tcx); + dcx.cdata = Some(cdata); + Decodable::decode(&mut dcx).unwrap() } pub fn def_key(cdata: Cmd, id: DefIndex) -> hir_map::DefKey { diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 4b603fcb1055..dcc3d13631eb 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -28,7 +28,6 @@ use middle::dependency_format::Linkage; use rustc::dep_graph::DepNode; use rustc::traits::specialization_graph; use rustc::ty::{self, Ty, TyCtxt}; -use rustc::ty::subst::Substs; use rustc::hir::svh::Svh; use rustc::mir::mir_map::MirMap; @@ -126,17 +125,6 @@ impl<'a, 'tcx> SpecializedEncoder> for EncodeContext<'a, 'tcx> { } } -impl<'a, 'tcx> SpecializedEncoder<&'tcx Substs<'tcx>> for EncodeContext<'a, 'tcx> { - fn specialized_encode(&mut self, substs: &&'tcx Substs<'tcx>) -> Result<(), Self::Error> { - let cx = self.ty_str_ctxt(); - - self.start_tag(tag_opaque)?; - tyencode::enc_substs(&mut self.rbml_w.opaque.cursor, &cx, substs); - self.mark_stable_position(); - self.end_tag() - } -} - fn encode_name(ecx: &mut EncodeContext, name: Name) { ecx.wr_tagged_str(tag_paths_data_name, &name.as_str()); } @@ -163,10 +151,8 @@ fn encode_def_id_and_key(ecx: &mut EncodeContext, def_id: DefId) { fn encode_trait_ref<'a, 'tcx>(ecx: &mut EncodeContext<'a, 'tcx>, trait_ref: ty::TraitRef<'tcx>, tag: usize) { - let cx = ecx.ty_str_ctxt(); ecx.start_tag(tag); - tyencode::enc_trait_ref(&mut ecx.opaque.cursor, &cx, trait_ref); - ecx.mark_stable_position(); + trait_ref.encode(ecx).unwrap(); ecx.end_tag(); } @@ -211,19 +197,10 @@ fn encode_variant_id(ecx: &mut EncodeContext, vid: DefId) { ecx.wr_tagged_u64(tag_mod_child, id); } -fn write_closure_type<'a, 'tcx>(ecx: &mut EncodeContext<'a, 'tcx>, - closure_type: &ty::ClosureTy<'tcx>) { - let cx = ecx.ty_str_ctxt(); - tyencode::enc_closure_ty(&mut ecx.opaque.cursor, &cx, closure_type); - ecx.mark_stable_position(); -} - impl<'a, 'b, 'tcx> ItemContentBuilder<'a, 'b, 'tcx> { fn encode_type(&mut self, typ: Ty<'tcx>) { - let cx = self.ty_str_ctxt(); self.start_tag(tag_items_data_item_type); - tyencode::enc_ty(&mut self.opaque.cursor, &cx, typ); - self.mark_stable_position(); + typ.encode(self.ecx).unwrap(); self.end_tag(); } @@ -519,10 +496,8 @@ impl<'a, 'b, 'tcx> ItemContentBuilder<'a, 'b, 'tcx> { generics: &ty::Generics<'tcx>, predicates: &ty::GenericPredicates<'tcx>) { - let cx = self.ty_str_ctxt(); self.start_tag(tag_item_generics); - tyencode::enc_generics(&mut self.opaque.cursor, &cx, generics); - self.mark_stable_position(); + generics.encode(self.ecx).unwrap(); self.end_tag(); self.encode_predicates(predicates, tag_item_predicates); } @@ -859,7 +834,6 @@ fn encode_xrefs<'a, 'tcx>(ecx: &mut EncodeContext<'a, 'tcx>, xrefs: FnvHashMap, u32>) { let mut xref_positions = vec![0; xrefs.len()]; - let cx = ecx.ty_str_ctxt(); // Encode XRefs sorted by their ID let mut sorted_xrefs: Vec<_> = xrefs.into_iter().collect(); @@ -869,9 +843,7 @@ fn encode_xrefs<'a, 'tcx>(ecx: &mut EncodeContext<'a, 'tcx>, for (xref, id) in sorted_xrefs.into_iter() { xref_positions[id as usize] = ecx.mark_stable_position() as u32; match xref { - XRef::Predicate(p) => { - tyencode::enc_predicate(&mut ecx.opaque.cursor, &cx, &p) - } + XRef::Predicate(p) => p.encode(ecx).unwrap() } } ecx.mark_stable_position(); @@ -1396,8 +1368,7 @@ impl<'a, 'b, 'tcx> ItemContentBuilder<'a, 'b, 'tcx> { encode_name(self, syntax::parse::token::intern("")); self.start_tag(tag_items_closure_ty); - write_closure_type(self, - &tcx.tables.borrow().closure_tys[&def_id]); + tcx.tables.borrow().closure_tys[&def_id].encode(self.ecx).unwrap(); self.end_tag(); self.start_tag(tag_items_closure_kind); diff --git a/src/librustc_metadata/tydecode.rs b/src/librustc_metadata/tydecode.rs index 28e7b8852b30..ccc4894fcdda 100644 --- a/src/librustc_metadata/tydecode.rs +++ b/src/librustc_metadata/tydecode.rs @@ -21,7 +21,7 @@ use rustc::hir; use rustc::hir::def_id::{CrateNum, DefId, DefIndex}; use middle::region; use rustc::ty::subst::{Kind, Substs}; -use rustc::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable}; +use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; use rbml; use rustc_serialize::leb128; @@ -109,12 +109,6 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> { value as usize } - fn parse_name(&mut self, last: char) -> ast::Name { - fn is_last(b: char, c: char) -> bool { return c == b; } - let bytes = self.scan(|a| is_last(last, a)); - token::intern(str::from_utf8(bytes).unwrap()) - } - fn parse_size(&mut self) -> Option { assert_eq!(self.next(), '/'); @@ -128,7 +122,7 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> { } } - pub fn parse_substs(&mut self) -> &'tcx Substs<'tcx> { + fn parse_substs(&mut self) -> &'tcx Substs<'tcx> { let mut params = vec![]; assert_eq!(self.next(), '['); while self.peek() != ']' { @@ -144,34 +138,6 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> { Substs::new(self.tcx, params) } - pub fn parse_generics(&mut self) -> &'tcx ty::Generics<'tcx> { - let parent = self.parse_opt(|this| this.parse_def()); - let parent_regions = self.parse_u32(); - assert_eq!(self.next(), '|'); - let parent_types = self.parse_u32(); - - let mut regions = vec![]; - let mut types = vec![]; - assert_eq!(self.next(), '['); - while self.peek() != '|' { - regions.push(self.parse_region_param_def()); - } - assert_eq!(self.next(), '|'); - while self.peek() != ']' { - types.push(self.parse_type_param_def()); - } - assert_eq!(self.next(), ']'); - - self.tcx.alloc_generics(ty::Generics { - parent: parent, - parent_regions: parent_regions, - parent_types: parent_types, - regions: regions, - types: types, - has_self: self.next() == 'S' - }) - } - fn parse_bound_region(&mut self) -> ty::BoundRegion { match self.next() { 'a' => { @@ -207,7 +173,7 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> { } } - pub fn parse_region(&mut self) -> &'tcx ty::Region { + fn parse_region(&mut self) -> &'tcx ty::Region { self.tcx.mk_region(match self.next() { 'b' => { assert_eq!(self.next(), '['); @@ -300,16 +266,6 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> { }) } - fn parse_opt(&mut self, f: F) -> Option - where F: FnOnce(&mut TyDecoder<'a, 'tcx>) -> T, - { - match self.next() { - 'n' => None, - 's' => Some(f(self)), - _ => bug!("parse_opt: bad input") - } - } - fn parse_str(&mut self, term: char) -> String { let mut result = String::new(); while self.peek() != term { @@ -321,14 +277,14 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> { result } - pub fn parse_trait_ref(&mut self) -> ty::TraitRef<'tcx> { + fn parse_trait_ref(&mut self) -> ty::TraitRef<'tcx> { ty::TraitRef { def_id: self.parse_def(), substs: self.parse_substs() } } - pub fn parse_existential_trait_ref(&mut self) -> ty::ExistentialTraitRef<'tcx> { + fn parse_existential_trait_ref(&mut self) -> ty::ExistentialTraitRef<'tcx> { ty::ExistentialTraitRef { def_id: self.parse_def(), substs: self.parse_substs() @@ -538,18 +494,7 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> { abi::lookup(&abi_str[..]).expect(abi_str) } - pub fn parse_closure_ty(&mut self) -> ty::ClosureTy<'tcx> { - let unsafety = parse_unsafety(self.next()); - let sig = self.parse_sig(); - let abi = self.parse_abi_set(); - ty::ClosureTy { - unsafety: unsafety, - sig: sig, - abi: abi, - } - } - - pub fn parse_bare_fn_ty(&mut self) -> &'tcx ty::BareFnTy<'tcx> { + fn parse_bare_fn_ty(&mut self) -> &'tcx ty::BareFnTy<'tcx> { let unsafety = parse_unsafety(self.next()); let abi = self.parse_abi_set(); let sig = self.parse_sig(); @@ -578,48 +523,6 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> { variadic: variadic}) } - pub fn parse_predicate(&mut self) -> ty::Predicate<'tcx> { - match self.next() { - 't' => ty::Binder(self.parse_trait_ref()).to_predicate(), - 'e' => ty::Binder(ty::EquatePredicate(self.parse_ty(), - self.parse_ty())).to_predicate(), - 'r' => ty::Binder(ty::OutlivesPredicate(self.parse_region(), - self.parse_region())).to_predicate(), - 'o' => ty::Binder(ty::OutlivesPredicate(self.parse_ty(), - self.parse_region())).to_predicate(), - 'p' => ty::Binder(self.parse_projection_predicate()).to_predicate(), - 'w' => ty::Predicate::WellFormed(self.parse_ty()), - 'O' => { - let def_id = self.parse_def(); - assert_eq!(self.next(), '|'); - ty::Predicate::ObjectSafe(def_id) - } - 'c' => { - let def_id = self.parse_def(); - assert_eq!(self.next(), '|'); - let kind = match self.next() { - 'f' => ty::ClosureKind::Fn, - 'm' => ty::ClosureKind::FnMut, - 'o' => ty::ClosureKind::FnOnce, - c => bug!("Encountered invalid character in metadata: {}", c) - }; - assert_eq!(self.next(), '|'); - ty::Predicate::ClosureKind(def_id, kind) - } - c => bug!("Encountered invalid character in metadata: {}", c) - } - } - - fn parse_projection_predicate(&mut self) -> ty::ProjectionPredicate<'tcx> { - ty::ProjectionPredicate { - projection_ty: ty::ProjectionTy { - trait_ref: self.parse_trait_ref(), - item_name: token::intern(&self.parse_str('|')), - }, - ty: self.parse_ty(), - } - } - fn parse_existential_projection(&mut self) -> ty::ExistentialProjection<'tcx> { ty::ExistentialProjection { trait_ref: self.parse_existential_trait_ref(), @@ -628,61 +531,6 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> { } } - fn parse_type_param_def(&mut self) -> ty::TypeParameterDef<'tcx> { - let name = self.parse_name(':'); - let def_id = self.parse_def(); - let index = self.parse_u32(); - assert_eq!(self.next(), '|'); - let default_def_id = self.parse_def(); - let default = self.parse_opt(|this| this.parse_ty()); - let object_lifetime_default = self.parse_object_lifetime_default(); - - ty::TypeParameterDef { - name: name, - def_id: def_id, - index: index, - default_def_id: default_def_id, - default: default, - object_lifetime_default: object_lifetime_default, - } - } - - fn parse_region_param_def(&mut self) -> ty::RegionParameterDef<'tcx> { - let name = self.parse_name(':'); - let def_id = self.parse_def(); - let index = self.parse_u32(); - assert_eq!(self.next(), '|'); - let mut bounds = vec![]; - loop { - match self.next() { - 'R' => bounds.push(self.parse_region()), - '.' => { break; } - c => { - bug!("parse_region_param_def: bad bounds ('{}')", c) - } - } - } - ty::RegionParameterDef { - name: name, - def_id: def_id, - index: index, - bounds: bounds, - } - } - - - fn parse_object_lifetime_default(&mut self) -> ty::ObjectLifetimeDefault<'tcx> { - match self.next() { - 'a' => ty::ObjectLifetimeDefault::Ambiguous, - 'b' => ty::ObjectLifetimeDefault::BaseDefault, - 's' => { - let region = self.parse_region(); - ty::ObjectLifetimeDefault::Specific(region) - } - _ => bug!("parse_object_lifetime_default: bad input") - } - } - fn parse_builtin_bounds(&mut self) -> ty::BuiltinBounds { let mut builtin_bounds = ty::BuiltinBounds::empty(); loop { diff --git a/src/librustc_metadata/tyencode.rs b/src/librustc_metadata/tyencode.rs index 8cd18d1bfc7e..54b4dc933424 100644 --- a/src/librustc_metadata/tyencode.rs +++ b/src/librustc_metadata/tyencode.rs @@ -220,22 +220,8 @@ fn enc_mt<'a, 'tcx>(w: &mut Cursor>, cx: &ctxt<'a, 'tcx>, enc_ty(w, cx, mt.ty); } -fn enc_opt(w: &mut Cursor>, t: Option, enc_f: F) where - F: FnOnce(&mut Cursor>, T), -{ - match t { - None => { - write!(w, "n"); - } - Some(v) => { - write!(w, "s"); - enc_f(w, v); - } - } -} - -pub fn enc_substs<'a, 'tcx>(w: &mut Cursor>, cx: &ctxt<'a, 'tcx>, - substs: &Substs<'tcx>) { +fn enc_substs<'a, 'tcx>(w: &mut Cursor>, cx: &ctxt<'a, 'tcx>, + substs: &Substs<'tcx>) { write!(w, "["); for &k in substs.params() { if let Some(ty) = k.as_type() { @@ -251,32 +237,7 @@ pub fn enc_substs<'a, 'tcx>(w: &mut Cursor>, cx: &ctxt<'a, 'tcx>, write!(w, "]"); } -pub fn enc_generics<'a, 'tcx>(w: &mut Cursor>, cx: &ctxt<'a, 'tcx>, - generics: &ty::Generics<'tcx>) { - enc_opt(w, generics.parent, |w, def_id| { - write!(w, "{}|", (cx.ds)(cx.tcx, def_id)); - }); - write!(w, "{}|{}[", - generics.parent_regions, - generics.parent_types); - - for r in &generics.regions { - enc_region_param_def(w, cx, r) - } - write!(w, "|"); - for t in &generics.types { - enc_type_param_def(w, cx, t); - } - write!(w, "]"); - - if generics.has_self { - write!(w, "S"); - } else { - write!(w, "N"); - } -} - -pub fn enc_region(w: &mut Cursor>, cx: &ctxt, r: &ty::Region) { +fn enc_region(w: &mut Cursor>, cx: &ctxt, r: &ty::Region) { match *r { ty::ReLateBound(id, br) => { write!(w, "b[{}|", id.depth); @@ -355,8 +316,8 @@ fn enc_bound_region(w: &mut Cursor>, cx: &ctxt, br: ty::BoundRegion) { } } -pub fn enc_trait_ref<'a, 'tcx>(w: &mut Cursor>, cx: &ctxt<'a, 'tcx>, - s: ty::TraitRef<'tcx>) { +fn enc_trait_ref<'a, 'tcx>(w: &mut Cursor>, cx: &ctxt<'a, 'tcx>, + s: ty::TraitRef<'tcx>) { write!(w, "{}|", (cx.ds)(cx.tcx, s.def_id)); enc_substs(w, cx, s.substs); } @@ -380,20 +341,13 @@ fn enc_abi(w: &mut Cursor>, abi: Abi) { write!(w, "]"); } -pub fn enc_bare_fn_ty<'a, 'tcx>(w: &mut Cursor>, cx: &ctxt<'a, 'tcx>, - ft: &ty::BareFnTy<'tcx>) { +fn enc_bare_fn_ty<'a, 'tcx>(w: &mut Cursor>, cx: &ctxt<'a, 'tcx>, + ft: &ty::BareFnTy<'tcx>) { enc_unsafety(w, ft.unsafety); enc_abi(w, ft.abi); enc_fn_sig(w, cx, &ft.sig); } -pub fn enc_closure_ty<'a, 'tcx>(w: &mut Cursor>, cx: &ctxt<'a, 'tcx>, - ft: &ty::ClosureTy<'tcx>) { - enc_unsafety(w, ft.unsafety); - enc_fn_sig(w, cx, &ft.sig); - enc_abi(w, ft.abi); -} - fn enc_fn_sig<'a, 'tcx>(w: &mut Cursor>, cx: &ctxt<'a, 'tcx>, fsig: &ty::PolyFnSig<'tcx>) { write!(w, "["); @@ -422,92 +376,6 @@ fn enc_builtin_bounds(w: &mut Cursor>, _cx: &ctxt, bs: &ty::BuiltinBound write!(w, "."); } -fn enc_type_param_def<'a, 'tcx>(w: &mut Cursor>, cx: &ctxt<'a, 'tcx>, - v: &ty::TypeParameterDef<'tcx>) { - write!(w, "{}:{}|{}|{}|", - v.name, (cx.ds)(cx.tcx, v.def_id), - v.index, (cx.ds)(cx.tcx, v.default_def_id)); - enc_opt(w, v.default, |w, t| enc_ty(w, cx, t)); - enc_object_lifetime_default(w, cx, v.object_lifetime_default); -} - -fn enc_region_param_def(w: &mut Cursor>, cx: &ctxt, - v: &ty::RegionParameterDef) { - write!(w, "{}:{}|{}|", - v.name, (cx.ds)(cx.tcx, v.def_id), v.index); - for &r in &v.bounds { - write!(w, "R"); - enc_region(w, cx, r); - } - write!(w, "."); -} - -fn enc_object_lifetime_default<'a, 'tcx>(w: &mut Cursor>, - cx: &ctxt<'a, 'tcx>, - default: ty::ObjectLifetimeDefault) -{ - match default { - ty::ObjectLifetimeDefault::Ambiguous => { - write!(w, "a"); - } - ty::ObjectLifetimeDefault::BaseDefault => { - write!(w, "b"); - } - ty::ObjectLifetimeDefault::Specific(r) => { - write!(w, "s"); - enc_region(w, cx, r); - } - } -} - -pub fn enc_predicate<'a, 'tcx>(w: &mut Cursor>, - cx: &ctxt<'a, 'tcx>, - p: &ty::Predicate<'tcx>) -{ - match *p { - ty::Predicate::Trait(ref trait_ref) => { - write!(w, "t"); - enc_trait_ref(w, cx, trait_ref.0.trait_ref); - } - ty::Predicate::Equate(ty::Binder(ty::EquatePredicate(a, b))) => { - write!(w, "e"); - enc_ty(w, cx, a); - enc_ty(w, cx, b); - } - ty::Predicate::RegionOutlives(ty::Binder(ty::OutlivesPredicate(a, b))) => { - write!(w, "r"); - enc_region(w, cx, a); - enc_region(w, cx, b); - } - ty::Predicate::TypeOutlives(ty::Binder(ty::OutlivesPredicate(a, b))) => { - write!(w, "o"); - enc_ty(w, cx, a); - enc_region(w, cx, b); - } - ty::Predicate::Projection(ty::Binder(ref data)) => { - write!(w, "p"); - enc_trait_ref(w, cx, data.projection_ty.trait_ref); - write!(w, "{}|", data.projection_ty.item_name); - enc_ty(w, cx, data.ty); - } - ty::Predicate::WellFormed(data) => { - write!(w, "w"); - enc_ty(w, cx, data); - } - ty::Predicate::ObjectSafe(trait_def_id) => { - write!(w, "O{}|", (cx.ds)(cx.tcx, trait_def_id)); - } - ty::Predicate::ClosureKind(closure_def_id, kind) => { - let kind_char = match kind { - ty::ClosureKind::Fn => 'f', - ty::ClosureKind::FnMut => 'm', - ty::ClosureKind::FnOnce => 'o', - }; - write!(w, "c{}|{}|", (cx.ds)(cx.tcx, closure_def_id), kind_char); - } - } -} - fn enc_existential_projection<'a, 'tcx>(w: &mut Cursor>, cx: &ctxt<'a, 'tcx>, data: &ty::ExistentialProjection<'tcx>) { From 88c5679c4e0ba0bd21a15eaaf8e5fafcc6bcdafd Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Fri, 2 Sep 2016 11:08:16 +0300 Subject: [PATCH 418/443] rustc_metadata: remove ty{en,de}code and move to auto-derived serialization. --- src/librustc/ty/context.rs | 108 +++-- src/librustc/ty/mod.rs | 40 ++ src/librustc/ty/structural_impls.rs | 13 +- src/librustc/ty/sty.rs | 55 +-- src/librustc_const_eval/check_match.rs | 27 +- src/librustc_metadata/common.rs | 9 +- src/librustc_metadata/decoder.rs | 54 ++- src/librustc_metadata/encoder.rs | 51 ++- src/librustc_metadata/lib.rs | 4 +- src/librustc_metadata/tydecode.rs | 598 ------------------------- src/librustc_metadata/tyencode.rs | 385 ---------------- src/libserialize/collection_impls.rs | 4 +- 12 files changed, 235 insertions(+), 1113 deletions(-) delete mode 100644 src/librustc_metadata/tydecode.rs delete mode 100644 src/librustc_metadata/tyencode.rs diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index bb9e90f89194..338ea6b0dd6d 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -25,7 +25,7 @@ use middle::stability; use ty::subst::Substs; use traits; use ty::{self, TraitRef, Ty, TypeAndMut}; -use ty::{TyS, TypeVariants}; +use ty::{TyS, TypeVariants, Slice}; use ty::{AdtKind, AdtDef, ClosureSubsts, Region}; use hir::FreevarMap; use ty::{BareFnTy, InferTy, ParamTy, ProjectionTy, TraitObject}; @@ -92,7 +92,7 @@ pub struct CtxtInterners<'tcx> { /// Specifically use a speedy hash algorithm for these hash sets, /// they're accessed quite often. type_: RefCell>>>, - type_list: RefCell]>>>, + type_list: RefCell>>>>, substs: RefCell>>>, bare_fn: RefCell>>>, region: RefCell>>, @@ -847,10 +847,11 @@ impl<'a, 'tcx> Lift<'tcx> for &'a Region { } } -impl<'a, 'tcx> Lift<'tcx> for &'a [Ty<'a>] { - type Lifted = &'tcx [Ty<'tcx>]; - fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<&'tcx [Ty<'tcx>]> { - if let Some(&Interned(list)) = tcx.interners.type_list.borrow().get(*self) { +impl<'a, 'tcx> Lift<'tcx> for &'a Slice> { + type Lifted = &'tcx Slice>; + fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) + -> Option<&'tcx Slice>> { + if let Some(&Interned(list)) = tcx.interners.type_list.borrow().get(&self[..]) { if *self as *const _ == list as *const _ { return Some(list); } @@ -1067,9 +1068,24 @@ impl<'tcx: 'lcx, 'lcx> Borrow> for Interned<'tcx, TyS<'tcx>> } } -impl<'tcx: 'lcx, 'lcx> Borrow<[Ty<'lcx>]> for Interned<'tcx, [Ty<'tcx>]> { +// NB: An Interned> compares and hashes as its elements. +impl<'tcx, T: PartialEq> PartialEq for Interned<'tcx, Slice> { + fn eq(&self, other: &Interned<'tcx, Slice>) -> bool { + self.0[..] == other.0[..] + } +} + +impl<'tcx, T: Eq> Eq for Interned<'tcx, Slice> {} + +impl<'tcx, T: Hash> Hash for Interned<'tcx, Slice> { + fn hash(&self, s: &mut H) { + self.0[..].hash(s) + } +} + +impl<'tcx: 'lcx, 'lcx> Borrow<[Ty<'lcx>]> for Interned<'tcx, Slice>> { fn borrow<'a>(&'a self) -> &'a [Ty<'lcx>] { - self.0 + &self.0[..] } } @@ -1091,32 +1107,23 @@ impl<'tcx> Borrow for Interned<'tcx, Region> { } } -macro_rules! items { ($($item:item)+) => ($($item)+) } -macro_rules! impl_interners { - ($lt_tcx:tt, $($name:ident: $method:ident($alloc:ty, $needs_infer:expr)-> $ty:ty),+) => { - items!($(impl<$lt_tcx> PartialEq for Interned<$lt_tcx, $ty> { - fn eq(&self, other: &Self) -> bool { - self.0 == other.0 - } - } - - impl<$lt_tcx> Eq for Interned<$lt_tcx, $ty> {} - - impl<$lt_tcx> Hash for Interned<$lt_tcx, $ty> { - fn hash(&self, s: &mut H) { - self.0.hash(s) - } - } - +macro_rules! intern_method { + ($lt_tcx:tt, $name:ident: $method:ident($alloc:ty, + $alloc_to_key:expr, + $alloc_to_ret:expr, + $needs_infer:expr) -> $ty:ty) => { impl<'a, 'gcx, $lt_tcx> TyCtxt<'a, 'gcx, $lt_tcx> { pub fn $method(self, v: $alloc) -> &$lt_tcx $ty { - if let Some(i) = self.interners.$name.borrow().get::<$ty>(&v) { - return i.0; - } - if !self.is_global() { - if let Some(i) = self.global_interners.$name.borrow().get::<$ty>(&v) { + { + let key = ($alloc_to_key)(&v); + if let Some(i) = self.interners.$name.borrow().get(key) { return i.0; } + if !self.is_global() { + if let Some(i) = self.global_interners.$name.borrow().get(key) { + return i.0; + } + } } // HACK(eddyb) Depend on flags being accurate to @@ -1127,7 +1134,7 @@ macro_rules! impl_interners { let v = unsafe { mem::transmute(v) }; - let i = self.global_interners.arenas.$name.alloc(v); + let i = ($alloc_to_ret)(self.global_interners.arenas.$name.alloc(v)); self.global_interners.$name.borrow_mut().insert(Interned(i)); return i; } @@ -1141,11 +1148,31 @@ macro_rules! impl_interners { } } - let i = self.interners.arenas.$name.alloc(v); + let i = ($alloc_to_ret)(self.interners.arenas.$name.alloc(v)); self.interners.$name.borrow_mut().insert(Interned(i)); i } - })+); + } + } +} + +macro_rules! direct_interners { + ($lt_tcx:tt, $($name:ident: $method:ident($needs_infer:expr) -> $ty:ty),+) => { + $(impl<$lt_tcx> PartialEq for Interned<$lt_tcx, $ty> { + fn eq(&self, other: &Self) -> bool { + self.0 == other.0 + } + } + + impl<$lt_tcx> Eq for Interned<$lt_tcx, $ty> {} + + impl<$lt_tcx> Hash for Interned<$lt_tcx, $ty> { + fn hash(&self, s: &mut H) { + self.0.hash(s) + } + } + + intern_method!($lt_tcx, $name: $method($ty, |x| x, |x| x, $needs_infer) -> $ty);)+ } } @@ -1153,15 +1180,14 @@ fn keep_local<'tcx, T: ty::TypeFoldable<'tcx>>(x: &T) -> bool { x.has_type_flags(ty::TypeFlags::KEEP_IN_LOCAL_TCX) } -impl_interners!('tcx, - type_list: mk_type_list(Vec>, keep_local) -> [Ty<'tcx>], - substs: mk_substs(Substs<'tcx>, |substs: &Substs| { +direct_interners!('tcx, + substs: mk_substs(|substs: &Substs| { substs.params().iter().any(keep_local) }) -> Substs<'tcx>, - bare_fn: mk_bare_fn(BareFnTy<'tcx>, |fty: &BareFnTy| { + bare_fn: mk_bare_fn(|fty: &BareFnTy| { keep_local(&fty.sig) }) -> BareFnTy<'tcx>, - region: mk_region(Region, |r| { + region: mk_region(|r| { match r { &ty::ReVar(_) | &ty::ReSkolemized(..) => true, _ => false @@ -1169,6 +1195,12 @@ impl_interners!('tcx, }) -> Region ); +intern_method!('tcx, + type_list: mk_type_list(Vec>, Deref::deref, |xs: &[Ty]| -> &Slice { + unsafe { mem::transmute(xs) } + }, keep_local) -> Slice> +); + impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// Create an unsafe fn ty based on a safe fn ty. pub fn safe_to_unsafe_fn_ty(self, bare_fn: &BareFnTy<'tcx>) -> Ty<'tcx> { diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index d4dd8298db3e..59475b422263 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -38,6 +38,7 @@ use std::borrow::Cow; use std::cell::Cell; use std::hash::{Hash, Hasher}; use std::iter; +use std::ops::Deref; use std::rc::Rc; use std::slice; use std::vec::IntoIter; @@ -569,6 +570,45 @@ pub type Ty<'tcx> = &'tcx TyS<'tcx>; impl<'tcx> serialize::UseSpecializedEncodable for Ty<'tcx> {} impl<'tcx> serialize::UseSpecializedDecodable for Ty<'tcx> {} +/// A wrapper for slices with the additioanl invariant +/// that the slice is interned and no other slice with +/// the same contents can exist in the same context. +/// This means we can use pointer + length for both +/// equality comparisons and hashing. +#[derive(Debug, RustcEncodable)] +pub struct Slice([T]); + +impl PartialEq for Slice { + #[inline] + fn eq(&self, other: &Slice) -> bool { + (&self.0 as *const [T]) == (&other.0 as *const [T]) + } +} +impl Eq for Slice {} + +impl Hash for Slice { + fn hash(&self, s: &mut H) { + (self.as_ptr(), self.len()).hash(s) + } +} + +impl Deref for Slice { + type Target = [T]; + fn deref(&self) -> &[T] { + &self.0 + } +} + +impl<'a, T> IntoIterator for &'a Slice { + type Item = &'a T; + type IntoIter = <&'a [T] as IntoIterator>::IntoIter; + fn into_iter(self) -> Self::IntoIter { + self[..].iter() + } +} + +impl<'tcx> serialize::UseSpecializedDecodable for &'tcx Slice> {} + /// Upvars do not get their own node-id. Instead, we use the pair of /// the original var id (that is, the root variable that is referenced /// by the upvar) and the id of the closure expression. diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 6c3dabfe113f..5a87ea1473d9 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -14,7 +14,6 @@ use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; use std::rc::Rc; use syntax::abi; -use syntax::ptr::P; use hir; @@ -437,16 +436,6 @@ impl<'tcx, T:TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::Binder { } } -impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for P<[T]> { - fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - self.iter().map(|t| t.fold_with(folder)).collect() - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.iter().any(|t| t.visit_with(visitor)) - } -} - impl<'tcx> TypeFoldable<'tcx> for ty::TraitObject<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { ty::TraitObject { @@ -464,7 +453,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::TraitObject<'tcx> { } } -impl<'tcx> TypeFoldable<'tcx> for &'tcx [Ty<'tcx>] { +impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Slice> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { let tys = self.iter().map(|t| t.fold_with(folder)).collect(); folder.tcx().mk_type_list(tys) diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 0f2ff8a689fa..302cab0446cd 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -13,12 +13,12 @@ use hir::def_id::DefId; use middle::region; use ty::subst::Substs; -use ty::{self, AdtDef, ToPredicate, TypeFlags, Ty, TyCtxt, TyS, TypeFoldable}; +use ty::{self, AdtDef, ToPredicate, TypeFlags, Ty, TyCtxt, TypeFoldable}; +use ty::{Slice, TyS}; use util::common::ErrorReported; use collections::enum_set::{self, EnumSet, CLike}; use std::fmt; -use std::mem; use std::ops; use syntax::abi; use syntax::ast::{self, Name}; @@ -31,7 +31,7 @@ use hir; use self::InferTy::*; use self::TypeVariants::*; -#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] pub struct TypeAndMut<'tcx> { pub ty: Ty<'tcx>, pub mutbl: hir::Mutability, @@ -87,7 +87,7 @@ pub enum Issue32330 { // NB: If you change this, you'll probably want to change the corresponding // AST structure in libsyntax/ast.rs as well. -#[derive(Clone, PartialEq, Eq, Hash, Debug)] +#[derive(Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] pub enum TypeVariants<'tcx> { /// The primitive boolean type. Written as `bool`. TyBool, @@ -155,7 +155,7 @@ pub enum TypeVariants<'tcx> { TyNever, /// A tuple type. For example, `(i32, bool)`. - TyTuple(&'tcx [Ty<'tcx>]), + TyTuple(&'tcx Slice>), /// The projection of an associated type. For example, /// `>::N`. @@ -252,7 +252,7 @@ pub enum TypeVariants<'tcx> { /// closure C wind up influencing the decisions we ought to make for /// closure C (which would then require fixed point iteration to /// handle). Plus it fixes an ICE. :P -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] pub struct ClosureSubsts<'tcx> { /// Lifetime and type parameters from the enclosing function. /// These are separated out because trans wants to pass them around @@ -262,12 +262,10 @@ pub struct ClosureSubsts<'tcx> { /// The types of the upvars. The list parallels the freevars and /// `upvar_borrows` lists. These are kept distinct so that we can /// easily index into them. - pub upvar_tys: &'tcx [Ty<'tcx>] + pub upvar_tys: &'tcx Slice> } -impl<'tcx> serialize::UseSpecializedDecodable for ClosureSubsts<'tcx> {} - -#[derive(Clone, PartialEq, Eq, Hash)] +#[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] pub struct TraitObject<'tcx> { pub principal: PolyExistentialTraitRef<'tcx>, pub region_bound: &'tcx ty::Region, @@ -330,7 +328,7 @@ impl<'tcx> PolyTraitRef<'tcx> { /// /// The substitutions don't include the erased `Self`, only trait /// type and lifetime parameters (`[X, Y]` and `['a, 'b]` above). -#[derive(Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] pub struct ExistentialTraitRef<'tcx> { pub def_id: DefId, pub substs: &'tcx Substs<'tcx>, @@ -423,13 +421,15 @@ pub struct ProjectionTy<'tcx> { pub item_name: Name, } -#[derive(Clone, PartialEq, Eq, Hash, Debug)] +#[derive(Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] pub struct BareFnTy<'tcx> { pub unsafety: hir::Unsafety, pub abi: abi::Abi, pub sig: PolyFnSig<'tcx>, } +impl<'tcx> serialize::UseSpecializedDecodable for &'tcx BareFnTy<'tcx> {} + #[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] pub struct ClosureTy<'tcx> { pub unsafety: hir::Unsafety, @@ -467,7 +467,7 @@ impl<'tcx> PolyFnSig<'tcx> { } } -#[derive(Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] pub struct ParamTy { pub idx: u32, pub name: Name, @@ -654,17 +654,17 @@ pub struct EarlyBoundRegion { pub name: Name, } -#[derive(Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] pub struct TyVid { pub index: u32, } -#[derive(Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] pub struct IntVid { pub index: u32 } -#[derive(Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] pub struct FloatVid { pub index: u32 } @@ -679,7 +679,7 @@ pub struct SkolemizedRegionVid { pub index: u32 } -#[derive(Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] pub enum InferTy { TyVar(TyVid), IntVar(IntVid), @@ -694,7 +694,7 @@ pub enum InferTy { } /// A `ProjectionPredicate` for an `ExistentialTraitRef`. -#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] pub struct ExistentialProjection<'tcx> { pub trait_ref: ExistentialTraitRef<'tcx>, pub item_name: Name, @@ -739,7 +739,7 @@ impl<'a, 'tcx, 'gcx> PolyExistentialProjection<'tcx> { } } -#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] pub struct BuiltinBounds(EnumSet); impl<'a, 'gcx, 'tcx> BuiltinBounds { @@ -782,12 +782,11 @@ impl<'a> IntoIterator for &'a BuiltinBounds { #[derive(Clone, RustcEncodable, PartialEq, Eq, RustcDecodable, Hash, Debug, Copy)] -#[repr(usize)] pub enum BuiltinBound { - Send, - Sized, - Copy, - Sync, + Send = 0, + Sized = 1, + Copy = 2, + Sync = 3, } impl CLike for BuiltinBound { @@ -795,7 +794,13 @@ impl CLike for BuiltinBound { *self as usize } fn from_usize(v: usize) -> BuiltinBound { - unsafe { mem::transmute(v) } + match v { + 0 => BuiltinBound::Send, + 1 => BuiltinBound::Sized, + 2 => BuiltinBound::Copy, + 3 => BuiltinBound::Sync, + _ => bug!("{} is not a valid BuiltinBound", v) + } } } diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs index dda72ce57b4f..8af06286189b 100644 --- a/src/librustc_const_eval/check_match.rs +++ b/src/librustc_const_eval/check_match.rs @@ -26,8 +26,7 @@ use rustc::middle::expr_use_visitor as euv; use rustc::middle::mem_categorization::{cmt}; use rustc::hir::pat_util::*; use rustc::traits::Reveal; -use rustc::ty::*; -use rustc::ty; +use rustc::ty::{self, Ty, TyCtxt}; use std::cmp::Ordering; use std::fmt; use std::iter::{FromIterator, IntoIterator, repeat}; @@ -110,7 +109,7 @@ impl<'a, 'tcx> FromIterator>)>> for Matrix<'a, 'tc //NOTE: appears to be the only place other then InferCtxt to contain a ParamEnv pub struct MatchCheckCtxt<'a, 'tcx: 'a> { pub tcx: TyCtxt<'a, 'tcx, 'tcx>, - pub param_env: ParameterEnvironment<'tcx>, + pub param_env: ty::ParameterEnvironment<'tcx>, } #[derive(Clone, Debug, PartialEq)] @@ -248,7 +247,7 @@ fn check_for_bindings_named_the_same_as_variants(cx: &MatchCheckCtxt, pat: &Pat) if edef.is_enum() { if let Def::Local(..) = cx.tcx.expect_def(p.id) { if edef.variants.iter().any(|variant| { - variant.name == name.node && variant.kind == VariantKind::Unit + variant.name == name.node && variant.kind == ty::VariantKind::Unit }) { let ty_path = cx.tcx.item_path_str(edef.did); let mut err = struct_span_warn!(cx.tcx.sess, p.span, E0170, @@ -579,7 +578,7 @@ fn construct_witness<'a,'tcx>(cx: &MatchCheckCtxt<'a,'tcx>, ctor: &Constructor, ty::TyAdt(adt, _) => { let v = ctor.variant_for_adt(adt); match v.kind { - VariantKind::Struct => { + ty::VariantKind::Struct => { let field_pats: hir::HirVec<_> = v.fields.iter() .zip(pats) .filter(|&(_, ref pat)| pat.node != PatKind::Wild) @@ -594,10 +593,10 @@ fn construct_witness<'a,'tcx>(cx: &MatchCheckCtxt<'a,'tcx>, ctor: &Constructor, let has_more_fields = field_pats.len() < pats_len; PatKind::Struct(def_to_path(cx.tcx, v.did), field_pats, has_more_fields) } - VariantKind::Tuple => { + ty::VariantKind::Tuple => { PatKind::TupleStruct(def_to_path(cx.tcx, v.did), pats.collect(), None) } - VariantKind::Unit => { + ty::VariantKind::Unit => { PatKind::Path(None, def_to_path(cx.tcx, v.did)) } } @@ -639,7 +638,7 @@ fn construct_witness<'a,'tcx>(cx: &MatchCheckCtxt<'a,'tcx>, ctor: &Constructor, impl Constructor { fn variant_for_adt<'tcx, 'container, 'a>(&self, adt: &'a ty::AdtDefData<'tcx, 'container>) - -> &'a VariantDefData<'tcx, 'container> { + -> &'a ty::VariantDefData<'tcx, 'container> { match self { &Variant(vid) => adt.variant_with_id(vid), _ => adt.struct_variant() @@ -878,7 +877,7 @@ fn wrap_pat<'a, 'b, 'tcx>(cx: &MatchCheckCtxt<'b, 'tcx>, let pat_ty = cx.tcx.pat_ty(pat); (pat, Some(match pat.node { PatKind::Binding(hir::BindByRef(..), ..) => { - pat_ty.builtin_deref(false, NoPreference).unwrap().ty + pat_ty.builtin_deref(false, ty::NoPreference).unwrap().ty } _ => pat_ty })) @@ -1068,7 +1067,7 @@ fn check_fn(cx: &mut MatchCheckCtxt, fn_id: NodeId) { match kind { FnKind::Closure(_) => {} - _ => cx.param_env = ParameterEnvironment::for_item(cx.tcx, fn_id), + _ => cx.param_env = ty::ParameterEnvironment::for_item(cx.tcx, fn_id), } intravisit::walk_fn(cx, kind, decl, body, sp, fn_id); @@ -1187,17 +1186,17 @@ impl<'a, 'gcx, 'tcx> Delegate<'tcx> for MutationChecker<'a, 'gcx> { _: NodeId, span: Span, _: cmt, - _: &'tcx Region, - kind: BorrowKind, + _: &'tcx ty::Region, + kind:ty:: BorrowKind, _: LoanCause) { match kind { - MutBorrow => { + ty::MutBorrow => { struct_span_err!(self.cx.tcx.sess, span, E0301, "cannot mutably borrow in a pattern guard") .span_label(span, &format!("borrowed mutably in pattern guard")) .emit(); } - ImmBorrow | UniqueImmBorrow => {} + ty::ImmBorrow | ty::UniqueImmBorrow => {} } } fn decl_without_init(&mut self, _: NodeId, _: Span) {} diff --git a/src/librustc_metadata/common.rs b/src/librustc_metadata/common.rs index 3b63ee6b5fa8..123ed11a7a51 100644 --- a/src/librustc_metadata/common.rs +++ b/src/librustc_metadata/common.rs @@ -10,9 +10,7 @@ #![allow(non_camel_case_types, non_upper_case_globals)] -pub const tag_opaque: usize = 0x00; - -// GAP 0x01...0x19 +// GAP 0x00...0x19 pub const tag_items: usize = 0x100; // top-level only @@ -214,3 +212,8 @@ pub const tag_macro_derive_registrar: usize = 0x115; // NB: increment this if you change the format of metadata such that // rustc_version can't be found. pub const metadata_encoding_version : &'static [u8] = &[b'r', b'u', b's', b't', 0, 0, 0, 2]; + +/// The shorthand encoding of `Ty` uses `TypeVariants`' variant `usize` +/// and is offset by this value so it never matches a real variant. +/// This offset is also chosen so that the first byte is never < 0x80. +pub const TYPE_SHORTHAND_OFFSET: usize = 0x80; diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index d3c04874a08e..0118cacad182 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -20,7 +20,6 @@ use common::*; use def_key; use encoder::def_to_u64; use index; -use tydecode::TyDecoder; use rustc::hir::def_id::CRATE_DEF_INDEX; use rustc::hir::svh::Svh; @@ -45,13 +44,14 @@ use rustc_const_math::ConstInt; use rustc::mir::repr::Mir; use std::io; +use std::mem; use std::rc::Rc; use std::str; use std::u32; use rbml::reader; use rbml; -use rustc_serialize::{Decodable, SpecializedDecoder, opaque}; +use rustc_serialize::{Decodable, Decoder, SpecializedDecoder, opaque}; use rustc_serialize as serialize; use syntax::attr; use syntax::parse::token; @@ -233,35 +233,53 @@ impl<'a, 'tcx> SpecializedDecoder for DecodeContext<'a, 'tcx> { impl<'a, 'tcx> SpecializedDecoder> for DecodeContext<'a, 'tcx> { fn specialized_decode(&mut self) -> Result, Self::Error> { - let pos = self.opaque.position(); - let doc = rbml::Doc::at(self.opaque.data, pos); - self.opaque.advance(doc.end - pos); - Ok(TyDecoder::with_doc(self.tcx(), self.cdata().cnum, doc, - &mut |d| translate_def_id(self.cdata(), d)) - .parse_ty()) + let tcx = self.tcx(); + + // Handle shorthands first, if we have an usize > 0x80. + if self.opaque.data[self.opaque.position()] & 0x80 != 0 { + let pos = self.read_usize()?; + assert!(pos >= TYPE_SHORTHAND_OFFSET); + let key = ty::CReaderCacheKey { + cnum: self.cdata().cnum, + pos: pos - TYPE_SHORTHAND_OFFSET + }; + if let Some(ty) = tcx.rcache.borrow().get(&key).cloned() { + return Ok(ty); + } + + let new = opaque::Decoder::new(self.opaque.data, key.pos); + let old = mem::replace(&mut self.opaque, new); + let ty = Ty::decode(self)?; + self.opaque = old; + tcx.rcache.borrow_mut().insert(key, ty); + return Ok(ty); + } + + Ok(tcx.mk_ty(ty::TypeVariants::decode(self)?)) } } impl<'a, 'tcx> SpecializedDecoder<&'tcx Substs<'tcx>> for DecodeContext<'a, 'tcx> { fn specialized_decode(&mut self) -> Result<&'tcx Substs<'tcx>, Self::Error> { - let substs = Substs::decode(self)?; - Ok(self.tcx().mk_substs(substs)) + Ok(self.tcx().mk_substs(Decodable::decode(self)?)) } } impl<'a, 'tcx> SpecializedDecoder<&'tcx ty::Region> for DecodeContext<'a, 'tcx> { fn specialized_decode(&mut self) -> Result<&'tcx ty::Region, Self::Error> { - let r = ty::Region::decode(self)?; - Ok(self.tcx().mk_region(r)) + Ok(self.tcx().mk_region(Decodable::decode(self)?)) } } -impl<'a, 'tcx> SpecializedDecoder> for DecodeContext<'a, 'tcx> { - fn specialized_decode(&mut self) -> Result, Self::Error> { - Ok(ty::ClosureSubsts { - func_substs: Decodable::decode(self)?, - upvar_tys: self.tcx().mk_type_list(Decodable::decode(self)?) - }) +impl<'a, 'tcx> SpecializedDecoder<&'tcx ty::Slice>> for DecodeContext<'a, 'tcx> { + fn specialized_decode(&mut self) -> Result<&'tcx ty::Slice>, Self::Error> { + Ok(self.tcx().mk_type_list(Decodable::decode(self)?)) + } +} + +impl<'a, 'tcx> SpecializedDecoder<&'tcx ty::BareFnTy<'tcx>> for DecodeContext<'a, 'tcx> { + fn specialized_decode(&mut self) -> Result<&'tcx ty::BareFnTy<'tcx>, Self::Error> { + Ok(self.tcx().mk_bare_fn(Decodable::decode(self)?)) } } diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index dcc3d13631eb..e414275f8b42 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -18,7 +18,6 @@ use common::*; use cstore; use decoder; use def_key; -use tyencode; use index::{self, IndexData}; use middle::cstore::{InlinedItemRef, LinkMeta}; @@ -34,8 +33,10 @@ use rustc::mir::mir_map::MirMap; use rustc::session::config::{self, PanicStrategy, CrateTypeRustcMacro}; use rustc::util::nodemap::{FnvHashMap, NodeSet}; -use rustc_serialize::{Encodable, SpecializedEncoder, opaque}; +use rustc_serialize::{Encodable, Encoder, SpecializedEncoder, opaque}; use rustc_serialize as serialize; +use std::cell::RefCell; +use std::intrinsics; use std::io::prelude::*; use std::io::Cursor; use std::ops::{Deref, DerefMut}; @@ -55,14 +56,14 @@ use rustc::hir::map::DefKey; use super::index_builder::{FromId, IndexBuilder, ItemContentBuilder, Untracked, XRef}; pub struct EncodeContext<'a, 'tcx: 'a> { - pub rbml_w: rbml::writer::Encoder<'a>, + rbml_w: rbml::writer::Encoder<'a>, pub tcx: TyCtxt<'a, 'tcx, 'tcx>, - pub reexports: &'a def::ExportMap, - pub link_meta: &'a LinkMeta, - pub cstore: &'a cstore::CStore, - pub type_abbrevs: &'a tyencode::abbrev_map<'tcx>, - pub reachable: &'a NodeSet, - pub mir_map: &'a MirMap<'tcx>, + reexports: &'a def::ExportMap, + link_meta: &'a LinkMeta, + cstore: &'a cstore::CStore, + type_shorthands: RefCell, usize>>, + reachable: &'a NodeSet, + mir_map: &'a MirMap<'tcx>, } impl<'a, 'tcx> Deref for EncodeContext<'a, 'tcx> { @@ -116,12 +117,32 @@ impl<'a, 'tcx> serialize::Encoder for ::encoder::EncodeContext<'a, 'tcx> { impl<'a, 'tcx> SpecializedEncoder> for EncodeContext<'a, 'tcx> { fn specialized_encode(&mut self, ty: &Ty<'tcx>) -> Result<(), Self::Error> { - let cx = self.ty_str_ctxt(); + let existing_shorthand = self.type_shorthands.borrow().get(ty).cloned(); + if let Some(shorthand) = existing_shorthand { + return self.emit_usize(shorthand); + } - self.start_tag(tag_opaque)?; - tyencode::enc_ty(&mut self.rbml_w.opaque.cursor, &cx, ty); - self.mark_stable_position(); - self.end_tag() + let start = self.mark_stable_position(); + ty.sty.encode(self)?; + let len = self.mark_stable_position() - start; + + // The shorthand encoding uses the same usize as the + // discriminant, with an offset so they can't conflict. + let discriminant = unsafe { intrinsics::discriminant_value(&ty.sty) }; + assert!(discriminant < TYPE_SHORTHAND_OFFSET as u64); + let shorthand = start + TYPE_SHORTHAND_OFFSET; + + // Get the number of bits that leb128 could fit + // in the same space as the fully encoded type. + let leb128_bits = len * 7; + + // Check that the shorthand is a not longer than the + // full encoding itself, i.e. it's an obvious win. + if leb128_bits >= 64 || (shorthand as u64) < (1 << leb128_bits) { + self.type_shorthands.borrow_mut().insert(*ty, shorthand); + } + + Ok(()) } } @@ -1742,7 +1763,7 @@ pub fn encode_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, cstore: cstore, reachable: reachable, mir_map: mir_map, - type_abbrevs: &Default::default(), + type_shorthands: Default::default(), }); // RBML compacts the encoded bytes whenever appropriate, diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs index 7205a88618fc..e5f7aab38c36 100644 --- a/src/librustc_metadata/lib.rs +++ b/src/librustc_metadata/lib.rs @@ -17,9 +17,9 @@ html_root_url = "https://doc.rust-lang.org/nightly/")] #![cfg_attr(not(stage0), deny(warnings))] +#![feature(core_intrinsics)] #![feature(box_patterns)] #![feature(dotdot_in_tuple_patterns)] -#![feature(enumset)] #![feature(question_mark)] #![feature(quote)] #![feature(rustc_diagnostic_macros)] @@ -63,8 +63,6 @@ pub mod diagnostics; pub mod astencode; pub mod common; pub mod def_key; -pub mod tyencode; -pub mod tydecode; pub mod encoder; mod index_builder; pub mod decoder; diff --git a/src/librustc_metadata/tydecode.rs b/src/librustc_metadata/tydecode.rs deleted file mode 100644 index ccc4894fcdda..000000000000 --- a/src/librustc_metadata/tydecode.rs +++ /dev/null @@ -1,598 +0,0 @@ -// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - - -// Type decoding - -// tjc note: Would be great to have a `match check` macro equivalent -// for some of these - -#![allow(non_camel_case_types)] - -use rustc::hir; - -use rustc::hir::def_id::{CrateNum, DefId, DefIndex}; -use middle::region; -use rustc::ty::subst::{Kind, Substs}; -use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; - -use rbml; -use rustc_serialize::leb128; -use std::str; -use syntax::abi; -use syntax::ast; -use syntax::parse::token; - -// Compact string representation for Ty values. API TyStr & -// parse_from_str. Extra parameters are for converting to/from def_ids in the -// data buffer. Whatever format you choose should not contain pipe characters. - -pub type DefIdConvert<'a> = &'a mut FnMut(DefId) -> DefId; - -pub struct TyDecoder<'a, 'tcx: 'a> { - data: &'a [u8], - krate: CrateNum, - pos: usize, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - conv_def_id: DefIdConvert<'a>, -} - -impl<'a,'tcx> TyDecoder<'a,'tcx> { - pub fn with_doc(tcx: TyCtxt<'a, 'tcx, 'tcx>, - crate_num: CrateNum, - doc: rbml::Doc<'a>, - conv: DefIdConvert<'a>) - -> TyDecoder<'a,'tcx> { - TyDecoder::new(doc.data, crate_num, doc.start, tcx, conv) - } - - pub fn new(data: &'a [u8], - crate_num: CrateNum, - pos: usize, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - conv: DefIdConvert<'a>) - -> TyDecoder<'a, 'tcx> { - TyDecoder { - data: data, - krate: crate_num, - pos: pos, - tcx: tcx, - conv_def_id: conv, - } - } - - pub fn position(&self) -> usize { - self.pos - } - - fn peek(&self) -> char { - self.data[self.pos] as char - } - - fn next(&mut self) -> char { - let ch = self.data[self.pos] as char; - self.pos = self.pos + 1; - return ch; - } - - fn next_byte(&mut self) -> u8 { - let b = self.data[self.pos]; - self.pos = self.pos + 1; - return b; - } - - fn scan(&mut self, mut is_last: F) -> &'a [u8] - where F: FnMut(char) -> bool, - { - let start_pos = self.pos; - debug!("scan: '{}' (start)", self.data[self.pos] as char); - while !is_last(self.data[self.pos] as char) { - self.pos += 1; - debug!("scan: '{}'", self.data[self.pos] as char); - } - let end_pos = self.pos; - self.pos += 1; - return &self.data[start_pos..end_pos]; - } - - fn parse_vuint(&mut self) -> usize { - let (value, bytes_read) = leb128::read_unsigned_leb128(self.data, - self.pos); - self.pos += bytes_read; - value as usize - } - - fn parse_size(&mut self) -> Option { - assert_eq!(self.next(), '/'); - - if self.peek() == '|' { - assert_eq!(self.next(), '|'); - None - } else { - let n = self.parse_uint(); - assert_eq!(self.next(), '|'); - Some(n) - } - } - - fn parse_substs(&mut self) -> &'tcx Substs<'tcx> { - let mut params = vec![]; - assert_eq!(self.next(), '['); - while self.peek() != ']' { - let k = match self.next() { - 'r' => Kind::from(self.parse_region()), - 't' => Kind::from(self.parse_ty()), - _ => bug!() - }; - params.push(k); - } - assert_eq!(self.next(), ']'); - - Substs::new(self.tcx, params) - } - - fn parse_bound_region(&mut self) -> ty::BoundRegion { - match self.next() { - 'a' => { - let id = self.parse_u32(); - assert_eq!(self.next(), '|'); - ty::BrAnon(id) - } - '[' => { - let def = self.parse_def(); - let name = token::intern(&self.parse_str('|')); - let issue32330 = match self.next() { - 'n' => { - assert_eq!(self.next(), ']'); - ty::Issue32330::WontChange - } - 'y' => { - ty::Issue32330::WillChange { - fn_def_id: self.parse_def(), - region_name: token::intern(&self.parse_str(']')), - } - } - c => panic!("expected n or y not {}", c) - }; - ty::BrNamed(def, name, issue32330) - } - 'f' => { - let id = self.parse_u32(); - assert_eq!(self.next(), '|'); - ty::BrFresh(id) - } - 'e' => ty::BrEnv, - _ => bug!("parse_bound_region: bad input") - } - } - - fn parse_region(&mut self) -> &'tcx ty::Region { - self.tcx.mk_region(match self.next() { - 'b' => { - assert_eq!(self.next(), '['); - let id = ty::DebruijnIndex::new(self.parse_u32()); - assert_eq!(self.next(), '|'); - let br = self.parse_bound_region(); - assert_eq!(self.next(), ']'); - ty::ReLateBound(id, br) - } - 'B' => { - assert_eq!(self.next(), '['); - let index = self.parse_u32(); - assert_eq!(self.next(), '|'); - let name = token::intern(&self.parse_str(']')); - ty::ReEarlyBound(ty::EarlyBoundRegion { - index: index, - name: name - }) - } - 'f' => { - assert_eq!(self.next(), '['); - let scope = self.parse_scope(); - assert_eq!(self.next(), '|'); - let br = self.parse_bound_region(); - assert_eq!(self.next(), ']'); - ty::ReFree(ty::FreeRegion { scope: scope, - bound_region: br}) - } - 's' => { - let scope = self.parse_scope(); - assert_eq!(self.next(), '|'); - ty::ReScope(scope) - } - 't' => ty::ReStatic, - 'e' => ty::ReEmpty, - 'E' => ty::ReErased, - _ => bug!("parse_region: bad input") - }) - } - - fn parse_scope(&mut self) -> region::CodeExtent { - self.tcx.region_maps.bogus_code_extent(match self.next() { - // This creates scopes with the wrong NodeId. This isn't - // actually a problem because scopes only exist *within* - // functions, and functions aren't loaded until trans which - // doesn't care about regions. - // - // May still be worth fixing though. - 'C' => { - assert_eq!(self.next(), '['); - let fn_id = ast::NodeId::new(self.parse_uint()); - assert_eq!(self.next(), '|'); - let body_id = ast::NodeId::new(self.parse_uint()); - assert_eq!(self.next(), ']'); - region::CodeExtentData::CallSiteScope { - fn_id: fn_id, body_id: body_id - } - } - // This creates scopes with the wrong NodeId. (See note above.) - 'P' => { - assert_eq!(self.next(), '['); - let fn_id = ast::NodeId::new(self.parse_uint()); - assert_eq!(self.next(), '|'); - let body_id = ast::NodeId::new(self.parse_uint()); - assert_eq!(self.next(), ']'); - region::CodeExtentData::ParameterScope { - fn_id: fn_id, body_id: body_id - } - } - 'M' => { - let node_id = ast::NodeId::new(self.parse_uint()); - region::CodeExtentData::Misc(node_id) - } - 'D' => { - let node_id = ast::NodeId::new(self.parse_uint()); - region::CodeExtentData::DestructionScope(node_id) - } - 'B' => { - assert_eq!(self.next(), '['); - let node_id = ast::NodeId::new(self.parse_uint()); - assert_eq!(self.next(), '|'); - let first_stmt_index = self.parse_u32(); - assert_eq!(self.next(), ']'); - let block_remainder = region::BlockRemainder { - block: node_id, first_statement_index: first_stmt_index, - }; - region::CodeExtentData::Remainder(block_remainder) - } - _ => bug!("parse_scope: bad input") - }) - } - - fn parse_str(&mut self, term: char) -> String { - let mut result = String::new(); - while self.peek() != term { - unsafe { - result.as_mut_vec().extend_from_slice(&[self.next_byte()]) - } - } - self.next(); - result - } - - fn parse_trait_ref(&mut self) -> ty::TraitRef<'tcx> { - ty::TraitRef { - def_id: self.parse_def(), - substs: self.parse_substs() - } - } - - fn parse_existential_trait_ref(&mut self) -> ty::ExistentialTraitRef<'tcx> { - ty::ExistentialTraitRef { - def_id: self.parse_def(), - substs: self.parse_substs() - } - } - - pub fn parse_ty(&mut self) -> Ty<'tcx> { - let tcx = self.tcx; - match self.next() { - 'b' => return tcx.types.bool, - '!' => return tcx.types.never, - 'i' => { /* eat the s of is */ self.next(); return tcx.types.isize }, - 'u' => { /* eat the s of us */ self.next(); return tcx.types.usize }, - 'M' => { - match self.next() { - 'b' => return tcx.types.u8, - 'w' => return tcx.types.u16, - 'l' => return tcx.types.u32, - 'd' => return tcx.types.u64, - 'B' => return tcx.types.i8, - 'W' => return tcx.types.i16, - 'L' => return tcx.types.i32, - 'D' => return tcx.types.i64, - 'f' => return tcx.types.f32, - 'F' => return tcx.types.f64, - _ => bug!("parse_ty: bad numeric type") - } - } - 'c' => return tcx.types.char, - 'x' => { - assert_eq!(self.next(), '['); - let trait_ref = ty::Binder(self.parse_existential_trait_ref()); - let builtin_bounds = self.parse_builtin_bounds(); - let region_bound = self.parse_region(); - let mut projection_bounds = Vec::new(); - - loop { - match self.next() { - 'P' => { - let bound = self.parse_existential_projection(); - projection_bounds.push(ty::Binder(bound)); - } - '.' => { break; } - c => { - bug!("parse_bounds: bad bounds ('{}')", c) - } - } - } - assert_eq!(self.next(), ']'); - return tcx.mk_trait(ty::TraitObject { - principal: trait_ref, - region_bound: region_bound, - builtin_bounds: builtin_bounds, - projection_bounds: projection_bounds - }); - } - 'p' => { - assert_eq!(self.next(), '['); - let index = self.parse_u32(); - assert_eq!(self.next(), '|'); - let name = token::intern(&self.parse_str(']')); - return tcx.mk_param(index, name); - } - '~' => return tcx.mk_box(self.parse_ty()), - '*' => return tcx.mk_ptr(self.parse_mt()), - '&' => { - return tcx.mk_ref(self.parse_region(), self.parse_mt()); - } - 'V' => { - let t = self.parse_ty(); - return match self.parse_size() { - Some(n) => tcx.mk_array(t, n), - None => tcx.mk_slice(t) - }; - } - 'v' => { - return tcx.mk_str(); - } - 'T' => { - assert_eq!(self.next(), '['); - let mut params = Vec::new(); - while self.peek() != ']' { params.push(self.parse_ty()); } - self.pos = self.pos + 1; - return tcx.mk_tup(params); - } - 'F' => { - let def_id = self.parse_def(); - let substs = self.parse_substs(); - return tcx.mk_fn_def(def_id, substs, self.parse_bare_fn_ty()); - } - 'G' => { - return tcx.mk_fn_ptr(self.parse_bare_fn_ty()); - } - '#' => { - // This is a hacky little caching scheme. The idea is that if we encode - // the same type twice, the second (and third, and fourth...) time we will - // just write `#123`, where `123` is the offset in the metadata of the - // first appearance. Now when we are *decoding*, if we see a `#123`, we - // can first check a cache (`tcx.rcache`) for that offset. If we find something, - // we return it (modulo closure types, see below). But if not, then we - // jump to offset 123 and read the type from there. - - let pos = self.parse_vuint(); - let key = ty::CReaderCacheKey { cnum: self.krate, pos: pos }; - if let Some(tt) = tcx.rcache.borrow().get(&key).cloned() { - // If there is a closure buried in the type some where, then we - // need to re-convert any def ids (see case 'k', below). That means - // we can't reuse the cached version. - if !tt.has_closure_types() { - return tt; - } - } - - let mut substate = TyDecoder::new(self.data, - self.krate, - pos, - self.tcx, - self.conv_def_id); - let tt = substate.parse_ty(); - tcx.rcache.borrow_mut().insert(key, tt); - return tt; - } - '\"' => { - let _ = self.parse_def(); - let inner = self.parse_ty(); - inner - } - 'a' => { - assert_eq!(self.next(), '['); - let did = self.parse_def(); - let substs = self.parse_substs(); - assert_eq!(self.next(), ']'); - let def = self.tcx.lookup_adt_def(did); - return self.tcx.mk_adt(def, substs); - } - 'k' => { - assert_eq!(self.next(), '['); - let did = self.parse_def(); - let substs = self.parse_substs(); - let mut tys = vec![]; - while self.peek() != '.' { - tys.push(self.parse_ty()); - } - assert_eq!(self.next(), '.'); - assert_eq!(self.next(), ']'); - return self.tcx.mk_closure(did, substs, tys); - } - 'P' => { - assert_eq!(self.next(), '['); - let trait_ref = self.parse_trait_ref(); - let name = token::intern(&self.parse_str(']')); - return tcx.mk_projection(trait_ref, name); - } - 'A' => { - assert_eq!(self.next(), '['); - let def_id = self.parse_def(); - let substs = self.parse_substs(); - assert_eq!(self.next(), ']'); - return self.tcx.mk_anon(def_id, substs); - } - 'e' => { - return tcx.types.err; - } - c => { bug!("unexpected char in type string: {}", c);} - } - } - - fn parse_mutability(&mut self) -> hir::Mutability { - match self.peek() { - 'm' => { self.next(); hir::MutMutable } - _ => { hir::MutImmutable } - } - } - - fn parse_mt(&mut self) -> ty::TypeAndMut<'tcx> { - let m = self.parse_mutability(); - ty::TypeAndMut { ty: self.parse_ty(), mutbl: m } - } - - fn parse_def(&mut self) -> DefId { - let def_id = parse_defid(self.scan(|c| c == '|')); - return (self.conv_def_id)(def_id); - } - - fn parse_uint(&mut self) -> usize { - let mut n = 0; - loop { - let cur = self.peek(); - if cur < '0' || cur > '9' { return n; } - self.pos = self.pos + 1; - n *= 10; - n += (cur as usize) - ('0' as usize); - }; - } - - fn parse_u32(&mut self) -> u32 { - let n = self.parse_uint(); - let m = n as u32; - assert_eq!(m as usize, n); - m - } - - fn parse_abi_set(&mut self) -> abi::Abi { - assert_eq!(self.next(), '['); - let bytes = self.scan(|c| c == ']'); - let abi_str = str::from_utf8(bytes).unwrap(); - abi::lookup(&abi_str[..]).expect(abi_str) - } - - fn parse_bare_fn_ty(&mut self) -> &'tcx ty::BareFnTy<'tcx> { - let unsafety = parse_unsafety(self.next()); - let abi = self.parse_abi_set(); - let sig = self.parse_sig(); - self.tcx.mk_bare_fn(ty::BareFnTy { - unsafety: unsafety, - abi: abi, - sig: sig - }) - } - - fn parse_sig(&mut self) -> ty::PolyFnSig<'tcx> { - assert_eq!(self.next(), '['); - let mut inputs = Vec::new(); - while self.peek() != ']' { - inputs.push(self.parse_ty()); - } - self.pos += 1; // eat the ']' - let variadic = match self.next() { - 'V' => true, - 'N' => false, - r => bug!("bad variadic: {}", r), - }; - let output = self.parse_ty(); - ty::Binder(ty::FnSig {inputs: inputs, - output: output, - variadic: variadic}) - } - - fn parse_existential_projection(&mut self) -> ty::ExistentialProjection<'tcx> { - ty::ExistentialProjection { - trait_ref: self.parse_existential_trait_ref(), - item_name: token::intern(&self.parse_str('|')), - ty: self.parse_ty(), - } - } - - fn parse_builtin_bounds(&mut self) -> ty::BuiltinBounds { - let mut builtin_bounds = ty::BuiltinBounds::empty(); - loop { - match self.next() { - 'S' => { - builtin_bounds.insert(ty::BoundSend); - } - 'Z' => { - builtin_bounds.insert(ty::BoundSized); - } - 'P' => { - builtin_bounds.insert(ty::BoundCopy); - } - 'T' => { - builtin_bounds.insert(ty::BoundSync); - } - '.' => { - return builtin_bounds; - } - c => { - bug!("parse_bounds: bad builtin bounds ('{}')", c) - } - } - } - } -} - -// Rust metadata parsing -fn parse_defid(buf: &[u8]) -> DefId { - let mut colon_idx = 0; - let len = buf.len(); - while colon_idx < len && buf[colon_idx] != ':' as u8 { colon_idx += 1; } - if colon_idx == len { - error!("didn't find ':' when parsing def id"); - bug!(); - } - - let crate_part = &buf[0..colon_idx]; - let def_part = &buf[colon_idx + 1..len]; - - let crate_num = match str::from_utf8(crate_part).ok().and_then(|s| { - s.parse::().ok() - }) { - Some(cn) => CrateNum::new(cn), - None => bug!("internal error: parse_defid: crate number expected, found {:?}", - crate_part) - }; - let def_num = match str::from_utf8(def_part).ok().and_then(|s| { - s.parse::().ok() - }) { - Some(dn) => dn, - None => bug!("internal error: parse_defid: id expected, found {:?}", - def_part) - }; - let index = DefIndex::new(def_num); - DefId { krate: crate_num, index: index } -} - -fn parse_unsafety(c: char) -> hir::Unsafety { - match c { - 'u' => hir::Unsafety::Unsafe, - 'n' => hir::Unsafety::Normal, - _ => bug!("parse_unsafety: bad unsafety {}", c) - } -} diff --git a/src/librustc_metadata/tyencode.rs b/src/librustc_metadata/tyencode.rs deleted file mode 100644 index 54b4dc933424..000000000000 --- a/src/librustc_metadata/tyencode.rs +++ /dev/null @@ -1,385 +0,0 @@ -// 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. - -// Type encoding - -#![allow(unused_must_use)] // as with encoding, everything is a no-fail MemWriter -#![allow(non_camel_case_types)] - -use std::cell::RefCell; -use std::io::Cursor; -use std::io::prelude::*; - -use rustc::hir::def_id::DefId; -use middle::region; -use rustc::ty::subst::Substs; -use rustc::ty::{self, Ty, TyCtxt}; -use rustc::util::nodemap::FnvHashMap; - -use rustc::hir; - -use syntax::abi::Abi; -use syntax::ast; - -use rustc_serialize::leb128; -use encoder; - -pub struct ctxt<'a, 'tcx: 'a> { - // Def -> str Callback: - pub ds: for<'b> fn(TyCtxt<'b, 'tcx, 'tcx>, DefId) -> String, - // The type context. - pub tcx: TyCtxt<'a, 'tcx, 'tcx>, - pub abbrevs: &'a abbrev_map<'tcx> -} - -impl<'a, 'tcx> encoder::EncodeContext<'a, 'tcx> { - pub fn ty_str_ctxt(&self) -> ctxt<'a, 'tcx> { - ctxt { - ds: encoder::def_to_string, - tcx: self.tcx, - abbrevs: self.type_abbrevs - } - } -} - -// Compact string representation for Ty values. API TyStr & parse_from_str. -// Extra parameters are for converting to/from def_ids in the string rep. -// Whatever format you choose should not contain pipe characters. -pub struct ty_abbrev { - s: Vec -} - -pub type abbrev_map<'tcx> = RefCell, ty_abbrev>>; - -pub fn enc_ty<'a, 'tcx>(w: &mut Cursor>, cx: &ctxt<'a, 'tcx>, t: Ty<'tcx>) { - if let Some(a) = cx.abbrevs.borrow_mut().get(&t) { - w.write_all(&a.s); - return; - } - - let pos = w.position(); - - match t.sty { - ty::TyBool => { write!(w, "b"); } - ty::TyChar => { write!(w, "c"); } - ty::TyNever => { write!(w, "!"); } - ty::TyInt(t) => { - match t { - ast::IntTy::Is => write!(w, "is"), - ast::IntTy::I8 => write!(w, "MB"), - ast::IntTy::I16 => write!(w, "MW"), - ast::IntTy::I32 => write!(w, "ML"), - ast::IntTy::I64 => write!(w, "MD") - }; - } - ty::TyUint(t) => { - match t { - ast::UintTy::Us => write!(w, "us"), - ast::UintTy::U8 => write!(w, "Mb"), - ast::UintTy::U16 => write!(w, "Mw"), - ast::UintTy::U32 => write!(w, "Ml"), - ast::UintTy::U64 => write!(w, "Md") - }; - } - ty::TyFloat(t) => { - match t { - ast::FloatTy::F32 => write!(w, "Mf"), - ast::FloatTy::F64 => write!(w, "MF"), - }; - } - ty::TyTrait(ref obj) => { - write!(w, "x["); - enc_existential_trait_ref(w, cx, obj.principal.0); - enc_builtin_bounds(w, cx, &obj.builtin_bounds); - - enc_region(w, cx, obj.region_bound); - - for tp in &obj.projection_bounds { - write!(w, "P"); - enc_existential_projection(w, cx, &tp.0); - } - - write!(w, "."); - write!(w, "]"); - } - ty::TyTuple(ts) => { - write!(w, "T["); - for t in ts { enc_ty(w, cx, *t); } - write!(w, "]"); - } - ty::TyBox(typ) => { write!(w, "~"); enc_ty(w, cx, typ); } - ty::TyRawPtr(mt) => { write!(w, "*"); enc_mt(w, cx, mt); } - ty::TyRef(r, mt) => { - write!(w, "&"); - enc_region(w, cx, r); - enc_mt(w, cx, mt); - } - ty::TyArray(t, sz) => { - write!(w, "V"); - enc_ty(w, cx, t); - write!(w, "/{}|", sz); - } - ty::TySlice(t) => { - write!(w, "V"); - enc_ty(w, cx, t); - write!(w, "/|"); - } - ty::TyStr => { - write!(w, "v"); - } - ty::TyFnDef(def_id, substs, f) => { - write!(w, "F"); - write!(w, "{}|", (cx.ds)(cx.tcx, def_id)); - enc_substs(w, cx, substs); - enc_bare_fn_ty(w, cx, f); - } - ty::TyFnPtr(f) => { - write!(w, "G"); - enc_bare_fn_ty(w, cx, f); - } - ty::TyInfer(_) => { - bug!("cannot encode inference variable types"); - } - ty::TyParam(p) => { - write!(w, "p[{}|{}]", p.idx, p.name); - } - ty::TyAdt(def, substs) => { - write!(w, "a[{}|", (cx.ds)(cx.tcx, def.did)); - enc_substs(w, cx, substs); - write!(w, "]"); - } - ty::TyClosure(def, substs) => { - write!(w, "k[{}|", (cx.ds)(cx.tcx, def)); - enc_substs(w, cx, substs.func_substs); - for ty in substs.upvar_tys { - enc_ty(w, cx, ty); - } - write!(w, "."); - write!(w, "]"); - } - ty::TyProjection(ref data) => { - write!(w, "P["); - enc_trait_ref(w, cx, data.trait_ref); - write!(w, "{}]", data.item_name); - } - ty::TyAnon(def_id, substs) => { - write!(w, "A[{}|", (cx.ds)(cx.tcx, def_id)); - enc_substs(w, cx, substs); - write!(w, "]"); - } - ty::TyError => { - write!(w, "e"); - } - } - - let end = w.position(); - let len = end - pos; - - let mut abbrev = Cursor::new(Vec::with_capacity(16)); - abbrev.write_all(b"#"); - { - let start_position = abbrev.position() as usize; - let meta_start = 8 + ::common::metadata_encoding_version.len() as u64; - let bytes_written = leb128::write_unsigned_leb128(abbrev.get_mut(), - start_position, - pos - meta_start); - abbrev.set_position((start_position + bytes_written) as u64); - } - - cx.abbrevs.borrow_mut().insert(t, ty_abbrev { - s: if abbrev.position() < len { - abbrev.get_ref()[..abbrev.position() as usize].to_owned() - } else { - // if the abbreviation is longer than the real type, - // don't use #-notation. However, insert it here so - // other won't have to `mark_stable_position` - w.get_ref()[pos as usize .. end as usize].to_owned() - } - }); -} - -fn enc_mutability(w: &mut Cursor>, mt: hir::Mutability) { - match mt { - hir::MutImmutable => (), - hir::MutMutable => { - write!(w, "m"); - } - }; -} - -fn enc_mt<'a, 'tcx>(w: &mut Cursor>, cx: &ctxt<'a, 'tcx>, - mt: ty::TypeAndMut<'tcx>) { - enc_mutability(w, mt.mutbl); - enc_ty(w, cx, mt.ty); -} - -fn enc_substs<'a, 'tcx>(w: &mut Cursor>, cx: &ctxt<'a, 'tcx>, - substs: &Substs<'tcx>) { - write!(w, "["); - for &k in substs.params() { - if let Some(ty) = k.as_type() { - write!(w, "t"); - enc_ty(w, cx, ty); - } else if let Some(r) = k.as_region() { - write!(w, "r"); - enc_region(w, cx, r); - } else { - bug!() - } - } - write!(w, "]"); -} - -fn enc_region(w: &mut Cursor>, cx: &ctxt, r: &ty::Region) { - match *r { - ty::ReLateBound(id, br) => { - write!(w, "b[{}|", id.depth); - enc_bound_region(w, cx, br); - write!(w, "]"); - } - ty::ReEarlyBound(ref data) => { - write!(w, "B[{}|{}]", - data.index, - data.name); - } - ty::ReFree(ref fr) => { - write!(w, "f["); - enc_scope(w, cx, fr.scope); - write!(w, "|"); - enc_bound_region(w, cx, fr.bound_region); - write!(w, "]"); - } - ty::ReScope(scope) => { - write!(w, "s"); - enc_scope(w, cx, scope); - write!(w, "|"); - } - ty::ReStatic => { - write!(w, "t"); - } - ty::ReEmpty => { - write!(w, "e"); - } - ty::ReErased => { - write!(w, "E"); - } - ty::ReVar(_) | ty::ReSkolemized(..) => { - // these should not crop up after typeck - bug!("cannot encode region variables"); - } - } -} - -fn enc_scope(w: &mut Cursor>, cx: &ctxt, scope: region::CodeExtent) { - match cx.tcx.region_maps.code_extent_data(scope) { - region::CodeExtentData::CallSiteScope { - fn_id, body_id } => write!(w, "C[{}|{}]", fn_id, body_id), - region::CodeExtentData::ParameterScope { - fn_id, body_id } => write!(w, "P[{}|{}]", fn_id, body_id), - region::CodeExtentData::Misc(node_id) => write!(w, "M{}", node_id), - region::CodeExtentData::Remainder(region::BlockRemainder { - block: b, first_statement_index: i }) => write!(w, "B[{}|{}]", b, i), - region::CodeExtentData::DestructionScope(node_id) => write!(w, "D{}", node_id), - }; -} - -fn enc_bound_region(w: &mut Cursor>, cx: &ctxt, br: ty::BoundRegion) { - match br { - ty::BrAnon(idx) => { - write!(w, "a{}|", idx); - } - ty::BrNamed(d, name, issue32330) => { - write!(w, "[{}|{}|", - (cx.ds)(cx.tcx, d), - name); - - match issue32330 { - ty::Issue32330::WontChange => - write!(w, "n]"), - ty::Issue32330::WillChange { fn_def_id, region_name } => - write!(w, "y{}|{}]", (cx.ds)(cx.tcx, fn_def_id), region_name), - }; - } - ty::BrFresh(id) => { - write!(w, "f{}|", id); - } - ty::BrEnv => { - write!(w, "e|"); - } - } -} - -fn enc_trait_ref<'a, 'tcx>(w: &mut Cursor>, cx: &ctxt<'a, 'tcx>, - s: ty::TraitRef<'tcx>) { - write!(w, "{}|", (cx.ds)(cx.tcx, s.def_id)); - enc_substs(w, cx, s.substs); -} - -fn enc_existential_trait_ref<'a, 'tcx>(w: &mut Cursor>, cx: &ctxt<'a, 'tcx>, - s: ty::ExistentialTraitRef<'tcx>) { - write!(w, "{}|", (cx.ds)(cx.tcx, s.def_id)); - enc_substs(w, cx, s.substs); -} - -fn enc_unsafety(w: &mut Cursor>, p: hir::Unsafety) { - match p { - hir::Unsafety::Normal => write!(w, "n"), - hir::Unsafety::Unsafe => write!(w, "u"), - }; -} - -fn enc_abi(w: &mut Cursor>, abi: Abi) { - write!(w, "["); - write!(w, "{}", abi.name()); - write!(w, "]"); -} - -fn enc_bare_fn_ty<'a, 'tcx>(w: &mut Cursor>, cx: &ctxt<'a, 'tcx>, - ft: &ty::BareFnTy<'tcx>) { - enc_unsafety(w, ft.unsafety); - enc_abi(w, ft.abi); - enc_fn_sig(w, cx, &ft.sig); -} - -fn enc_fn_sig<'a, 'tcx>(w: &mut Cursor>, cx: &ctxt<'a, 'tcx>, - fsig: &ty::PolyFnSig<'tcx>) { - write!(w, "["); - for ty in &fsig.0.inputs { - enc_ty(w, cx, *ty); - } - write!(w, "]"); - if fsig.0.variadic { - write!(w, "V"); - } else { - write!(w, "N"); - } - enc_ty(w, cx, fsig.0.output); -} - -fn enc_builtin_bounds(w: &mut Cursor>, _cx: &ctxt, bs: &ty::BuiltinBounds) { - for bound in bs { - match bound { - ty::BoundSend => write!(w, "S"), - ty::BoundSized => write!(w, "Z"), - ty::BoundCopy => write!(w, "P"), - ty::BoundSync => write!(w, "T"), - }; - } - - write!(w, "."); -} - -fn enc_existential_projection<'a, 'tcx>(w: &mut Cursor>, - cx: &ctxt<'a, 'tcx>, - data: &ty::ExistentialProjection<'tcx>) { - enc_existential_trait_ref(w, cx, data.trait_ref); - write!(w, "{}|", data.item_name); - enc_ty(w, cx, data.ty); -} diff --git a/src/libserialize/collection_impls.rs b/src/libserialize/collection_impls.rs index 7b5092e8848e..ba9bf2b86a60 100644 --- a/src/libserialize/collection_impls.rs +++ b/src/libserialize/collection_impls.rs @@ -134,7 +134,7 @@ impl< fn encode(&self, s: &mut S) -> Result<(), S::Error> { let mut bits = 0; for item in self { - bits |= item.to_usize(); + bits |= 1 << item.to_usize(); } s.emit_usize(bits) } @@ -148,7 +148,7 @@ impl< let mut set = EnumSet::new(); for bit in 0..(mem::size_of::()*8) { if bits & (1 << bit) != 0 { - set.insert(CLike::from_usize(1 << bit)); + set.insert(CLike::from_usize(bit)); } } Ok(set) From 8734aaa33ed745a09b983bea9a89b6278b1b082c Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Mon, 19 Sep 2016 23:49:01 +0300 Subject: [PATCH 419/443] rustc_metadata: move more RBML tags to auto-serialization. --- src/librustc/dep_graph/dep_node.rs | 15 +- src/librustc/hir/def.rs | 2 +- src/librustc/hir/map/mod.rs | 22 +- src/librustc/middle/cstore.rs | 70 +- src/librustc/middle/dead.rs | 2 +- src/librustc/middle/lang_items.rs | 2 +- src/librustc/session/config.rs | 2 +- src/librustc/traits/select.rs | 2 +- .../traits/specialize/specialization_graph.rs | 63 +- src/librustc/ty/context.rs | 15 +- src/librustc/ty/maps.rs | 4 +- src/librustc/ty/mod.rs | 148 +-- src/librustc_const_eval/eval.rs | 14 +- src/librustc_metadata/common.rs | 124 ++- src/librustc_metadata/creader.rs | 14 +- src/librustc_metadata/csearch.rs | 114 +- src/librustc_metadata/cstore.rs | 22 +- src/librustc_metadata/decoder.rs | 999 ++++++------------ src/librustc_metadata/encoder.rs | 954 +++++++---------- src/librustc_metadata/index_builder.rs | 67 +- src/librustc_metadata/lib.rs | 1 + src/librustc_metadata/rbml/reader.rs | 132 +-- src/librustc_metadata/rbml/writer.rs | 47 +- src/librustc_resolve/build_reduced_graph.rs | 37 +- src/librustc_resolve/lib.rs | 1 + src/librustc_save_analysis/lib.rs | 6 +- src/librustc_trans/collector.rs | 24 +- src/librustc_trans/meth.rs | 2 +- src/librustc_trans/mir/constant.rs | 16 +- src/librustc_typeck/check/method/mod.rs | 29 +- src/librustc_typeck/check/method/probe.rs | 20 +- src/librustc_typeck/check/method/suggest.rs | 39 +- src/librustc_typeck/coherence/mod.rs | 6 +- src/librustc_typeck/coherence/overlap.rs | 6 +- src/librustc_typeck/collect.rs | 31 +- src/librustdoc/clean/inline.rs | 110 +- src/librustdoc/clean/mod.rs | 10 +- src/librustdoc/core.rs | 8 +- src/librustdoc/test.rs | 2 +- src/librustdoc/visit_lib.rs | 41 +- 40 files changed, 1084 insertions(+), 2139 deletions(-) diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 18179027c25d..3cf7548e3209 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -103,18 +103,13 @@ pub enum DepNode { // table in the tcx (or elsewhere) maps to one of these // nodes. Often we map multiple tables to the same node if there // is no point in distinguishing them (e.g., both the type and - // predicates for an item wind up in `ItemSignature`). Other - // times, such as `ImplItems` vs `TraitItemDefIds`, tables which - // might be mergable are kept distinct because the sets of def-ids - // to which they apply are disjoint, and hence we might as well - // have distinct labels for easier debugging. + // predicates for an item wind up in `ItemSignature`). ImplOrTraitItems(D), ItemSignature(D), FieldTy(D), SizedConstraint(D), - TraitItemDefIds(D), + ImplOrTraitItemIds(D), InherentImpls(D), - ImplItems(D), // The set of impls for a given trait. Ultimately, it would be // nice to get more fine-grained here (e.g., to include a @@ -162,9 +157,8 @@ impl DepNode { ImplOrTraitItems, ItemSignature, FieldTy, - TraitItemDefIds, + ImplOrTraitItemIds, InherentImpls, - ImplItems, TraitImpls, ReprHints, } @@ -231,9 +225,8 @@ impl DepNode { ItemSignature(ref d) => op(d).map(ItemSignature), FieldTy(ref d) => op(d).map(FieldTy), SizedConstraint(ref d) => op(d).map(SizedConstraint), - TraitItemDefIds(ref d) => op(d).map(TraitItemDefIds), + ImplOrTraitItemIds(ref d) => op(d).map(ImplOrTraitItemIds), InherentImpls(ref d) => op(d).map(InherentImpls), - ImplItems(ref d) => op(d).map(ImplItems), TraitImpls(ref d) => op(d).map(TraitImpls), TraitItems(ref d) => op(d).map(TraitItems), ReprHints(ref d) => op(d).map(ReprHints), diff --git a/src/librustc/hir/def.rs b/src/librustc/hir/def.rs index b4418ed424ea..fddf09c99056 100644 --- a/src/librustc/hir/def.rs +++ b/src/librustc/hir/def.rs @@ -92,7 +92,7 @@ pub type DefMap = NodeMap; // within. pub type ExportMap = NodeMap>; -#[derive(Copy, Clone)] +#[derive(Copy, Clone, RustcEncodable, RustcDecodable)] pub struct Export { pub name: ast::Name, // The name of the target. pub def_id: DefId, // The definition of the target. diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index b728f1cbca09..b351bd427acb 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -580,22 +580,24 @@ impl<'ast> Map<'ast> { } } - pub fn expect_struct(&self, id: NodeId) -> &'ast VariantData { + pub fn expect_variant_data(&self, id: NodeId) -> &'ast VariantData { match self.find(id) { Some(NodeItem(i)) => { match i.node { - ItemStruct(ref struct_def, _) => struct_def, - _ => bug!("struct ID bound to non-struct") + ItemStruct(ref struct_def, _) | + ItemUnion(ref struct_def, _) => struct_def, + _ => { + bug!("struct ID bound to non-struct {}", + self.node_to_string(id)); + } } } - Some(NodeVariant(variant)) => { - if variant.node.data.is_struct() { - &variant.node.data - } else { - bug!("struct ID bound to enum variant that isn't struct-like") - } + Some(NodeStructCtor(data)) => data, + Some(NodeVariant(variant)) => &variant.node.data, + _ => { + bug!("expected struct or variant, found {}", + self.node_to_string(id)); } - _ => bug!("expected struct, found {}", self.node_to_string(id)), } } diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 1d6047579f6c..52cadd76c64c 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -28,14 +28,13 @@ use hir::map as hir_map; use hir::map::definitions::DefKey; use hir::svh::Svh; use middle::lang_items; -use ty::{self, Ty, TyCtxt, VariantKind}; +use ty::{self, Ty, TyCtxt}; use mir::repr::Mir; use mir::mir_map::MirMap; use session::Session; use session::config::PanicStrategy; use session::search_paths::PathKind; -use util::nodemap::{FnvHashMap, NodeSet, DefIdMap}; -use std::rc::Rc; +use util::nodemap::{NodeSet, DefIdMap}; use std::path::PathBuf; use syntax::ast; use syntax::attr; @@ -47,7 +46,6 @@ use rustc_back::target::Target; use hir; use hir::intravisit::Visitor; -pub use self::DefLike::{DlDef, DlField, DlImpl}; pub use self::NativeLibraryKind::{NativeStatic, NativeFramework, NativeUnknown}; // lonely orphan structs and enums looking for a better home @@ -67,27 +65,17 @@ pub struct CrateSource { pub cnum: CrateNum, } -#[derive(Copy, Debug, PartialEq, Clone)] +#[derive(Copy, Debug, PartialEq, Clone, RustcEncodable, RustcDecodable)] pub enum LinkagePreference { RequireDynamic, RequireStatic, } -enum_from_u32! { - #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] - pub enum NativeLibraryKind { - NativeStatic, // native static library (.a archive) - NativeFramework, // OSX-specific - NativeUnknown, // default way to specify a dynamic library - } -} - -// Something that a name can resolve to. -#[derive(Copy, Clone, Debug)] -pub enum DefLike { - DlDef(Def), - DlImpl(DefId), - DlField +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] +pub enum NativeLibraryKind { + NativeStatic, // native static library (.a archive) + NativeFramework, // OSX-specific + NativeUnknown, // default way to specify a dynamic library } /// The data we save and restore about an inlined item or method. This is not @@ -110,7 +98,7 @@ pub enum InlinedItemRef<'a> { #[derive(Copy, Clone)] pub struct ChildItem { - pub def: DefLike, + pub def: Def, pub name: ast::Name, pub vis: ty::Visibility, } @@ -166,21 +154,15 @@ pub trait CrateStore<'tcx> { fn inherent_implementations_for_type(&self, def_id: DefId) -> Vec; // trait info - fn implementations_of_trait(&self, def_id: DefId) -> Vec; - fn provided_trait_methods<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) - -> Vec>>; - fn trait_item_def_ids(&self, def: DefId) - -> Vec; + fn implementations_of_trait(&self, filter: Option) -> Vec; // impl info - fn impl_items(&self, impl_def_id: DefId) -> Vec; + fn impl_or_trait_items(&self, def_id: DefId) -> Vec; fn impl_trait_ref<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> Option>; - fn impl_polarity(&self, def: DefId) -> Option; + fn impl_polarity(&self, def: DefId) -> hir::ImplPolarity; fn custom_coerce_unsized_kind(&self, def: DefId) -> Option; - fn associated_consts<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) - -> Vec>>; fn impl_parent(&self, impl_def_id: DefId) -> Option; // trait/impl-item info @@ -191,12 +173,10 @@ pub trait CrateStore<'tcx> { // flags fn is_const_fn(&self, did: DefId) -> bool; fn is_defaulted_trait(&self, did: DefId) -> bool; - fn is_impl(&self, did: DefId) -> bool; fn is_default_impl(&self, impl_did: DefId) -> bool; fn is_extern_item<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, did: DefId) -> bool; fn is_foreign_item(&self, did: DefId) -> bool; fn is_statically_included_foreign_item(&self, id: ast::NodeId) -> bool; - fn is_typedef(&self, did: DefId) -> bool; // crate metadata fn dylib_dependency_formats(&self, cnum: CrateNum) @@ -218,8 +198,6 @@ pub trait CrateStore<'tcx> { fn original_crate_name(&self, cnum: CrateNum) -> InternedString; fn crate_hash(&self, cnum: CrateNum) -> Svh; fn crate_disambiguator(&self, cnum: CrateNum) -> InternedString; - fn crate_struct_field_attrs(&self, cnum: CrateNum) - -> FnvHashMap>; fn plugin_registrar_fn(&self, cnum: CrateNum) -> Option; fn native_libraries(&self, cnum: CrateNum) -> Vec<(NativeLibraryKind, String)>; fn reachable_ids(&self, cnum: CrateNum) -> Vec; @@ -232,12 +210,10 @@ pub trait CrateStore<'tcx> { -> Option; fn def_key(&self, def: DefId) -> hir_map::DefKey; fn relative_def_path(&self, def: DefId) -> Option; - fn variant_kind(&self, def_id: DefId) -> Option; fn struct_ctor_def_id(&self, struct_def_id: DefId) -> Option; fn tuple_struct_definition_if_ctor(&self, did: DefId) -> Option; fn struct_field_names(&self, def: DefId) -> Vec; fn item_children(&self, did: DefId) -> Vec; - fn crate_top_level_items(&self, cnum: CrateNum) -> Vec; // misc. metadata fn maybe_get_item_ast<'a>(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) @@ -344,11 +320,7 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { fn inherent_implementations_for_type(&self, def_id: DefId) -> Vec { vec![] } // trait info - fn implementations_of_trait(&self, def_id: DefId) -> Vec { vec![] } - fn provided_trait_methods<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) - -> Vec>> { bug!("provided_trait_methods") } - fn trait_item_def_ids(&self, def: DefId) - -> Vec { bug!("trait_item_def_ids") } + fn implementations_of_trait(&self, filter: Option) -> Vec { vec![] } fn def_index_for_def_key(&self, cnum: CrateNum, def: DefKey) @@ -357,16 +329,14 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { } // impl info - fn impl_items(&self, impl_def_id: DefId) -> Vec - { bug!("impl_items") } + fn impl_or_trait_items(&self, def_id: DefId) -> Vec + { bug!("impl_or_trait_items") } fn impl_trait_ref<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> Option> { bug!("impl_trait_ref") } - fn impl_polarity(&self, def: DefId) -> Option { bug!("impl_polarity") } + fn impl_polarity(&self, def: DefId) -> hir::ImplPolarity { bug!("impl_polarity") } fn custom_coerce_unsized_kind(&self, def: DefId) -> Option { bug!("custom_coerce_unsized_kind") } - fn associated_consts<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) - -> Vec>> { bug!("associated_consts") } fn impl_parent(&self, def: DefId) -> Option { bug!("impl_parent") } // trait/impl-item info @@ -377,13 +347,11 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { // flags fn is_const_fn(&self, did: DefId) -> bool { bug!("is_const_fn") } fn is_defaulted_trait(&self, did: DefId) -> bool { bug!("is_defaulted_trait") } - fn is_impl(&self, did: DefId) -> bool { bug!("is_impl") } fn is_default_impl(&self, impl_did: DefId) -> bool { bug!("is_default_impl") } fn is_extern_item<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, did: DefId) -> bool { bug!("is_extern_item") } fn is_foreign_item(&self, did: DefId) -> bool { bug!("is_foreign_item") } fn is_statically_included_foreign_item(&self, id: ast::NodeId) -> bool { false } - fn is_typedef(&self, did: DefId) -> bool { bug!("is_typedef") } // crate metadata fn dylib_dependency_formats(&self, cnum: CrateNum) @@ -411,9 +379,6 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { fn crate_hash(&self, cnum: CrateNum) -> Svh { bug!("crate_hash") } fn crate_disambiguator(&self, cnum: CrateNum) -> InternedString { bug!("crate_disambiguator") } - fn crate_struct_field_attrs(&self, cnum: CrateNum) - -> FnvHashMap> - { bug!("crate_struct_field_attrs") } fn plugin_registrar_fn(&self, cnum: CrateNum) -> Option { bug!("plugin_registrar_fn") } fn native_libraries(&self, cnum: CrateNum) -> Vec<(NativeLibraryKind, String)> @@ -426,15 +391,12 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { fn relative_def_path(&self, def: DefId) -> Option { bug!("relative_def_path") } - fn variant_kind(&self, def_id: DefId) -> Option { bug!("variant_kind") } fn struct_ctor_def_id(&self, struct_def_id: DefId) -> Option { bug!("struct_ctor_def_id") } fn tuple_struct_definition_if_ctor(&self, did: DefId) -> Option { bug!("tuple_struct_definition_if_ctor") } fn struct_field_names(&self, def: DefId) -> Vec { bug!("struct_field_names") } fn item_children(&self, did: DefId) -> Vec { bug!("item_children") } - fn crate_top_level_items(&self, cnum: CrateNum) -> Vec - { bug!("crate_top_level_items") } // misc. metadata fn maybe_get_item_ast<'a>(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index 9db6ac1dcefd..2c952e9f8634 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -470,7 +470,7 @@ impl<'a, 'tcx> DeadVisitor<'a, 'tcx> { // This is done to handle the case where, for example, the static // method of a private type is used, but the type itself is never // called directly. - let impl_items = self.tcx.impl_items.borrow(); + let impl_items = self.tcx.impl_or_trait_item_ids.borrow(); if let Some(impl_list) = self.tcx.inherent_impls.borrow().get(&self.tcx.map.local_def_id(id)) { for impl_did in impl_list.iter() { diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index d1769d5cbc51..078cce9c49ff 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -43,7 +43,7 @@ macro_rules! language_item_table { enum_from_u32! { - #[derive(Copy, Clone, PartialEq, Eq, Hash)] + #[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] pub enum LangItem { $($variant,)* } diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 2009e18f6ee2..8dd5d4d45f7a 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -493,7 +493,7 @@ impl Passes { } } -#[derive(Clone, PartialEq, Hash)] +#[derive(Clone, PartialEq, Hash, RustcEncodable, RustcDecodable)] pub enum PanicStrategy { Unwind, Abort, diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 94dba7d12a8c..9d7131dc96cc 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -814,7 +814,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { fn filter_negative_impls(&self, candidate: SelectionCandidate<'tcx>) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> { if let ImplCandidate(def_id) = candidate { - if self.tcx().trait_impl_polarity(def_id) == Some(hir::ImplPolarity::Negative) { + if self.tcx().trait_impl_polarity(def_id) == hir::ImplPolarity::Negative { return Err(Unimplemented) } } diff --git a/src/librustc/traits/specialize/specialization_graph.rs b/src/librustc/traits/specialize/specialization_graph.rs index 13193e1b2d71..4339b1a254f2 100644 --- a/src/librustc/traits/specialize/specialization_graph.rs +++ b/src/librustc/traits/specialize/specialization_graph.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::cell; use std::rc::Rc; use super::{OverlapError, specializes}; @@ -287,21 +286,10 @@ impl<'a, 'gcx, 'tcx> Node { /// Iterate over the items defined directly by the given (impl or trait) node. pub fn items(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> NodeItems<'a, 'gcx> { - match *self { - Node::Impl(impl_def_id) => { - NodeItems::Impl { - tcx: tcx.global_tcx(), - items: cell::Ref::map(tcx.impl_items.borrow(), - |impl_items| &impl_items[&impl_def_id]), - idx: 0, - } - } - Node::Trait(trait_def_id) => { - NodeItems::Trait { - items: tcx.trait_items(trait_def_id).clone(), - idx: 0, - } - } + NodeItems { + tcx: tcx.global_tcx(), + items: tcx.impl_or_trait_items(self.def_id()), + idx: 0, } } @@ -314,42 +302,23 @@ impl<'a, 'gcx, 'tcx> Node { } /// An iterator over the items defined within a trait or impl. -pub enum NodeItems<'a, 'tcx: 'a> { - Impl { - tcx: TyCtxt<'a, 'tcx, 'tcx>, - items: cell::Ref<'a, Vec>, - idx: usize, - }, - Trait { - items: Rc>>, - idx: usize, - }, +pub struct NodeItems<'a, 'tcx: 'a> { + tcx: TyCtxt<'a, 'tcx, 'tcx>, + items: Rc>, + idx: usize } impl<'a, 'tcx> Iterator for NodeItems<'a, 'tcx> { type Item = ImplOrTraitItem<'tcx>; fn next(&mut self) -> Option> { - match *self { - NodeItems::Impl { tcx, ref items, ref mut idx } => { - let items_table = tcx.impl_or_trait_items.borrow(); - if *idx < items.len() { - let item_def_id = items[*idx].def_id(); - let item = items_table[&item_def_id].clone(); - *idx += 1; - Some(item) - } else { - None - } - } - NodeItems::Trait { ref items, ref mut idx } => { - if *idx < items.len() { - let item = items[*idx].clone(); - *idx += 1; - Some(item) - } else { - None - } - } + if self.idx < self.items.len() { + let item_def_id = self.items[self.idx].def_id(); + let items_table = self.tcx.impl_or_trait_items.borrow(); + let item = items_table[&item_def_id].clone(); + self.idx += 1; + Some(item) + } else { + None } } } diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 338ea6b0dd6d..0d6beb34c690 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -330,8 +330,8 @@ pub struct GlobalCtxt<'tcx> { /// Maps from a trait item to the trait item "descriptor" pub impl_or_trait_items: RefCell>>, - /// Maps from a trait def-id to a list of the def-ids of its trait items - pub trait_item_def_ids: RefCell>>, + /// Maps from an impl/trait def-id to a list of the def-ids of its items + pub impl_or_trait_item_ids: RefCell>>, /// A cache for the trait_items() routine; note that the routine /// itself pushes the `TraitItems` dependency node. @@ -392,12 +392,6 @@ pub struct GlobalCtxt<'tcx> { /// Methods in these implementations don't need to be exported. pub inherent_impls: RefCell>>, - /// Maps a DefId of an impl to a list of its items. - /// Note that this contains all of the impls that we know about, - /// including ones in other crates. It's not clear that this is the best - /// way to do it. - pub impl_items: RefCell>>, - /// Set of used unsafe nodes (functions or blocks). Unsafe nodes not /// present in this set can be warned about. pub used_unsafe: RefCell, @@ -734,13 +728,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { rcache: RefCell::new(FnvHashMap()), tc_cache: RefCell::new(FnvHashMap()), impl_or_trait_items: RefCell::new(DepTrackingMap::new(dep_graph.clone())), - trait_item_def_ids: RefCell::new(DepTrackingMap::new(dep_graph.clone())), + impl_or_trait_item_ids: RefCell::new(DepTrackingMap::new(dep_graph.clone())), trait_items_cache: RefCell::new(DepTrackingMap::new(dep_graph.clone())), ty_param_defs: RefCell::new(NodeMap()), normalized_cache: RefCell::new(FnvHashMap()), lang_items: lang_items, inherent_impls: RefCell::new(DepTrackingMap::new(dep_graph.clone())), - impl_items: RefCell::new(DepTrackingMap::new(dep_graph.clone())), used_unsafe: RefCell::new(NodeSet()), used_mut_nodes: RefCell::new(NodeSet()), used_trait_imports: RefCell::new(NodeSet()), @@ -1401,7 +1394,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn trait_items(self, trait_did: DefId) -> Rc>> { self.trait_items_cache.memoize(trait_did, || { - let def_ids = self.trait_item_def_ids(trait_did); + let def_ids = self.impl_or_trait_items(trait_did); Rc::new(def_ids.iter() .map(|d| self.impl_or_trait_item(d.def_id())) .collect()) diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index 5772d16c6d43..5e029cf98dc6 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -34,13 +34,13 @@ dep_map_ty! { Tcache: ItemSignature(DefId) -> Ty<'tcx> } dep_map_ty! { Generics: ItemSignature(DefId) -> &'tcx ty::Generics<'tcx> } dep_map_ty! { Predicates: ItemSignature(DefId) -> ty::GenericPredicates<'tcx> } dep_map_ty! { SuperPredicates: ItemSignature(DefId) -> ty::GenericPredicates<'tcx> } -dep_map_ty! { TraitItemDefIds: TraitItemDefIds(DefId) -> Rc> } +dep_map_ty! { ImplOrTraitItemIds: ImplOrTraitItemIds(DefId) + -> Rc> } dep_map_ty! { ImplTraitRefs: ItemSignature(DefId) -> Option> } dep_map_ty! { TraitDefs: ItemSignature(DefId) -> &'tcx ty::TraitDef<'tcx> } dep_map_ty! { AdtDefs: ItemSignature(DefId) -> ty::AdtDefMaster<'tcx> } dep_map_ty! { ItemVariances: ItemSignature(DefId) -> Rc> } dep_map_ty! { InherentImpls: InherentImpls(DefId) -> Vec } -dep_map_ty! { ImplItems: ImplItems(DefId) -> Vec } dep_map_ty! { TraitItems: TraitItems(DefId) -> Rc>> } dep_map_ty! { ReprHints: ReprHints(DefId) -> Rc> } dep_map_ty! { InlinedClosures: Hir(DefId) -> ast::NodeId } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 59475b422263..3eb9f8593e3a 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -50,7 +50,6 @@ use syntax_pos::{DUMMY_SP, Span}; use rustc_const_math::ConstInt; use hir; -use hir::{ItemImpl, ItemTrait, PatKind}; use hir::intravisit::Visitor; pub use self::sty::{Binder, DebruijnIndex}; @@ -251,7 +250,7 @@ impl<'tcx> ImplOrTraitItem<'tcx> { } } -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy, Debug, RustcEncodable, RustcDecodable)] pub enum ImplOrTraitItemId { ConstTraitItemId(DefId), MethodTraitItemId(DefId), @@ -268,7 +267,7 @@ impl ImplOrTraitItemId { } } -#[derive(Clone, Debug, PartialEq, Eq, Copy)] +#[derive(Clone, Debug, PartialEq, Eq, Copy, RustcEncodable, RustcDecodable)] pub enum Visibility { /// Visible everywhere (including in other crates). Public, @@ -346,34 +345,12 @@ pub struct Method<'tcx> { pub explicit_self: ExplicitSelfCategory<'tcx>, pub vis: Visibility, pub defaultness: hir::Defaultness, + pub has_body: bool, pub def_id: DefId, pub container: ImplOrTraitItemContainer, } impl<'tcx> Method<'tcx> { - pub fn new(name: Name, - generics: &'tcx ty::Generics<'tcx>, - predicates: GenericPredicates<'tcx>, - fty: &'tcx BareFnTy<'tcx>, - explicit_self: ExplicitSelfCategory<'tcx>, - vis: Visibility, - defaultness: hir::Defaultness, - def_id: DefId, - container: ImplOrTraitItemContainer) - -> Method<'tcx> { - Method { - name: name, - generics: generics, - predicates: predicates, - fty: fty, - explicit_self: explicit_self, - vis: vis, - defaultness: defaultness, - def_id: def_id, - container: container, - } - } - pub fn container_id(&self) -> DefId { match self.container { TraitContainer(id) => id, @@ -2236,7 +2213,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { match self.map.find(id) { Some(ast_map::NodeLocal(pat)) => { match pat.node { - PatKind::Binding(_, ref path1, _) => path1.node.as_str(), + hir::PatKind::Binding(_, ref path1, _) => path1.node.as_str(), _ => { bug!("Variable id {} maps to {:?}, not local", id, pat); }, @@ -2299,84 +2276,19 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } pub fn provided_trait_methods(self, id: DefId) -> Vec>> { - if let Some(id) = self.map.as_local_node_id(id) { - if let ItemTrait(.., ref ms) = self.map.expect_item(id).node { - ms.iter().filter_map(|ti| { - if let hir::MethodTraitItem(_, Some(_)) = ti.node { - match self.impl_or_trait_item(self.map.local_def_id(ti.id)) { - MethodTraitItem(m) => Some(m), - _ => { - bug!("provided_trait_methods(): \ - non-method item found from \ - looking up provided method?!") - } - } - } else { - None - } - }).collect() - } else { - bug!("provided_trait_methods: `{:?}` is not a trait", id) + self.impl_or_trait_items(id).iter().filter_map(|id| { + match self.impl_or_trait_item(id.def_id()) { + MethodTraitItem(ref m) if m.has_body => Some(m.clone()), + _ => None } - } else { - self.sess.cstore.provided_trait_methods(self.global_tcx(), id) - } + }).collect() } - pub fn associated_consts(self, id: DefId) -> Vec>> { + pub fn trait_impl_polarity(self, id: DefId) -> hir::ImplPolarity { if let Some(id) = self.map.as_local_node_id(id) { match self.map.expect_item(id).node { - ItemTrait(.., ref tis) => { - tis.iter().filter_map(|ti| { - if let hir::ConstTraitItem(..) = ti.node { - match self.impl_or_trait_item(self.map.local_def_id(ti.id)) { - ConstTraitItem(ac) => Some(ac), - _ => { - bug!("associated_consts(): \ - non-const item found from \ - looking up a constant?!") - } - } - } else { - None - } - }).collect() - } - ItemImpl(.., ref iis) => { - iis.iter().filter_map(|ii| { - if let hir::ImplItemKind::Const(..) = ii.node { - match self.impl_or_trait_item(self.map.local_def_id(ii.id)) { - ConstTraitItem(ac) => Some(ac), - _ => { - bug!("associated_consts(): \ - non-const item found from \ - looking up a constant?!") - } - } - } else { - None - } - }).collect() - } - _ => { - bug!("associated_consts: `{:?}` is not a trait or impl", id) - } - } - } else { - self.sess.cstore.associated_consts(self.global_tcx(), id) - } - } - - pub fn trait_impl_polarity(self, id: DefId) -> Option { - if let Some(id) = self.map.as_local_node_id(id) { - match self.map.find(id) { - Some(ast_map::NodeItem(item)) => { - match item.node { - hir::ItemImpl(_, polarity, ..) => Some(polarity), - _ => None - } - } - _ => None + hir::ItemImpl(_, polarity, ..) => polarity, + ref item => bug!("trait_impl_polarity: {:?} not an impl", item) } } else { self.sess.cstore.impl_polarity(id) @@ -2409,10 +2321,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { .expect("missing ImplOrTraitItem in metadata")) } - pub fn trait_item_def_ids(self, id: DefId) -> Rc> { + pub fn impl_or_trait_items(self, id: DefId) -> Rc> { lookup_locally_or_in_crate_store( - "trait_item_def_ids", id, &self.trait_item_def_ids, - || Rc::new(self.sess.cstore.trait_item_def_ids(id))) + "impl_or_trait_items", id, &self.impl_or_trait_item_ids, + || Rc::new(self.sess.cstore.impl_or_trait_items(id))) } /// Returns the trait-ref corresponding to a given impl, or None if it is @@ -2423,20 +2335,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { || self.sess.cstore.impl_trait_ref(self.global_tcx(), id)) } - /// Returns whether this DefId refers to an impl - pub fn is_impl(self, id: DefId) -> bool { - if let Some(id) = self.map.as_local_node_id(id) { - if let Some(ast_map::NodeItem( - &hir::Item { node: hir::ItemImpl(..), .. })) = self.map.find(id) { - true - } else { - false - } - } else { - self.sess.cstore.is_impl(id) - } - } - /// Returns a path resolution for node id if it exists, panics otherwise. pub fn expect_resolution(self, id: NodeId) -> PathResolution { *self.def_map.borrow().get(&id).expect("no def-map entry for node id") @@ -2699,10 +2597,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { debug!("populate_implementations_for_primitive_if_necessary: searching for {:?}", primitive_def_id); - let impl_items = self.sess.cstore.impl_items(primitive_def_id); + let impl_items = self.sess.cstore.impl_or_trait_items(primitive_def_id); // Store the implementation info. - self.impl_items.borrow_mut().insert(primitive_def_id, impl_items); + self.impl_or_trait_item_ids.borrow_mut().insert(primitive_def_id, Rc::new(impl_items)); self.populated_external_primitive_impls.borrow_mut().insert(primitive_def_id); } @@ -2728,8 +2626,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { let inherent_impls = self.sess.cstore.inherent_implementations_for_type(type_id); for &impl_def_id in &inherent_impls { // Store the implementation info. - let impl_items = self.sess.cstore.impl_items(impl_def_id); - self.impl_items.borrow_mut().insert(impl_def_id, impl_items); + let impl_items = self.sess.cstore.impl_or_trait_items(impl_def_id); + self.impl_or_trait_item_ids.borrow_mut().insert(impl_def_id, Rc::new(impl_items)); } self.inherent_impls.borrow_mut().insert(type_id, inherent_impls); @@ -2758,8 +2656,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.record_trait_has_default_impl(trait_id); } - for impl_def_id in self.sess.cstore.implementations_of_trait(trait_id) { - let impl_items = self.sess.cstore.impl_items(impl_def_id); + for impl_def_id in self.sess.cstore.implementations_of_trait(Some(trait_id)) { + let impl_items = self.sess.cstore.impl_or_trait_items(impl_def_id); let trait_ref = self.impl_trait_ref(impl_def_id).unwrap(); // Record the trait->implementation mapping. @@ -2779,7 +2677,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } // Store the implementation info. - self.impl_items.borrow_mut().insert(impl_def_id, impl_items); + self.impl_or_trait_item_ids.borrow_mut().insert(impl_def_id, Rc::new(impl_items)); } def.flags.set(def.flags.get() | TraitFlags::IMPLS_VALID); @@ -3012,7 +2910,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } /// The category of explicit self. -#[derive(Clone, Copy, Eq, PartialEq, Debug)] +#[derive(Clone, Copy, Eq, PartialEq, Debug, RustcEncodable, RustcDecodable)] pub enum ExplicitSelfCategory<'tcx> { Static, ByValue, diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index ede13aa4dc8b..fe3c498d184b 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -1080,9 +1080,17 @@ fn resolve_trait_associated_const<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // when constructing the inference context above. match selection { traits::VtableImpl(ref impl_data) => { - match tcx.associated_consts(impl_data.impl_def_id) - .iter().find(|ic| ic.name == ti.name) { - Some(ic) => lookup_const_by_id(tcx, ic.def_id, None), + let ac = tcx.impl_or_trait_items(impl_data.impl_def_id) + .iter().filter_map(|id| { + match *id { + ty::ConstTraitItemId(def_id) => { + Some(tcx.impl_or_trait_item(def_id)) + } + _ => None + } + }).find(|ic| ic.name() == ti.name); + match ac { + Some(ic) => lookup_const_by_id(tcx, ic.def_id(), None), None => match ti.node { hir::ConstTraitItem(ref ty, Some(ref expr)) => { Some((&*expr, tcx.ast_ty_to_prim_ty(ty))) diff --git a/src/librustc_metadata/common.rs b/src/librustc_metadata/common.rs index 123ed11a7a51..94581a3fc897 100644 --- a/src/librustc_metadata/common.rs +++ b/src/librustc_metadata/common.rs @@ -10,13 +10,38 @@ #![allow(non_camel_case_types, non_upper_case_globals)] +use rustc::ty; + +#[derive(Clone, Copy, Debug, PartialEq, RustcEncodable, RustcDecodable)] +pub enum Family { + ImmStatic, + MutStatic, + Fn, + Method, + AssociatedType, + Type, + Mod, + ForeignMod, + Enum, + Variant(ty::VariantKind), + Impl, + DefaultImpl, + Trait, + Struct(ty::VariantKind), + Union, + PublicField, + InheritedField, + Const, + AssociatedConst, +} + // GAP 0x00...0x19 pub const tag_items: usize = 0x100; // top-level only pub const tag_paths_data_name: usize = 0x20; -pub const tag_def_id: usize = 0x21; +pub const tag_def_index: usize = 0x21; pub const tag_items_data: usize = 0x22; @@ -26,9 +51,7 @@ pub const tag_items_data_item_family: usize = 0x24; pub const tag_items_data_item_type: usize = 0x25; -// GAP 0x26 - -pub const tag_items_data_item_variant: usize = 0x27; +// GAP 0x26, 0x27 pub const tag_items_data_parent_item: usize = 0x28; @@ -47,19 +70,11 @@ pub const tag_attributes: usize = 0x101; // top-level only // The list of crates that this crate depends on pub const tag_crate_deps: usize = 0x102; // top-level only - -// A single crate dependency -pub const tag_crate_dep: usize = 0x35; - pub const tag_crate_hash: usize = 0x103; // top-level only pub const tag_crate_crate_name: usize = 0x104; // top-level only pub const tag_crate_disambiguator: usize = 0x113; // top-level only -pub const tag_crate_dep_crate_name: usize = 0x36; -pub const tag_crate_dep_hash: usize = 0x37; -pub const tag_crate_dep_explicitly_linked: usize = 0x38; // top-level only - -pub const tag_item_trait_item: usize = 0x3a; +// GAP 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a pub const tag_item_trait_ref: usize = 0x3b; @@ -68,26 +83,13 @@ pub const tag_disr_val: usize = 0x3c; // GAP 0x3d, 0x3e, 0x3f, 0x40 -pub const tag_item_field: usize = 0x41; +pub const tag_item_fields: usize = 0x41; // GAP 0x42 pub const tag_item_variances: usize = 0x43; -/* - trait items contain tag_item_trait_item elements, - impl items contain tag_item_impl_item elements, and classes - have both. That's because some code treats classes like traits, - and other code treats them like impls. Because classes can contain - both, tag_item_trait_item and tag_item_impl_item have to be two - different tags. - */ -pub const tag_item_impl_item: usize = 0x44; +// GAP 0x44 pub const tag_item_trait_method_explicit_self: usize = 0x45; - -// Reexports are found within module tags. Each reexport contains def_ids -// and names. -pub const tag_items_data_item_reexport: usize = 0x46; -pub const tag_items_data_item_reexport_def_id: usize = 0x47; -pub const tag_items_data_item_reexport_name: usize = 0x48; +// GAP 0x46, 0x47, 0x48 // used to encode crate_ctxt side tables pub const tag_ast: usize = 0x50; @@ -98,58 +100,58 @@ pub const tag_mir: usize = 0x52; // GAP 0x53...0x6a -pub const tag_item_trait_item_sort: usize = 0x70; +pub const tag_item_trait_item_has_body: usize = 0x70; pub const tag_crate_triple: usize = 0x105; // top-level only pub const tag_dylib_dependency_formats: usize = 0x106; // top-level only -// Language items are a top-level directory (for speed). Hierarchy: -// -// tag_lang_items -// - tag_lang_items_item -// - tag_lang_items_item_id: u32 -// - tag_lang_items_item_index: u32 - pub const tag_lang_items: usize = 0x107; // top-level only -pub const tag_lang_items_item: usize = 0x73; -pub const tag_lang_items_item_id: usize = 0x74; -pub const tag_lang_items_item_index: usize = 0x75; -pub const tag_lang_items_missing: usize = 0x76; -pub const tag_item_unnamed_field: usize = 0x77; +// GAP 0x73, 0x74, 0x75 + +pub const tag_lang_items_missing: usize = 0x76; // top-level only + +// GAP 0x77 + pub const tag_items_data_item_visibility: usize = 0x78; -pub const tag_items_data_item_inherent_impl: usize = 0x79; +pub const tag_items_data_item_inherent_impls: usize = 0x79; + // GAP 0x7a -pub const tag_mod_child: usize = 0x7b; + +// GAP 0x7c +pub const tag_mod_children: usize = 0x7b; + +// GAP 0x108 // top-level only + // GAP 0x7c // GAP 0x108 pub const tag_impls: usize = 0x109; // top-level only -pub const tag_impls_trait: usize = 0x7d; -pub const tag_impls_trait_impl: usize = 0x7e; -// GAP 0x7f, 0x80, 0x81 +// GAP 0x7d, 0x7e, 0x7f, 0x80, 0x81 pub const tag_native_libraries: usize = 0x10a; // top-level only -pub const tag_native_libraries_lib: usize = 0x82; -pub const tag_native_libraries_name: usize = 0x83; -pub const tag_native_libraries_kind: usize = 0x84; + +// GAP 0x82, 0x83, 0x84 pub const tag_plugin_registrar_fn: usize = 0x10b; // top-level only pub const tag_method_argument_names: usize = 0x85; -pub const tag_method_argument_name: usize = 0x86; + +// GAP 0x86 pub const tag_reachable_ids: usize = 0x10c; // top-level only -pub const tag_reachable_id: usize = 0x87; + +// GAP 0x87 pub const tag_items_data_item_stability: usize = 0x88; pub const tag_items_data_item_repr: usize = 0x89; -pub const tag_struct_fields: usize = 0x10d; // top-level only -pub const tag_struct_field: usize = 0x8a; +// GAP 0x10d // top-level only + +// GAP 0x8a pub const tag_items_data_item_struct_ctor: usize = 0x8b; pub const tag_attribute_is_sugared_doc: usize = 0x8c; @@ -160,10 +162,7 @@ pub const tag_item_generics: usize = 0x8f; // GAP 0x90, 0x91, 0x92, 0x93, 0x94 pub const tag_item_predicates: usize = 0x95; -// GAP 0x96 - -pub const tag_predicate: usize = 0x97; -// GAP 0x98, 0x99 +// GAP 0x96, 0x97, 0x98, 0x99 pub const tag_unsafety: usize = 0x9a; @@ -173,15 +172,14 @@ pub const tag_associated_type_name: usize = 0x9c; pub const tag_polarity: usize = 0x9d; pub const tag_macro_defs: usize = 0x10e; // top-level only -pub const tag_macro_def: usize = 0x9e; -pub const tag_macro_def_body: usize = 0x9f; -pub const tag_macro_def_span_lo: usize = 0xa8; -pub const tag_macro_def_span_hi: usize = 0xa9; + +// GAP 0x9e, 0x9f pub const tag_paren_sugar: usize = 0xa0; pub const tag_codemap: usize = 0xa1; -pub const tag_codemap_filemap: usize = 0xa2; + +// GAP 0xa2 pub const tag_item_super_predicates: usize = 0xa3; diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 2774ffdf6c77..7b6ed4e6b764 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -264,7 +264,7 @@ impl<'a> CrateReader<'a> { // Check for (potential) conflicts with the local crate if self.local_crate_name == crate_name && - self.sess.local_crate_disambiguator() == disambiguator { + self.sess.local_crate_disambiguator() == &disambiguator[..] { span_fatal!(self.sess, span, E0519, "the current crate is indistinguishable from one of its \ dependencies: it has the same crate-name `{}` and was \ @@ -320,7 +320,6 @@ impl<'a> CrateReader<'a> { let loader::Library { dylib, rlib, metadata } = lib; let cnum_map = self.resolve_crate_deps(root, metadata.as_slice(), cnum, span); - let staged_api = self.is_staged_api(metadata.as_slice()); let cmeta = Rc::new(cstore::CrateMetadata { name: name.to_string(), @@ -332,7 +331,6 @@ impl<'a> CrateReader<'a> { cnum_map: RefCell::new(cnum_map), cnum: cnum, codemap_import_info: RefCell::new(vec![]), - staged_api: staged_api, explicitly_linked: Cell::new(explicitly_linked), }); @@ -352,16 +350,6 @@ impl<'a> CrateReader<'a> { (cnum, cmeta, source) } - fn is_staged_api(&self, data: &[u8]) -> bool { - let attrs = decoder::get_crate_attributes(data); - for attr in &attrs { - if attr.name() == "stable" || attr.name() == "unstable" { - return true - } - } - false - } - fn resolve_crate(&mut self, root: &Option, ident: &str, diff --git a/src/librustc_metadata/csearch.rs b/src/librustc_metadata/csearch.rs index b291c4927aa3..38b18fa63e3e 100644 --- a/src/librustc_metadata/csearch.rs +++ b/src/librustc_metadata/csearch.rs @@ -14,11 +14,11 @@ use decoder; use encoder; use loader; -use middle::cstore::{InlinedItem, CrateStore, CrateSource, ChildItem, ExternCrate, DefLike}; +use middle::cstore::{InlinedItem, CrateStore, CrateSource, ChildItem, ExternCrate}; use middle::cstore::{NativeLibraryKind, LinkMeta, LinkagePreference}; use rustc::hir::def; use middle::lang_items; -use rustc::ty::{self, Ty, TyCtxt, VariantKind}; +use rustc::ty::{self, Ty, TyCtxt}; use rustc::hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX}; use rustc::dep_graph::DepNode; @@ -26,10 +26,9 @@ use rustc::hir::map as hir_map; use rustc::hir::map::DefKey; use rustc::mir::repr::Mir; use rustc::mir::mir_map::MirMap; -use rustc::util::nodemap::{FnvHashMap, NodeSet, DefIdMap}; +use rustc::util::nodemap::{NodeSet, DefIdMap}; use rustc::session::config::PanicStrategy; -use std::rc::Rc; use std::path::PathBuf; use syntax::ast; use syntax::attr; @@ -166,42 +165,27 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { result } - fn implementations_of_trait(&self, def_id: DefId) -> Vec + fn implementations_of_trait(&self, filter: Option) -> Vec { - self.dep_graph.read(DepNode::MetaData(def_id)); + if let Some(def_id) = filter { + self.dep_graph.read(DepNode::MetaData(def_id)); + } let mut result = vec![]; self.iter_crate_data(|_, cdata| { - decoder::each_implementation_for_trait(cdata, def_id, &mut |iid| { + decoder::each_implementation_for_trait(cdata, filter, &mut |iid| { result.push(iid) }) }); result } - fn provided_trait_methods<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) - -> Vec>> - { - self.dep_graph.read(DepNode::MetaData(def)); - let cdata = self.get_crate_data(def.krate); - decoder::get_provided_trait_methods(&cdata, def.index, tcx) + fn impl_or_trait_items(&self, def_id: DefId) -> Vec { + self.dep_graph.read(DepNode::MetaData(def_id)); + let cdata = self.get_crate_data(def_id.krate); + decoder::get_impl_or_trait_items(&cdata, def_id.index) } - fn trait_item_def_ids(&self, def: DefId) - -> Vec - { - self.dep_graph.read(DepNode::MetaData(def)); - let cdata = self.get_crate_data(def.krate); - decoder::get_trait_item_def_ids(&cdata, def.index) - } - - fn impl_items(&self, impl_def_id: DefId) -> Vec - { - self.dep_graph.read(DepNode::MetaData(impl_def_id)); - let cdata = self.get_crate_data(impl_def_id.krate); - decoder::get_impl_items(&cdata, impl_def_id.index) - } - - fn impl_polarity(&self, def: DefId) -> Option + fn impl_polarity(&self, def: DefId) -> hir::ImplPolarity { self.dep_graph.read(DepNode::MetaData(def)); let cdata = self.get_crate_data(def.krate); @@ -224,14 +208,6 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { decoder::get_custom_coerce_unsized_kind(&cdata, def.index) } - // FIXME: killme - fn associated_consts<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) - -> Vec>> { - self.dep_graph.read(DepNode::MetaData(def)); - let cdata = self.get_crate_data(def.krate); - decoder::get_associated_consts(&cdata, def.index, tcx) - } - fn impl_parent(&self, impl_def: DefId) -> Option { self.dep_graph.read(DepNode::MetaData(impl_def)); let cdata = self.get_crate_data(impl_def.krate); @@ -266,13 +242,6 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { decoder::is_defaulted_trait(&cdata, trait_def_id.index) } - fn is_impl(&self, did: DefId) -> bool - { - self.dep_graph.read(DepNode::MetaData(did)); - let cdata = self.get_crate_data(did.krate); - decoder::is_impl(&cdata, did.index) - } - fn is_default_impl(&self, impl_did: DefId) -> bool { self.dep_graph.read(DepNode::MetaData(impl_did)); let cdata = self.get_crate_data(impl_did.krate); @@ -295,12 +264,6 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { self.do_is_statically_included_foreign_item(id) } - fn is_typedef(&self, did: DefId) -> bool { - self.dep_graph.read(DepNode::MetaData(did)); - let cdata = self.get_crate_data(did.krate); - decoder::is_typedef(&cdata, did.index) - } - fn dylib_dependency_formats(&self, cnum: CrateNum) -> Vec<(CrateNum, LinkagePreference)> { @@ -310,12 +273,8 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { fn lang_items(&self, cnum: CrateNum) -> Vec<(DefIndex, usize)> { - let mut result = vec![]; let crate_data = self.get_crate_data(cnum); - decoder::each_lang_item(&crate_data, |did, lid| { - result.push((did, lid)); true - }); - result + decoder::get_lang_items(&crate_data) } fn missing_lang_items(&self, cnum: CrateNum) @@ -327,7 +286,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { fn is_staged_api(&self, cnum: CrateNum) -> bool { - self.get_crate_data(cnum).staged_api + self.get_crate_data(cnum).is_staged_api() } fn is_explicitly_linked(&self, cnum: CrateNum) -> bool @@ -355,7 +314,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { fn crate_attrs(&self, cnum: CrateNum) -> Vec { - decoder::get_crate_attributes(self.get_crate_data(cnum).data()) + decoder::get_item_attrs(&self.get_crate_data(cnum), CRATE_DEF_INDEX) } fn crate_name(&self, cnum: CrateNum) -> token::InternedString @@ -382,13 +341,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { fn crate_disambiguator(&self, cnum: CrateNum) -> token::InternedString { let cdata = self.get_crate_data(cnum); - token::intern_and_get_ident(decoder::get_crate_disambiguator(cdata.data())) - } - - fn crate_struct_field_attrs(&self, cnum: CrateNum) - -> FnvHashMap> - { - decoder::get_struct_field_attrs(&self.get_crate_data(cnum)) + token::intern_and_get_ident(&decoder::get_crate_disambiguator(cdata.data())) } fn plugin_registrar_fn(&self, cnum: CrateNum) -> Option @@ -447,12 +400,6 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { decoder::def_path(&cdata, def.index) } - fn variant_kind(&self, def_id: DefId) -> Option { - self.dep_graph.read(DepNode::MetaData(def_id)); - let cdata = self.get_crate_data(def_id.krate); - decoder::get_variant_kind(&cdata, def_id.index) - } - fn struct_ctor_def_id(&self, struct_def_id: DefId) -> Option { self.dep_graph.read(DepNode::MetaData(struct_def_id)); @@ -486,17 +433,6 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { result } - fn crate_top_level_items(&self, cnum: CrateNum) -> Vec - { - let mut result = vec![]; - let crate_data = self.get_crate_data(cnum); - let get_crate_data = |cnum| self.get_crate_data(cnum); - decoder::each_top_level_item_of_crate(&crate_data, get_crate_data, |def, name, vis| { - result.push(ChildItem { def: def, name: name, vis: vis }); - }); - result - } - fn maybe_get_item_ast<'a>(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) @@ -726,9 +662,10 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { let mut bfs_queue = &mut VecDeque::new(); let mut add_child = |bfs_queue: &mut VecDeque<_>, child: ChildItem, parent: DefId| { - let child = match child.def { - DefLike::DlDef(def) if child.vis == ty::Visibility::Public => def.def_id(), - _ => return, + let child = if child.vis == ty::Visibility::Public { + child.def.def_id() + } else { + return; }; match visible_parent_map.entry(child) { @@ -746,10 +683,10 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { } }; - let croot = DefId { krate: cnum, index: CRATE_DEF_INDEX }; - for child in self.crate_top_level_items(cnum) { - add_child(bfs_queue, child, croot); - } + bfs_queue.push_back(DefId { + krate: cnum, + index: CRATE_DEF_INDEX + }); while let Some(def) = bfs_queue.pop_front() { for child in self.item_children(def) { add_child(bfs_queue, child, def); @@ -760,4 +697,3 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { visible_parent_map } } - diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs index 388620a2dafd..7aa4677353bb 100644 --- a/src/librustc_metadata/cstore.rs +++ b/src/librustc_metadata/cstore.rs @@ -22,7 +22,7 @@ use index; use loader; use rustc::dep_graph::DepGraph; -use rustc::hir::def_id::{CrateNum, DefIndex, DefId}; +use rustc::hir::def_id::{CRATE_DEF_INDEX, CrateNum, DefIndex, DefId}; use rustc::hir::map::DefKey; use rustc::hir::svh::Svh; use rustc::middle::cstore::ExternCrate; @@ -77,7 +77,6 @@ pub struct CrateMetadata { pub cnum_map: RefCell, pub cnum: CrateNum, pub codemap_import_info: RefCell>, - pub staged_api: bool, pub index: index::Index, pub xref_index: index::DenseIndex, @@ -300,9 +299,9 @@ impl CStore { impl CrateMetadata { pub fn data<'a>(&'a self) -> &'a [u8] { self.data.as_slice() } - pub fn name(&self) -> &str { decoder::get_crate_name(self.data()) } + pub fn name(&self) -> String { decoder::get_crate_name(self.data()) } pub fn hash(&self) -> Svh { decoder::get_crate_hash(self.data()) } - pub fn disambiguator(&self) -> &str { + pub fn disambiguator(&self) -> String { decoder::get_crate_disambiguator(self.data()) } pub fn imported_filemaps<'a>(&'a self, codemap: &codemap::CodeMap) @@ -320,23 +319,30 @@ impl CrateMetadata { } } + pub fn is_staged_api(&self) -> bool { + let attrs = decoder::get_item_attrs(self, CRATE_DEF_INDEX); + attrs.iter().any(|attr| { + attr.name() == "stable" || attr.name() == "unstable" + }) + } + pub fn is_allocator(&self) -> bool { - let attrs = decoder::get_crate_attributes(self.data()); + let attrs = decoder::get_item_attrs(self, CRATE_DEF_INDEX); attr::contains_name(&attrs, "allocator") } pub fn needs_allocator(&self) -> bool { - let attrs = decoder::get_crate_attributes(self.data()); + let attrs = decoder::get_item_attrs(self, CRATE_DEF_INDEX); attr::contains_name(&attrs, "needs_allocator") } pub fn is_panic_runtime(&self) -> bool { - let attrs = decoder::get_crate_attributes(self.data()); + let attrs = decoder::get_item_attrs(self, CRATE_DEF_INDEX); attr::contains_name(&attrs, "panic_runtime") } pub fn needs_panic_runtime(&self) -> bool { - let attrs = decoder::get_crate_attributes(self.data()); + let attrs = decoder::get_item_attrs(self, CRATE_DEF_INDEX); attr::contains_name(&attrs, "needs_panic_runtime") } diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 0118cacad182..507e6414181b 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -12,13 +12,11 @@ #![allow(non_camel_case_types)] -use self::Family::*; - use astencode::decode_inlined_item; use cstore::{self, CrateMetadata}; use common::*; +use common::Family::*; use def_key; -use encoder::def_to_u64; use index; use rustc::hir::def_id::CRATE_DEF_INDEX; @@ -31,12 +29,11 @@ use rustc::hir::intravisit::IdRange; use rustc::session::config::PanicStrategy; use middle::cstore::{InlinedItem, LinkagePreference}; -use middle::cstore::{DefLike, DlDef, DlField, DlImpl}; -use rustc::hir::def::Def; +use rustc::hir::def::{self, Def}; use rustc::hir::def_id::{CrateNum, DefId, DefIndex, LOCAL_CRATE}; use middle::lang_items; use rustc::ty::{ImplContainer, TraitContainer}; -use rustc::ty::{self, AdtKind, Ty, TyCtxt, TypeFoldable, VariantKind}; +use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc::ty::subst::Substs; use rustc_const_math::ConstInt; @@ -52,12 +49,9 @@ use std::u32; use rbml::reader; use rbml; use rustc_serialize::{Decodable, Decoder, SpecializedDecoder, opaque}; -use rustc_serialize as serialize; use syntax::attr; -use syntax::parse::token; use syntax::ast::{self, NodeId}; -use syntax::print::pprust; -use syntax_pos::{self, Span, BytePos, NO_EXPANSION}; +use syntax_pos::{self, Span, BytePos}; pub struct DecodeContext<'a, 'tcx: 'a> { pub opaque: opaque::Decoder<'a>, @@ -94,6 +88,25 @@ impl<'a, 'tcx> DecodeContext<'a, 'tcx> { pub fn cdata(&self) -> &'a cstore::CrateMetadata { self.cdata.expect("missing CrateMetadata in DecodeContext") } + + pub fn decode(&mut self) -> T { + T::decode(self).unwrap() + } + + /// Iterate over the indices of a sequence. + /// This will work solely because of `serialize::opaque`'s + /// simple encoding of `n: usize` followed by `n` elements. + pub fn seq(mut self) -> impl Iterator { + (0..self.read_usize().unwrap()).map(move |_| { + self.decode() + }) + } + + pub fn seq_mut<'b, T: Decodable>(&'b mut self) -> impl Iterator + 'b { + (0..self.read_usize().unwrap()).map(move |_| { + self.decode() + }) + } } macro_rules! decoder_methods { @@ -104,8 +117,8 @@ macro_rules! decoder_methods { } } -impl<'doc, 'tcx> serialize::Decoder for ::decoder::DecodeContext<'doc, 'tcx> { - type Error = as serialize::Decoder>::Error; +impl<'doc, 'tcx> Decoder for DecodeContext<'doc, 'tcx> { + type Error = as Decoder>::Error; decoder_methods! { read_nil -> (); @@ -311,175 +324,70 @@ impl CrateMetadata { } pub fn load_index(data: &[u8]) -> index::Index { - let index = reader::get_doc(rbml::Doc::new(data), tag_index); - index::Index::from_rbml(index) + index::Index::from_rbml(rbml::Doc::new(data).get(tag_index)) } pub fn crate_rustc_version(data: &[u8]) -> Option { let doc = rbml::Doc::new(data); - reader::maybe_get_doc(doc, tag_rustc_version).map(|s| s.to_string()) + reader::maybe_get_doc(doc, tag_rustc_version).map(|s| { + str::from_utf8(&s.data[s.start..s.end]).unwrap().to_string() + }) } pub fn load_xrefs(data: &[u8]) -> index::DenseIndex { - let index = reader::get_doc(rbml::Doc::new(data), tag_xref_index); + let index = rbml::Doc::new(data).get(tag_xref_index); index::DenseIndex::from_buf(index.data, index.start, index.end) } // Go through each item in the metadata and create a map from that // item's def-key to the item's DefIndex. pub fn load_key_map(data: &[u8]) -> FnvHashMap { - let root_doc = rbml::Doc::new(data); - let items_doc = reader::get_doc(root_doc, tag_items); - let items_data_doc = reader::get_doc(items_doc, tag_items_data); - reader::docs(items_data_doc) - .filter(|&(tag, _)| tag == tag_items_data_item) - .map(|(_, item_doc)| { - // load def-key from item - let key = item_def_key(item_doc); + rbml::Doc::new(data).get(tag_items).get(tag_items_data).children().map(|item_doc| { + // load def-key from item + let key = item_def_key(item_doc); - // load def-index from item; we only encode the full def-id, - // so just pull out the index - let def_id_doc = reader::get_doc(item_doc, tag_def_id); - let def_id = untranslated_def_id(def_id_doc); - assert!(def_id.is_local()); // local to the crate we are decoding, that is - - (key, def_id.index) - }) - .collect() -} - -#[derive(Clone, Copy, Debug, PartialEq)] -enum Family { - ImmStatic, // c - MutStatic, // b - Fn, // f - StaticMethod, // F - Method, // h - Type, // y - Mod, // m - ForeignMod, // n - Enum, // t - Variant(VariantKind), // V, v, w - Impl, // i - DefaultImpl, // d - Trait, // I - Struct(VariantKind), // S, s, u - Union, // U - PublicField, // g - InheritedField, // N - Constant, // C + // load def-index from item + (key, item_doc.get(tag_def_index).decoder().decode()) + }).collect() } fn item_family(item: rbml::Doc) -> Family { - let fam = reader::get_doc(item, tag_items_data_item_family); - match reader::doc_as_u8(fam) as char { - 'C' => Constant, - 'c' => ImmStatic, - 'b' => MutStatic, - 'f' => Fn, - 'F' => StaticMethod, - 'h' => Method, - 'y' => Type, - 'm' => Mod, - 'n' => ForeignMod, - 't' => Enum, - 'V' => Variant(VariantKind::Struct), - 'v' => Variant(VariantKind::Tuple), - 'w' => Variant(VariantKind::Unit), - 'i' => Impl, - 'd' => DefaultImpl, - 'I' => Trait, - 'S' => Struct(VariantKind::Struct), - 's' => Struct(VariantKind::Tuple), - 'u' => Struct(VariantKind::Unit), - 'U' => Union, - 'g' => PublicField, - 'N' => InheritedField, - c => bug!("unexpected family char: {}", c) - } + item.get(tag_items_data_item_family).decoder().decode() } fn item_visibility(item: rbml::Doc) -> ty::Visibility { match reader::maybe_get_doc(item, tag_items_data_item_visibility) { None => ty::Visibility::Public, - Some(visibility_doc) => { - match reader::doc_as_u8(visibility_doc) as char { - 'y' => ty::Visibility::Public, - 'i' => ty::Visibility::PrivateExternal, - _ => bug!("unknown visibility character") - } - } - } -} - -fn fn_constness(item: rbml::Doc) -> hir::Constness { - match reader::maybe_get_doc(item, tag_items_data_item_constness) { - None => hir::Constness::NotConst, - Some(constness_doc) => { - match reader::doc_as_u8(constness_doc) as char { - 'c' => hir::Constness::Const, - 'n' => hir::Constness::NotConst, - _ => bug!("unknown constness character") - } - } + Some(visibility_doc) => visibility_doc.decoder().decode() } } fn item_defaultness(item: rbml::Doc) -> hir::Defaultness { match reader::maybe_get_doc(item, tag_items_data_item_defaultness) { None => hir::Defaultness::Default, // should occur only for default impls on traits - Some(defaultness_doc) => { - match reader::doc_as_u8(defaultness_doc) as char { - 'd' => hir::Defaultness::Default, - 'f' => hir::Defaultness::Final, - _ => bug!("unknown defaultness character") - } - } + Some(defaultness_doc) => defaultness_doc.decoder().decode() } } -fn item_sort(item: rbml::Doc) -> Option { - reader::tagged_docs(item, tag_item_trait_item_sort).nth(0).map(|doc| { - doc.as_str().as_bytes()[0] as char - }) -} - -fn untranslated_def_id(d: rbml::Doc) -> DefId { - let id = reader::doc_as_u64(d); - DefId { - krate: CrateNum::from_u32((id >> 32) as u32), - index: DefIndex::from_u32((id & 0xFFFF_FFFF) as u32) - } -} - -fn translated_def_id(cdata: Cmd, d: rbml::Doc) -> DefId { - let def_id = untranslated_def_id(d); - translate_def_id(cdata, def_id) -} - fn item_parent_item(cdata: Cmd, d: rbml::Doc) -> Option { - reader::tagged_docs(d, tag_items_data_parent_item).nth(0).map(|did| { - translated_def_id(cdata, did) + reader::maybe_get_doc(d, tag_items_data_parent_item).map(|did| { + let mut dcx = did.decoder(); + dcx.cdata = Some(cdata); + dcx.decode() }) } fn item_require_parent_item(cdata: Cmd, d: rbml::Doc) -> DefId { - translated_def_id(cdata, reader::get_doc(d, tag_items_data_parent_item)) + let mut dcx = d.get(tag_items_data_parent_item).decoder(); + dcx.cdata = Some(cdata); + dcx.decode() } fn item_def_id(d: rbml::Doc, cdata: Cmd) -> DefId { - translated_def_id(cdata, reader::get_doc(d, tag_def_id)) -} - -fn reexports<'a>(d: rbml::Doc<'a>) -> reader::TaggedDocsIterator<'a> { - reader::tagged_docs(d, tag_items_data_item_reexport) -} - -fn variant_disr_val(d: rbml::Doc) -> u64 { - let val_doc = reader::get_doc(d, tag_disr_val); - reader::with_doc_data(val_doc, |data| { - str::from_utf8(data).unwrap().parse().unwrap() - }) + DefId { + krate: cdata.cnum, + index: d.get(tag_def_index).decoder().decode() + } } fn doc_type<'a, 'tcx>(doc: rbml::Doc, tcx: TyCtxt<'a, 'tcx, 'tcx>, cdata: Cmd) -> Ty<'tcx> { @@ -492,7 +400,7 @@ fn maybe_doc_type<'a, 'tcx>(doc: rbml::Doc, tcx: TyCtxt<'a, 'tcx, 'tcx>, cdata: let mut dcx = tp.decoder(); dcx.tcx = Some(tcx); dcx.cdata = Some(cdata); - Decodable::decode(&mut dcx).unwrap() + dcx.decode() }) } @@ -501,13 +409,7 @@ fn doc_trait_ref<'a, 'tcx>(doc: rbml::Doc, tcx: TyCtxt<'a, 'tcx, 'tcx>, cdata: C let mut dcx = doc.decoder(); dcx.tcx = Some(tcx); dcx.cdata = Some(cdata); - Decodable::decode(&mut dcx).unwrap() -} - -fn item_trait_ref<'a, 'tcx>(doc: rbml::Doc, tcx: TyCtxt<'a, 'tcx, 'tcx>, cdata: Cmd) - -> ty::TraitRef<'tcx> { - let tp = reader::get_doc(doc, tag_item_trait_ref); - doc_trait_ref(tp, tcx, cdata) + dcx.decode() } fn item_name(item: rbml::Doc) -> ast::Name { @@ -516,95 +418,43 @@ fn item_name(item: rbml::Doc) -> ast::Name { fn maybe_item_name(item: rbml::Doc) -> Option { reader::maybe_get_doc(item, tag_paths_data_name).map(|name| { - let string = name.as_str(); - token::intern(string) + name.decoder().decode() }) } -fn family_to_variant_kind<'tcx>(family: Family) -> Option { - match family { - Struct(VariantKind::Struct) | Variant(VariantKind::Struct) | Union => - Some(ty::VariantKind::Struct), - Struct(VariantKind::Tuple) | Variant(VariantKind::Tuple) => - Some(ty::VariantKind::Tuple), - Struct(VariantKind::Unit) | Variant(VariantKind::Unit) => - Some(ty::VariantKind::Unit), - _ => None, - } -} - -fn item_to_def_like(cdata: Cmd, item: rbml::Doc, did: DefId) -> DefLike { - let fam = item_family(item); - match fam { - Constant => { - // Check whether we have an associated const item. - match item_sort(item) { - Some('C') | Some('c') => { - DlDef(Def::AssociatedConst(did)) - } - _ => { - // Regular const item. - DlDef(Def::Const(did)) - } - } +fn item_to_def(cdata: Cmd, item: rbml::Doc, did: DefId) -> Option { + Some(match item_family(item) { + Family::Const => Def::Const(did), + Family::AssociatedConst => Def::AssociatedConst(did), + Family::ImmStatic => Def::Static(did, false), + Family::MutStatic => Def::Static(did, true), + Family::Struct(..) => Def::Struct(did), + Family::Union => Def::Union(did), + Family::Fn => Def::Fn(did), + Family::Method => Def::Method(did), + Family::Type => Def::TyAlias(did), + Family::AssociatedType => { + Def::AssociatedTy(item_require_parent_item(cdata, item), did) } - ImmStatic => DlDef(Def::Static(did, false)), - MutStatic => DlDef(Def::Static(did, true)), - Struct(..) => DlDef(Def::Struct(did)), - Union => DlDef(Def::Union(did)), - Fn => DlDef(Def::Fn(did)), - Method | StaticMethod => { - DlDef(Def::Method(did)) + Family::Mod => Def::Mod(did), + Family::ForeignMod => Def::ForeignMod(did), + Family::Variant(..) => { + Def::Variant(item_require_parent_item(cdata, item), did) } - Type => { - if item_sort(item) == Some('t') { - let trait_did = item_require_parent_item(cdata, item); - DlDef(Def::AssociatedTy(trait_did, did)) - } else { - DlDef(Def::TyAlias(did)) - } + Family::Trait => Def::Trait(did), + Family::Enum => Def::Enum(did), + + Family::Impl | + Family::DefaultImpl | + Family::PublicField | + Family::InheritedField => { + return None } - Mod => DlDef(Def::Mod(did)), - ForeignMod => DlDef(Def::ForeignMod(did)), - Variant(..) => { - let enum_did = item_require_parent_item(cdata, item); - DlDef(Def::Variant(enum_did, did)) - } - Trait => DlDef(Def::Trait(did)), - Enum => DlDef(Def::Enum(did)), - Impl | DefaultImpl => DlImpl(did), - PublicField | InheritedField => DlField, - } -} - -fn parse_unsafety(item_doc: rbml::Doc) -> hir::Unsafety { - let unsafety_doc = reader::get_doc(item_doc, tag_unsafety); - if reader::doc_as_u8(unsafety_doc) != 0 { - hir::Unsafety::Unsafe - } else { - hir::Unsafety::Normal - } -} - -fn parse_paren_sugar(item_doc: rbml::Doc) -> bool { - let paren_sugar_doc = reader::get_doc(item_doc, tag_paren_sugar); - reader::doc_as_u8(paren_sugar_doc) != 0 -} - -fn parse_polarity(item_doc: rbml::Doc) -> hir::ImplPolarity { - let polarity_doc = reader::get_doc(item_doc, tag_polarity); - if reader::doc_as_u8(polarity_doc) != 0 { - hir::ImplPolarity::Negative - } else { - hir::ImplPolarity::Positive - } + }) } fn parse_associated_type_names(item_doc: rbml::Doc) -> Vec { - let names_doc = reader::get_doc(item_doc, tag_associated_type_names); - reader::tagged_docs(names_doc, tag_associated_type_name) - .map(|name_doc| token::intern(name_doc.as_str())) - .collect() + item_doc.get(tag_associated_type_names).decoder().decode() } pub fn get_trait_def<'a, 'tcx>(cdata: Cmd, @@ -613,15 +463,16 @@ pub fn get_trait_def<'a, 'tcx>(cdata: Cmd, { let item_doc = cdata.lookup_item(item_id); let generics = doc_generics(item_doc, tcx, cdata); - let unsafety = parse_unsafety(item_doc); + let unsafety = item_doc.get(tag_unsafety).decoder().decode(); let associated_type_names = parse_associated_type_names(item_doc); - let paren_sugar = parse_paren_sugar(item_doc); + let paren_sugar = item_doc.get(tag_paren_sugar).decoder().decode(); + let trait_ref = doc_trait_ref(item_doc.get(tag_item_trait_ref), tcx, cdata); let def_path = def_path(cdata, item_id).unwrap(); ty::TraitDef::new(unsafety, paren_sugar, generics, - item_trait_ref(item_doc, tcx, cdata), + trait_ref, associated_type_names, def_path.deterministic_hash(tcx)) } @@ -632,16 +483,19 @@ pub fn get_adt_def<'a, 'tcx>(cdata: Cmd, -> ty::AdtDefMaster<'tcx> { fn expect_variant_kind(family: Family) -> ty::VariantKind { - match family_to_variant_kind(family) { - Some(kind) => kind, + match family { + Struct(kind) | Variant(kind) => kind, + Union => ty::VariantKind::Struct, _ => bug!("unexpected family: {:?}", family), } } fn get_enum_variants<'tcx>(cdata: Cmd, doc: rbml::Doc) -> Vec> { - reader::tagged_docs(doc, tag_items_data_item_variant).map(|p| { - let did = translated_def_id(cdata, p); + let mut dcx = doc.get(tag_mod_children).decoder(); + dcx.cdata = Some(cdata); + + dcx.seq().map(|did: DefId| { let item = cdata.lookup_item(did.index); - let disr = variant_disr_val(item); + let disr = item.get(tag_disr_val).decoder().decode(); ty::VariantDefData { did: did, name: item_name(item), @@ -652,23 +506,18 @@ pub fn get_adt_def<'a, 'tcx>(cdata: Cmd, }).collect() } fn get_variant_fields<'tcx>(cdata: Cmd, doc: rbml::Doc) -> Vec> { - let mut index = 0; - reader::tagged_docs(doc, tag_item_field).map(|f| { - let ff = item_family(f); - match ff { - PublicField | InheritedField => {}, - _ => bug!("expected field, found {:?}", ff) + let mut dcx = doc.get(tag_item_fields).decoder(); + dcx.cdata = Some(cdata); + + dcx.seq().map(|did: DefId| { + let f = cdata.lookup_item(did.index); + let vis = match item_family(f) { + PublicField => ty::Visibility::Public, + InheritedField => ty::Visibility::PrivateExternal, + _ => bug!() }; - ty::FieldDefData::new(item_def_id(f, cdata), - item_name(f), - struct_field_family_to_visibility(ff)) - }).chain(reader::tagged_docs(doc, tag_item_unnamed_field).map(|f| { - let ff = item_family(f); - let name = token::with_ident_interner(|interner| interner.intern(index.to_string())); - index += 1; - ty::FieldDefData::new(item_def_id(f, cdata), name, - struct_field_family_to_visibility(ff)) - })).collect() + ty::FieldDefData::new(did, item_name(f), vis) + }).collect() } fn get_struct_variant<'tcx>(cdata: Cmd, doc: rbml::Doc, @@ -692,7 +541,9 @@ pub fn get_adt_def<'a, 'tcx>(cdata: Cmd, Struct(..) => { // Use separate constructor id for unit/tuple structs and reuse did for braced structs. ctor_did = reader::maybe_get_doc(doc, tag_items_data_item_struct_ctor).map(|ctor_doc| { - translated_def_id(cdata, ctor_doc) + let mut dcx = ctor_doc.decoder(); + dcx.cdata = Some(cdata); + dcx.decode() }); (AdtKind::Struct, vec![get_struct_variant(cdata, doc, ctor_did.unwrap_or(did))]) } @@ -784,14 +635,14 @@ pub fn get_type<'a, 'tcx>(cdata: Cmd, id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>) pub fn get_stability(cdata: Cmd, id: DefIndex) -> Option { let item = cdata.lookup_item(id); reader::maybe_get_doc(item, tag_items_data_item_stability).map(|doc| { - Decodable::decode(&mut doc.decoder()).unwrap() + doc.decoder().decode() }) } pub fn get_deprecation(cdata: Cmd, id: DefIndex) -> Option { let item = cdata.lookup_item(id); reader::maybe_get_doc(item, tag_items_data_item_deprecation).map(|doc| { - Decodable::decode(&mut doc.decoder()).unwrap() + doc.decoder().decode() }) } @@ -802,26 +653,21 @@ pub fn get_visibility(cdata: Cmd, id: DefIndex) -> ty::Visibility { pub fn get_parent_impl(cdata: Cmd, id: DefIndex) -> Option { let item = cdata.lookup_item(id); reader::maybe_get_doc(item, tag_items_data_parent_impl).map(|doc| { - translated_def_id(cdata, doc) + let mut dcx = doc.decoder(); + dcx.cdata = Some(cdata); + dcx.decode() }) } pub fn get_repr_attrs(cdata: Cmd, id: DefIndex) -> Vec { let item = cdata.lookup_item(id); reader::maybe_get_doc(item, tag_items_data_item_repr).map_or(vec![], |doc| { - Decodable::decode(&mut doc.decoder()).unwrap() + doc.decoder().decode() }) } -pub fn get_impl_polarity(cdata: Cmd, id: DefIndex) -> Option { - let item_doc = cdata.lookup_item(id); - let fam = item_family(item_doc); - match fam { - Family::Impl => { - Some(parse_polarity(item_doc)) - } - _ => None - } +pub fn get_impl_polarity(cdata: Cmd, id: DefIndex) -> hir::ImplPolarity { + cdata.lookup_item(id).get(tag_polarity).decoder().decode() } pub fn get_custom_coerce_unsized_kind( @@ -831,7 +677,7 @@ pub fn get_custom_coerce_unsized_kind( { let item_doc = cdata.lookup_item(id); reader::maybe_get_doc(item_doc, tag_impl_coerce_unsized_kind).map(|kind_doc| { - Decodable::decode(&mut kind_doc.decoder()).unwrap() + kind_doc.decoder().decode() }) } @@ -841,44 +687,38 @@ pub fn get_impl_trait<'a, 'tcx>(cdata: Cmd, -> Option> { let item_doc = cdata.lookup_item(id); - let fam = item_family(item_doc); - match fam { - Family::Impl | Family::DefaultImpl => { - reader::maybe_get_doc(item_doc, tag_item_trait_ref).map(|tp| { - doc_trait_ref(tp, tcx, cdata) - }) - } - _ => None - } -} - -/// Iterates over the language items in the given crate. -pub fn each_lang_item(cdata: Cmd, mut f: F) -> bool where - F: FnMut(DefIndex, usize) -> bool, -{ - let root = rbml::Doc::new(cdata.data()); - let lang_items = reader::get_doc(root, tag_lang_items); - reader::tagged_docs(lang_items, tag_lang_items_item).all(|item_doc| { - let id_doc = reader::get_doc(item_doc, tag_lang_items_item_id); - let id = reader::doc_as_u32(id_doc) as usize; - let index_doc = reader::get_doc(item_doc, tag_lang_items_item_index); - let index = DefIndex::from_u32(reader::doc_as_u32(index_doc)); - - f(index, id) + reader::maybe_get_doc(item_doc, tag_item_trait_ref).map(|tp| { + doc_trait_ref(tp, tcx, cdata) }) } -fn each_child_of_item_or_crate(cdata: Cmd, - item_doc: rbml::Doc, - mut get_crate_data: G, - mut callback: F) where - F: FnMut(DefLike, ast::Name, ty::Visibility), - G: FnMut(CrateNum) -> Rc, -{ - // Iterate over all children. - for child_info_doc in reader::tagged_docs(item_doc, tag_mod_child) { - let child_def_id = translated_def_id(cdata, child_info_doc); +/// Iterates over the language items in the given crate. +pub fn get_lang_items(cdata: Cmd) -> Vec<(DefIndex, usize)> { + rbml::Doc::new(cdata.data()).get(tag_lang_items).decoder().decode() +} + +/// Iterates over each child of the given item. +pub fn each_child_of_item(cdata: Cmd, id: DefIndex, + mut get_crate_data: G, + mut callback: F) + where F: FnMut(Def, ast::Name, ty::Visibility), + G: FnMut(CrateNum) -> Rc, +{ + // Find the item. + let item_doc = match cdata.get_item(id) { + None => return, + Some(item_doc) => item_doc, + }; + + let mut dcx = match reader::maybe_get_doc(item_doc, tag_mod_children) { + Some(doc) => doc.decoder(), + None => return + }; + dcx.cdata = Some(cdata); + + // Iterate over all children. + for child_def_id in dcx.seq_mut::() { // This item may be in yet another crate if it was the child of a // reexport. let crate_data = if child_def_id.krate == cdata.cnum { @@ -894,27 +734,20 @@ fn each_child_of_item_or_crate(cdata: Cmd, // Get the item. if let Some(child_item_doc) = crate_data.get_item(child_def_id.index) { // Hand off the item to the callback. - let child_name = item_name(child_item_doc); - let def_like = item_to_def_like(crate_data, child_item_doc, child_def_id); - let visibility = item_visibility(child_item_doc); - callback(def_like, child_name, visibility); + if let Some(def) = item_to_def(crate_data, child_item_doc, child_def_id) { + let child_name = item_name(child_item_doc); + let visibility = item_visibility(child_item_doc); + callback(def, child_name, visibility); + } } } - for reexport_doc in reexports(item_doc) { - let def_id_doc = reader::get_doc(reexport_doc, - tag_items_data_item_reexport_def_id); - let child_def_id = translated_def_id(cdata, def_id_doc); - - let name_doc = reader::get_doc(reexport_doc, - tag_items_data_item_reexport_name); - let name = name_doc.as_str(); - + for exp in dcx.seq_mut::() { // This reexport may be in yet another crate. - let crate_data = if child_def_id.krate == cdata.cnum { + let crate_data = if exp.def_id.krate == cdata.cnum { None } else { - Some(get_crate_data(child_def_id.krate)) + Some(get_crate_data(exp.def_id.krate)) }; let crate_data = match crate_data { Some(ref cdata) => &**cdata, @@ -922,38 +755,17 @@ fn each_child_of_item_or_crate(cdata: Cmd, }; // Get the item. - if let Some(child_item_doc) = crate_data.get_item(child_def_id.index) { + if let Some(child_item_doc) = crate_data.get_item(exp.def_id.index) { // Hand off the item to the callback. - let def_like = item_to_def_like(crate_data, child_item_doc, child_def_id); - // These items have a public visibility because they're part of - // a public re-export. - callback(def_like, token::intern(name), ty::Visibility::Public); + if let Some(def) = item_to_def(crate_data, child_item_doc, exp.def_id) { + // These items have a public visibility because they're part of + // a public re-export. + callback(def, exp.name, ty::Visibility::Public); + } } } } -/// Iterates over each child of the given item. -pub fn each_child_of_item(cdata: Cmd, id: DefIndex, get_crate_data: G, callback: F) - where F: FnMut(DefLike, ast::Name, ty::Visibility), - G: FnMut(CrateNum) -> Rc, -{ - // Find the item. - let item_doc = match cdata.get_item(id) { - None => return, - Some(item_doc) => item_doc, - }; - - each_child_of_item_or_crate(cdata, item_doc, get_crate_data, callback) -} - -/// Iterates over all the top-level crate items. -pub fn each_top_level_item_of_crate(cdata: Cmd, get_crate_data: G, callback: F) - where F: FnMut(DefLike, ast::Name, ty::Visibility), - G: FnMut(CrateNum) -> Rc, -{ - each_child_of_item(cdata, CRATE_DEF_INDEX, get_crate_data, callback) -} - pub fn get_item_name(cdata: Cmd, id: DefIndex) -> ast::Name { item_name(cdata.lookup_item(id)) } @@ -1030,48 +842,31 @@ pub fn maybe_get_item_mir<'a, 'tcx>(cdata: Cmd, let mut dcx = mir_doc.decoder(); dcx.tcx = Some(tcx); dcx.cdata = Some(cdata); - Decodable::decode(&mut dcx).unwrap() + dcx.decode() }) } -fn get_explicit_self<'a, 'tcx>(item: rbml::Doc, tcx: TyCtxt<'a, 'tcx, 'tcx>) +fn get_explicit_self<'a, 'tcx>(cdata: Cmd, item: rbml::Doc, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> ty::ExplicitSelfCategory<'tcx> { - fn get_mutability(ch: u8) -> hir::Mutability { - match ch as char { - 'i' => hir::MutImmutable, - 'm' => hir::MutMutable, - _ => bug!("unknown mutability character: `{}`", ch as char), - } - } + let mut dcx = item.get(tag_item_trait_method_explicit_self).decoder(); + dcx.cdata = Some(cdata); + dcx.tcx = Some(tcx); - let explicit_self_doc = reader::get_doc(item, tag_item_trait_method_explicit_self); - let string = explicit_self_doc.as_str(); - - let explicit_self_kind = string.as_bytes()[0]; - match explicit_self_kind as char { - 's' => ty::ExplicitSelfCategory::Static, - 'v' => ty::ExplicitSelfCategory::ByValue, - '~' => ty::ExplicitSelfCategory::ByBox, - // FIXME(#4846) expl. region - '&' => { - ty::ExplicitSelfCategory::ByReference( - tcx.mk_region(ty::ReEmpty), - get_mutability(string.as_bytes()[1])) - } - _ => bug!("unknown self type code: `{}`", explicit_self_kind as char) - } + dcx.decode() } /// Returns the def IDs of all the items in the given implementation. -pub fn get_impl_items(cdata: Cmd, impl_id: DefIndex) - -> Vec { - reader::tagged_docs(cdata.lookup_item(impl_id), tag_item_impl_item).map(|doc| { - let def_id = item_def_id(doc, cdata); - match item_sort(doc) { - Some('C') | Some('c') => ty::ConstTraitItemId(def_id), - Some('r') | Some('p') => ty::MethodTraitItemId(def_id), - Some('t') => ty::TypeTraitItemId(def_id), - _ => bug!("unknown impl item sort"), +pub fn get_impl_or_trait_items(cdata: Cmd, impl_id: DefIndex) + -> Vec { + let item = cdata.lookup_item(impl_id); + let mut dcx = item.get(tag_mod_children).decoder(); + dcx.cdata = Some(cdata); + dcx.seq().map(|def_id: DefId| { + match item_to_def(cdata, cdata.lookup_item(def_id.index), def_id) { + Some(Def::AssociatedConst(def_id)) => ty::ConstTraitItemId(def_id), + Some(Def::Method(def_id)) => ty::MethodTraitItemId(def_id), + Some(Def::AssociatedTy(_, def_id)) => ty::TypeTraitItemId(def_id), + def => bug!("get_impl_or_trait_items: invalid def {:?}", def) } }).collect() } @@ -1092,8 +887,7 @@ pub fn get_impl_or_trait_item<'a, 'tcx>(cdata: Cmd, id: DefIndex, tcx: TyCtxt<'a } else { return None; }; - let container_doc = cdata.lookup_item(container_id.index); - let container = match item_family(container_doc) { + let container = match item_family(cdata.lookup_item(container_id.index)) { Trait => TraitContainer(container_id), _ => ImplContainer(container_id), }; @@ -1102,8 +896,8 @@ pub fn get_impl_or_trait_item<'a, 'tcx>(cdata: Cmd, id: DefIndex, tcx: TyCtxt<'a let vis = item_visibility(item_doc); let defaultness = item_defaultness(item_doc); - Some(match item_sort(item_doc) { - sort @ Some('C') | sort @ Some('c') => { + Some(match item_family(item_doc) { + Family::AssociatedConst => { let ty = doc_type(item_doc, tcx, cdata); ty::ConstTraitItem(Rc::new(ty::AssociatedConst { name: name, @@ -1112,10 +906,10 @@ pub fn get_impl_or_trait_item<'a, 'tcx>(cdata: Cmd, id: DefIndex, tcx: TyCtxt<'a defaultness: defaultness, def_id: def_id, container: container, - has_value: sort == Some('C') + has_value: item_doc.get(tag_item_trait_item_has_body).decoder().decode(), })) } - Some('r') | Some('p') => { + Family::Method => { let generics = doc_generics(item_doc, tcx, cdata); let predicates = doc_predicates(item_doc, tcx, cdata, tag_item_predicates); let ity = tcx.lookup_item_type(def_id).ty; @@ -1125,19 +919,22 @@ pub fn get_impl_or_trait_item<'a, 'tcx>(cdata: Cmd, id: DefIndex, tcx: TyCtxt<'a "the type {:?} of the method {:?} is not a function?", ity, name) }; - let explicit_self = get_explicit_self(item_doc, tcx); + let explicit_self = get_explicit_self(cdata, item_doc, tcx); - ty::MethodTraitItem(Rc::new(ty::Method::new(name, - generics, - predicates, - fty, - explicit_self, - vis, - defaultness, - def_id, - container))) + ty::MethodTraitItem(Rc::new(ty::Method { + name: name, + generics: generics, + predicates: predicates, + fty: fty, + explicit_self: explicit_self, + vis: vis, + defaultness: defaultness, + has_body: item_doc.get(tag_item_trait_item_has_body).decoder().decode(), + def_id: def_id, + container: container, + })) } - Some('t') => { + Family::AssociatedType => { let ty = maybe_doc_type(item_doc, tcx, cdata); ty::TypeTraitItem(Rc::new(ty::AssociatedType { name: name, @@ -1152,84 +949,19 @@ pub fn get_impl_or_trait_item<'a, 'tcx>(cdata: Cmd, id: DefIndex, tcx: TyCtxt<'a }) } -pub fn get_trait_item_def_ids(cdata: Cmd, id: DefIndex) - -> Vec { - let item = cdata.lookup_item(id); - reader::tagged_docs(item, tag_item_trait_item).map(|mth| { - let def_id = item_def_id(mth, cdata); - match item_sort(mth) { - Some('C') | Some('c') => ty::ConstTraitItemId(def_id), - Some('r') | Some('p') => ty::MethodTraitItemId(def_id), - Some('t') => ty::TypeTraitItemId(def_id), - _ => bug!("unknown trait item sort"), - } - }).collect() -} - pub fn get_item_variances(cdata: Cmd, id: DefIndex) -> Vec { let item_doc = cdata.lookup_item(id); - let variance_doc = reader::get_doc(item_doc, tag_item_variances); - Decodable::decode(&mut variance_doc.decoder()).unwrap() -} - -pub fn get_provided_trait_methods<'a, 'tcx>(cdata: Cmd, - id: DefIndex, - tcx: TyCtxt<'a, 'tcx, 'tcx>) - -> Vec>> { - let item = cdata.lookup_item(id); - - reader::tagged_docs(item, tag_item_trait_item).filter_map(|mth_id| { - let did = item_def_id(mth_id, cdata); - let mth = cdata.lookup_item(did.index); - - if item_sort(mth) == Some('p') { - let trait_item = get_impl_or_trait_item(cdata, did.index, tcx); - if let Some(ty::MethodTraitItem(ref method)) = trait_item { - Some((*method).clone()) - } else { - None - } - } else { - None - } - }).collect() -} - -pub fn get_associated_consts<'a, 'tcx>(cdata: Cmd, id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>) - -> Vec>> { - let item = cdata.lookup_item(id); - - [tag_item_trait_item, tag_item_impl_item].iter().flat_map(|&tag| { - reader::tagged_docs(item, tag).filter_map(|ac_id| { - let did = item_def_id(ac_id, cdata); - let ac_doc = cdata.lookup_item(did.index); - - match item_sort(ac_doc) { - Some('C') | Some('c') => { - let trait_item = get_impl_or_trait_item(cdata, did.index, tcx); - if let Some(ty::ConstTraitItem(ref ac)) = trait_item { - Some((*ac).clone()) - } else { - None - } - } - _ => None - } - }) - }).collect() -} - -pub fn get_variant_kind(cdata: Cmd, node_id: DefIndex) -> Option -{ - let item = cdata.lookup_item(node_id); - family_to_variant_kind(item_family(item)) + item_doc.get(tag_item_variances).decoder().decode() } pub fn get_struct_ctor_def_id(cdata: Cmd, node_id: DefIndex) -> Option { let item = cdata.lookup_item(node_id); - reader::maybe_get_doc(item, tag_items_data_item_struct_ctor). - map(|ctor_doc| translated_def_id(cdata, ctor_doc)) + reader::maybe_get_doc(item, tag_items_data_item_struct_ctor).map(|ctor_doc| { + let mut dcx = ctor_doc.decoder(); + dcx.cdata = Some(cdata); + dcx.decode() + }) } /// If node_id is the constructor of a tuple struct, retrieve the NodeId of @@ -1239,8 +971,12 @@ pub fn get_tuple_struct_definition_if_ctor(cdata: Cmd, -> Option { let item = cdata.lookup_item(node_id); - reader::tagged_docs(item, tag_items_data_item_is_tuple_struct_ctor).next().map(|_| { - item_require_parent_item(cdata, item) + reader::maybe_get_doc(item, tag_items_data_item_is_tuple_struct_ctor).and_then(|doc| { + if doc.decoder().decode() { + Some(item_require_parent_item(cdata, item)) + } else { + None + } }) } @@ -1256,39 +992,18 @@ pub fn get_item_attrs(cdata: Cmd, get_attributes(item) } -pub fn get_struct_field_attrs(cdata: Cmd) -> FnvHashMap> { - let data = rbml::Doc::new(cdata.data()); - let fields = reader::get_doc(data, tag_struct_fields); - reader::tagged_docs(fields, tag_struct_field).map(|field| { - let def_id = translated_def_id(cdata, reader::get_doc(field, tag_def_id)); - let attrs = get_attributes(field); - (def_id, attrs) - }).collect() -} - -fn struct_field_family_to_visibility(family: Family) -> ty::Visibility { - match family { - PublicField => ty::Visibility::Public, - InheritedField => ty::Visibility::PrivateExternal, - _ => bug!() - } -} - pub fn get_struct_field_names(cdata: Cmd, id: DefIndex) -> Vec { - let item = cdata.lookup_item(id); - let mut index = 0; - reader::tagged_docs(item, tag_item_field).map(|an_item| { - item_name(an_item) - }).chain(reader::tagged_docs(item, tag_item_unnamed_field).map(|_| { - let name = token::with_ident_interner(|interner| interner.intern(index.to_string())); - index += 1; - name - })).collect() + let mut dcx = cdata.lookup_item(id).get(tag_item_fields).decoder(); + dcx.cdata = Some(cdata); + + dcx.seq().map(|did: DefId| { + item_name(cdata.lookup_item(did.index)) + }).collect() } fn get_attributes(md: rbml::Doc) -> Vec { reader::maybe_get_doc(md, tag_attributes).map_or(vec![], |attrs_doc| { - let mut attrs = Vec::::decode(&mut attrs_doc.decoder()).unwrap(); + let mut attrs = attrs_doc.decoder().decode::>(); // Need new unique IDs: old thread-local IDs won't map to new threads. for attr in attrs.iter_mut() { @@ -1299,22 +1014,6 @@ fn get_attributes(md: rbml::Doc) -> Vec { }) } -fn list_crate_attributes(md: rbml::Doc, hash: &Svh, - out: &mut io::Write) -> io::Result<()> { - write!(out, "=Crate Attributes ({})=\n", *hash)?; - - let r = get_attributes(md); - for attr in &r { - write!(out, "{}\n", pprust::attribute_to_string(attr))?; - } - - write!(out, "\n\n") -} - -pub fn get_crate_attributes(data: &[u8]) -> Vec { - get_attributes(rbml::Doc::new(data)) -} - #[derive(Clone)] pub struct CrateDep { pub cnum: CrateNum, @@ -1324,19 +1023,9 @@ pub struct CrateDep { } pub fn get_crate_deps(data: &[u8]) -> Vec { - let cratedoc = rbml::Doc::new(data); - let depsdoc = reader::get_doc(cratedoc, tag_crate_deps); + let dcx = rbml::Doc::new(data).get(tag_crate_deps).decoder(); - fn docstr(doc: rbml::Doc, tag_: usize) -> String { - let d = reader::get_doc(doc, tag_); - d.as_str().to_string() - } - - reader::tagged_docs(depsdoc, tag_crate_dep).enumerate().map(|(crate_num, depdoc)| { - let name = docstr(depdoc, tag_crate_dep_crate_name); - let hash = Svh::new(reader::doc_as_u64(reader::get_doc(depdoc, tag_crate_dep_hash))); - let doc = reader::get_doc(depdoc, tag_crate_dep_explicitly_linked); - let explicitly_linked = reader::doc_as_u8(doc) != 0; + dcx.seq().enumerate().map(|(crate_num, (name, hash, explicitly_linked))| { CrateDep { cnum: CrateNum::new(crate_num + 1), name: name, @@ -1358,63 +1047,39 @@ fn list_crate_deps(data: &[u8], out: &mut io::Write) -> io::Result<()> { pub fn maybe_get_crate_hash(data: &[u8]) -> Option { let cratedoc = rbml::Doc::new(data); reader::maybe_get_doc(cratedoc, tag_crate_hash).map(|doc| { - Svh::new(reader::doc_as_u64(doc)) + doc.decoder().decode() }) } pub fn get_crate_hash(data: &[u8]) -> Svh { - let cratedoc = rbml::Doc::new(data); - let hashdoc = reader::get_doc(cratedoc, tag_crate_hash); - Svh::new(reader::doc_as_u64(hashdoc)) + rbml::Doc::new(data).get(tag_crate_hash).decoder().decode() } -pub fn maybe_get_crate_name(data: &[u8]) -> Option<&str> { +pub fn maybe_get_crate_name(data: &[u8]) -> Option { let cratedoc = rbml::Doc::new(data); reader::maybe_get_doc(cratedoc, tag_crate_crate_name).map(|doc| { - doc.as_str() + doc.decoder().decode() }) } -pub fn get_crate_disambiguator<'a>(data: &'a [u8]) -> &'a str { - let crate_doc = rbml::Doc::new(data); - let disambiguator_doc = reader::get_doc(crate_doc, tag_crate_disambiguator); - let slice: &'a str = disambiguator_doc.as_str(); - slice +pub fn get_crate_disambiguator(data: &[u8]) -> String { + rbml::Doc::new(data).get(tag_crate_disambiguator).decoder().decode() } pub fn get_crate_triple(data: &[u8]) -> Option { let cratedoc = rbml::Doc::new(data); let triple_doc = reader::maybe_get_doc(cratedoc, tag_crate_triple); - triple_doc.map(|s| s.as_str().to_string()) + triple_doc.map(|s| s.decoder().decode()) } -pub fn get_crate_name(data: &[u8]) -> &str { +pub fn get_crate_name(data: &[u8]) -> String { maybe_get_crate_name(data).expect("no crate name in crate") } pub fn list_crate_metadata(bytes: &[u8], out: &mut io::Write) -> io::Result<()> { - let hash = get_crate_hash(bytes); - let md = rbml::Doc::new(bytes); - list_crate_attributes(md, &hash, out)?; list_crate_deps(bytes, out) } -// Translates a def_id from an external crate to a def_id for the current -// compilation environment. We use this when trying to load types from -// external crates - if those types further refer to types in other crates -// then we must translate the crate number from that encoded in the external -// crate to the correct local crate number. -pub fn translate_def_id(cdata: Cmd, did: DefId) -> DefId { - if did.is_local() { - return DefId { krate: cdata.cnum, index: did.index }; - } - - DefId { - krate: cdata.cnum_map.borrow()[did.krate], - index: did.index - } -} - // Translate a DefId from the current compilation environment to a DefId // for an external crate. fn reverse_translate_def_id(cdata: Cmd, did: DefId) -> Option { @@ -1433,32 +1098,41 @@ pub fn each_inherent_implementation_for_type(cdata: Cmd, where F: FnMut(DefId), { let item_doc = cdata.lookup_item(id); - for impl_doc in reader::tagged_docs(item_doc, tag_items_data_item_inherent_impl) { - if reader::maybe_get_doc(impl_doc, tag_item_trait_ref).is_none() { - callback(item_def_id(impl_doc, cdata)); - } + let mut dcx = item_doc.get(tag_items_data_item_inherent_impls).decoder(); + dcx.cdata = Some(cdata); + + for impl_def_id in dcx.seq() { + callback(impl_def_id); } } pub fn each_implementation_for_trait(cdata: Cmd, - def_id: DefId, + filter: Option, mut callback: F) where F: FnMut(DefId), { // Do a reverse lookup beforehand to avoid touching the crate_num // hash map in the loop below. - if let Some(crate_local_did) = reverse_translate_def_id(cdata, def_id) { - let def_id_u64 = def_to_u64(crate_local_did); + let filter = match filter.map(|def_id| reverse_translate_def_id(cdata, def_id)) { + Some(Some(def_id)) => Some(def_id), + Some(None) => return, + None => None + }; - let impls_doc = reader::get_doc(rbml::Doc::new(cdata.data()), tag_impls); - for trait_doc in reader::tagged_docs(impls_doc, tag_impls_trait) { - let trait_def_id = reader::get_doc(trait_doc, tag_def_id); - if reader::doc_as_u64(trait_def_id) != def_id_u64 { + // FIXME(eddyb) Make this O(1) instead of O(n). + for trait_doc in rbml::Doc::new(cdata.data()).get(tag_impls).children() { + let mut dcx = trait_doc.decoder(); + dcx.cdata = Some(cdata); + + let (krate, index) = dcx.decode(); + if let Some(local_did) = filter { + if (local_did.krate.as_u32(), local_did.index) != (krate, index) { continue; } - for impl_doc in reader::tagged_docs(trait_doc, tag_impls_trait_impl) { - callback(translated_def_id(cdata, impl_doc)); - } + } + + for impl_def_id in dcx.seq() { + callback(impl_def_id); } } } @@ -1479,33 +1153,20 @@ pub fn get_trait_of_item(cdata: Cmd, id: DefIndex) -> Option { pub fn get_native_libraries(cdata: Cmd) -> Vec<(cstore::NativeLibraryKind, String)> { - let libraries = reader::get_doc(rbml::Doc::new(cdata.data()), - tag_native_libraries); - reader::tagged_docs(libraries, tag_native_libraries_lib).map(|lib_doc| { - let kind_doc = reader::get_doc(lib_doc, tag_native_libraries_kind); - let name_doc = reader::get_doc(lib_doc, tag_native_libraries_name); - let kind: cstore::NativeLibraryKind = - cstore::NativeLibraryKind::from_u32(reader::doc_as_u32(kind_doc)).unwrap(); - let name = name_doc.as_str().to_string(); - (kind, name) - }).collect() + rbml::Doc::new(cdata.data()).get(tag_native_libraries).decoder().decode() } pub fn get_plugin_registrar_fn(data: &[u8]) -> Option { reader::maybe_get_doc(rbml::Doc::new(data), tag_plugin_registrar_fn) - .map(|doc| DefIndex::from_u32(reader::doc_as_u32(doc))) + .map(|doc| doc.decoder().decode()) } pub fn each_exported_macro(data: &[u8], mut f: F) where F: FnMut(ast::Name, Vec, Span, String) -> bool, { - let macros = reader::get_doc(rbml::Doc::new(data), tag_macro_defs); - for macro_doc in reader::tagged_docs(macros, tag_macro_def) { - let name = item_name(macro_doc); - let attrs = get_attributes(macro_doc); - let span = get_macro_span(macro_doc); - let body = reader::get_doc(macro_doc, tag_macro_def_body); - if !f(name, attrs, span, body.as_str().to_string()) { + let dcx = rbml::Doc::new(data).get(tag_macro_defs).decoder(); + for (name, attrs, span, body) in dcx.seq() { + if !f(name, attrs, span, body) { break; } } @@ -1513,86 +1174,52 @@ pub fn each_exported_macro(data: &[u8], mut f: F) where pub fn get_derive_registrar_fn(data: &[u8]) -> Option { reader::maybe_get_doc(rbml::Doc::new(data), tag_macro_derive_registrar) - .map(|doc| DefIndex::from_u32(reader::doc_as_u32(doc))) -} - -pub fn get_macro_span(doc: rbml::Doc) -> Span { - let lo_doc = reader::get_doc(doc, tag_macro_def_span_lo); - let lo = BytePos(reader::doc_as_u32(lo_doc)); - let hi_doc = reader::get_doc(doc, tag_macro_def_span_hi); - let hi = BytePos(reader::doc_as_u32(hi_doc)); - return Span { lo: lo, hi: hi, expn_id: NO_EXPANSION }; + .map(|doc| doc.decoder().decode()) } pub fn get_dylib_dependency_formats(cdata: Cmd) -> Vec<(CrateNum, LinkagePreference)> { - let formats = reader::get_doc(rbml::Doc::new(cdata.data()), - tag_dylib_dependency_formats); - let mut result = Vec::new(); + let dcx = rbml::Doc::new(cdata.data()).get(tag_dylib_dependency_formats).decoder(); - debug!("found dylib deps: {}", formats.as_str()); - for spec in formats.as_str().split(',') { - if spec.is_empty() { continue } - let mut split = spec.split(':'); - let cnum = split.next().unwrap(); - let link = split.next().unwrap(); - let cnum = CrateNum::new(cnum.parse().unwrap()); - let cnum = cdata.cnum_map.borrow()[cnum]; - result.push((cnum, if link == "d" { - LinkagePreference::RequireDynamic - } else { - LinkagePreference::RequireStatic - })); - } - return result; + dcx.seq::>().enumerate().flat_map(|(i, link)| { + let cnum = CrateNum::new(i + 1); + link.map(|link| (cdata.cnum_map.borrow()[cnum], link)) + }).collect() } -pub fn get_missing_lang_items(cdata: Cmd) - -> Vec -{ - let items = reader::get_doc(rbml::Doc::new(cdata.data()), tag_lang_items); - reader::tagged_docs(items, tag_lang_items_missing).map(|missing_docs| { - lang_items::LangItem::from_u32(reader::doc_as_u32(missing_docs)).unwrap() - }).collect() +pub fn get_missing_lang_items(cdata: Cmd) -> Vec { + rbml::Doc::new(cdata.data()).get(tag_lang_items_missing).decoder().decode() } pub fn get_method_arg_names(cdata: Cmd, id: DefIndex) -> Vec { let method_doc = cdata.lookup_item(id); match reader::maybe_get_doc(method_doc, tag_method_argument_names) { - Some(args_doc) => { - reader::tagged_docs(args_doc, tag_method_argument_name).map(|name_doc| { - name_doc.as_str().to_string() - }).collect() - }, + Some(args_doc) => args_doc.decoder().decode(), None => vec![], } } pub fn get_reachable_ids(cdata: Cmd) -> Vec { - let items = reader::get_doc(rbml::Doc::new(cdata.data()), - tag_reachable_ids); - reader::tagged_docs(items, tag_reachable_id).map(|doc| { + let dcx = rbml::Doc::new(cdata.data()).get(tag_reachable_ids).decoder(); + + dcx.seq().map(|index| { DefId { krate: cdata.cnum, - index: DefIndex::from_u32(reader::doc_as_u32(doc)), + index: index, } }).collect() } -pub fn is_typedef(cdata: Cmd, id: DefIndex) -> bool { - let item_doc = cdata.lookup_item(id); - match item_family(item_doc) { - Type => true, - _ => false, - } -} - pub fn is_const_fn(cdata: Cmd, id: DefIndex) -> bool { - let item_doc = cdata.lookup_item(id); - match fn_constness(item_doc) { - hir::Constness::Const => true, - hir::Constness::NotConst => false, + match reader::maybe_get_doc(cdata.lookup_item(id), tag_items_data_item_constness) { + None => false, + Some(doc) => { + match doc.decoder().decode() { + hir::Constness::Const => true, + hir::Constness::NotConst => false, + } + } } } @@ -1628,40 +1255,15 @@ pub fn is_foreign_item(cdata: Cmd, id: DefIndex) -> bool { item_family(parent_item_doc) == ForeignMod } -pub fn is_impl(cdata: Cmd, id: DefIndex) -> bool { - let item_doc = cdata.lookup_item(id); - match item_family(item_doc) { - Impl => true, - _ => false, - } -} - fn doc_generics<'a, 'tcx>(base_doc: rbml::Doc, tcx: TyCtxt<'a, 'tcx, 'tcx>, cdata: Cmd) -> &'tcx ty::Generics<'tcx> { - let mut dcx = reader::get_doc(base_doc, tag_item_generics).decoder(); + let mut dcx = base_doc.get(tag_item_generics).decoder(); dcx.tcx = Some(tcx); dcx.cdata = Some(cdata); - tcx.alloc_generics(Decodable::decode(&mut dcx).unwrap()) -} - -fn doc_predicate<'a, 'tcx>(cdata: Cmd, - doc: rbml::Doc, - tcx: TyCtxt<'a, 'tcx, 'tcx>) - -> ty::Predicate<'tcx> -{ - let predicate_pos = cdata.xref_index.lookup( - cdata.data(), reader::doc_as_u32(doc)).unwrap() as usize; - let mut dcx = rbml::Doc { - data: cdata.data(), - start: predicate_pos, - end: cdata.data().len(), - }.decoder(); - dcx.tcx = Some(tcx); - dcx.cdata = Some(cdata); - Decodable::decode(&mut dcx).unwrap() + tcx.alloc_generics(dcx.decode()) } fn doc_predicates<'a, 'tcx>(base_doc: rbml::Doc, @@ -1670,51 +1272,50 @@ fn doc_predicates<'a, 'tcx>(base_doc: rbml::Doc, tag: usize) -> ty::GenericPredicates<'tcx> { - let doc = reader::get_doc(base_doc, tag); + let mut dcx = base_doc.get(tag).decoder(); + dcx.cdata = Some(cdata); ty::GenericPredicates { - parent: item_parent_item(cdata, doc), - predicates: reader::tagged_docs(doc, tag_predicate).map(|predicate_doc| { - doc_predicate(cdata, predicate_doc, tcx) + parent: dcx.decode(), + predicates: dcx.seq().map(|offset| { + let predicate_pos = cdata.xref_index.lookup( + cdata.data(), offset).unwrap() as usize; + let mut dcx = rbml::Doc { + data: cdata.data(), + start: predicate_pos, + end: cdata.data().len(), + }.decoder(); + dcx.tcx = Some(tcx); + dcx.cdata = Some(cdata); + dcx.decode() }).collect() } } pub fn is_defaulted_trait(cdata: Cmd, trait_id: DefIndex) -> bool { - let trait_doc = cdata.lookup_item(trait_id); - assert!(item_family(trait_doc) == Family::Trait); - let defaulted_doc = reader::get_doc(trait_doc, tag_defaulted_trait); - reader::doc_as_u8(defaulted_doc) != 0 + cdata.lookup_item(trait_id).get(tag_defaulted_trait).decoder().decode() } pub fn is_default_impl(cdata: Cmd, impl_id: DefIndex) -> bool { - let impl_doc = cdata.lookup_item(impl_id); - item_family(impl_doc) == Family::DefaultImpl + item_family(cdata.lookup_item(impl_id)) == Family::DefaultImpl } pub fn get_imported_filemaps(metadata: &[u8]) -> Vec { - let crate_doc = rbml::Doc::new(metadata); - let cm_doc = reader::get_doc(crate_doc, tag_codemap); - - reader::tagged_docs(cm_doc, tag_codemap_filemap).map(|filemap_doc| { - Decodable::decode(&mut filemap_doc.decoder()).unwrap() - }).collect() + rbml::Doc::new(metadata).get(tag_codemap).decoder().decode() } pub fn closure_kind(cdata: Cmd, closure_id: DefIndex) -> ty::ClosureKind { - let closure_doc = cdata.lookup_item(closure_id); - let closure_kind_doc = reader::get_doc(closure_doc, tag_items_closure_kind); - ty::ClosureKind::decode(&mut closure_kind_doc.decoder()).unwrap() + cdata.lookup_item(closure_id).get(tag_items_closure_kind).decoder().decode() } pub fn closure_ty<'a, 'tcx>(cdata: Cmd, closure_id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> ty::ClosureTy<'tcx> { let closure_doc = cdata.lookup_item(closure_id); - let closure_ty_doc = reader::get_doc(closure_doc, tag_items_closure_ty); + let closure_ty_doc = closure_doc.get(tag_items_closure_ty); let mut dcx = closure_ty_doc.decoder(); dcx.tcx = Some(tcx); dcx.cdata = Some(cdata); - Decodable::decode(&mut dcx).unwrap() + dcx.decode() } pub fn def_key(cdata: Cmd, id: DefIndex) -> hir_map::DefKey { @@ -1726,10 +1327,8 @@ pub fn def_key(cdata: Cmd, id: DefIndex) -> hir_map::DefKey { fn item_def_key(item_doc: rbml::Doc) -> hir_map::DefKey { match reader::maybe_get_doc(item_doc, tag_def_key) { Some(def_key_doc) => { - let simple_key = def_key::DefKey::decode(&mut def_key_doc.decoder()).unwrap(); - let name = reader::maybe_get_doc(item_doc, tag_paths_data_name).map(|name| { - token::intern(name.as_str()).as_str() - }); + let simple_key = def_key_doc.decoder().decode(); + let name = maybe_item_name(item_doc).map(|name| name.as_str()); def_key::recover_def_key(simple_key, name) } None => { @@ -1753,11 +1352,5 @@ pub fn def_path(cdata: Cmd, id: DefIndex) -> Option { } pub fn get_panic_strategy(data: &[u8]) -> PanicStrategy { - let crate_doc = rbml::Doc::new(data); - let strat_doc = reader::get_doc(crate_doc, tag_panic_strategy); - match reader::doc_as_u8(strat_doc) { - b'U' => PanicStrategy::Unwind, - b'A' => PanicStrategy::Abort, - b => panic!("unknown panic strategy in metadata: {}", b), - } + rbml::Doc::new(data).get(tag_panic_strategy).decoder().decode() } diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index e414275f8b42..7b4a6972d221 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -20,7 +20,7 @@ use decoder; use def_key; use index::{self, IndexData}; -use middle::cstore::{InlinedItemRef, LinkMeta}; +use middle::cstore::{InlinedItemRef, LinkMeta, LinkagePreference}; use rustc::hir::def; use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId}; use middle::dependency_format::Linkage; @@ -28,24 +28,22 @@ use rustc::dep_graph::DepNode; use rustc::traits::specialization_graph; use rustc::ty::{self, Ty, TyCtxt}; -use rustc::hir::svh::Svh; use rustc::mir::mir_map::MirMap; -use rustc::session::config::{self, PanicStrategy, CrateTypeRustcMacro}; +use rustc::session::config::{self, CrateTypeRustcMacro}; use rustc::util::nodemap::{FnvHashMap, NodeSet}; use rustc_serialize::{Encodable, Encoder, SpecializedEncoder, opaque}; -use rustc_serialize as serialize; use std::cell::RefCell; use std::intrinsics; use std::io::prelude::*; use std::io::Cursor; +use std::mem; use std::ops::{Deref, DerefMut}; use std::rc::Rc; use std::u32; use syntax::ast::{self, NodeId, Name, CRATE_NODE_ID}; use syntax::attr; use syntax; -use syntax_pos::BytePos; use rbml; use rustc::hir::{self, PatKind}; @@ -53,7 +51,7 @@ use rustc::hir::intravisit::Visitor; use rustc::hir::intravisit; use rustc::hir::map::DefKey; -use super::index_builder::{FromId, IndexBuilder, ItemContentBuilder, Untracked, XRef}; +use super::index_builder::{FromId, IndexBuilder, Untracked}; pub struct EncodeContext<'a, 'tcx: 'a> { rbml_w: rbml::writer::Encoder<'a>, @@ -61,11 +59,17 @@ pub struct EncodeContext<'a, 'tcx: 'a> { reexports: &'a def::ExportMap, link_meta: &'a LinkMeta, cstore: &'a cstore::CStore, - type_shorthands: RefCell, usize>>, reachable: &'a NodeSet, mir_map: &'a MirMap<'tcx>, + + type_shorthands: RefCell, usize>>, + xrefs: FnvHashMap, u32>, // sequentially-assigned } +/// "interned" entries referenced by id +#[derive(PartialEq, Eq, Hash)] +enum XRef<'tcx> { Predicate(ty::Predicate<'tcx>) } + impl<'a, 'tcx> Deref for EncodeContext<'a, 'tcx> { type Target = rbml::writer::Encoder<'a>; fn deref(&self) -> &Self::Target { @@ -87,8 +91,8 @@ macro_rules! encoder_methods { } } -impl<'a, 'tcx> serialize::Encoder for ::encoder::EncodeContext<'a, 'tcx> { - type Error = as serialize::Encoder>::Error; +impl<'a, 'tcx> Encoder for EncodeContext<'a, 'tcx> { + type Error = as Encoder>::Error; fn emit_nil(&mut self) -> Result<(), Self::Error> { Ok(()) @@ -146,12 +150,35 @@ impl<'a, 'tcx> SpecializedEncoder> for EncodeContext<'a, 'tcx> { } } -fn encode_name(ecx: &mut EncodeContext, name: Name) { - ecx.wr_tagged_str(tag_paths_data_name, &name.as_str()); +impl<'a, 'tcx> EncodeContext<'a, 'tcx> { + fn seq(&mut self, iter: I, mut f: F) + where I: IntoIterator, + I::IntoIter: ExactSizeIterator, + F: FnMut(&mut Self, I::Item) -> T, + T: Encodable { + let iter = iter.into_iter(); + self.emit_seq(iter.len(), move |ecx| { + for (i, elem) in iter.enumerate() { + ecx.emit_seq_elt(i, |ecx| { + f(ecx, elem).encode(ecx) + })?; + } + Ok(()) + }).unwrap(); + } } -fn encode_def_id(ecx: &mut EncodeContext, id: DefId) { - ecx.wr_tagged_u64(tag_def_id, def_to_u64(id)); +fn encode_name(ecx: &mut EncodeContext, name: Name) { + ecx.start_tag(tag_paths_data_name); + name.encode(ecx).unwrap(); + ecx.end_tag(); +} + +fn encode_def_id(ecx: &mut EncodeContext, def_id: DefId) { + assert!(def_id.is_local()); + ecx.start_tag(tag_def_index); + def_id.index.encode(ecx).unwrap(); + ecx.end_tag(); } fn encode_def_key(ecx: &mut EncodeContext, key: DefKey) { @@ -178,16 +205,10 @@ fn encode_trait_ref<'a, 'tcx>(ecx: &mut EncodeContext<'a, 'tcx>, } // Item info table encoding -fn encode_family(ecx: &mut EncodeContext, c: char) { - ecx.wr_tagged_u8(tag_items_data_item_family, c as u8); -} - -pub fn def_to_u64(did: DefId) -> u64 { - (did.krate.as_u32() as u64) << 32 | (did.index.as_u32() as u64) -} - -pub fn def_to_string(_tcx: TyCtxt, did: DefId) -> String { - format!("{}:{}", did.krate, did.index.as_usize()) +fn encode_family(ecx: &mut EncodeContext, f: Family) { + ecx.start_tag(tag_items_data_item_family); + f.encode(ecx).unwrap(); + ecx.end_tag(); } fn encode_item_variances(ecx: &mut EncodeContext, id: NodeId) { @@ -197,7 +218,7 @@ fn encode_item_variances(ecx: &mut EncodeContext, id: NodeId) { ecx.end_tag(); } -impl<'a, 'b, 'tcx> ItemContentBuilder<'a, 'b, 'tcx> { +impl<'a, 'tcx> EncodeContext<'a, 'tcx> { fn encode_bounds_and_type_for_item(&mut self, def_id: DefId) { let tcx = self.tcx; self.encode_bounds_and_type(&tcx.lookup_item_type(def_id), @@ -210,44 +231,31 @@ impl<'a, 'b, 'tcx> ItemContentBuilder<'a, 'b, 'tcx> { self.encode_generics(&scheme.generics, &predicates); self.encode_type(scheme.ty); } -} -fn encode_variant_id(ecx: &mut EncodeContext, vid: DefId) { - let id = def_to_u64(vid); - ecx.wr_tagged_u64(tag_items_data_item_variant, id); - ecx.wr_tagged_u64(tag_mod_child, id); -} - -impl<'a, 'b, 'tcx> ItemContentBuilder<'a, 'b, 'tcx> { fn encode_type(&mut self, typ: Ty<'tcx>) { self.start_tag(tag_items_data_item_type); - typ.encode(self.ecx).unwrap(); + typ.encode(self).unwrap(); self.end_tag(); } fn encode_disr_val(&mut self, disr_val: ty::Disr) { - // convert to u64 so just the number is printed, without any type info - self.wr_tagged_str(tag_disr_val, &disr_val.to_u64_unchecked().to_string()); + self.start_tag(tag_disr_val); + disr_val.to_u64_unchecked().encode(self).unwrap(); + self.end_tag(); } fn encode_parent_item(&mut self, id: DefId) { - self.wr_tagged_u64(tag_items_data_parent_item, def_to_u64(id)); + self.start_tag(tag_items_data_parent_item); + id.encode(self).unwrap(); + self.end_tag(); } - fn encode_struct_fields(&mut self, - variant: ty::VariantDef) { - for f in &variant.fields { - if variant.kind == ty::VariantKind::Tuple { - self.start_tag(tag_item_unnamed_field); - } else { - self.start_tag(tag_item_field); - encode_name(self, f.name); - } - self.encode_struct_field_family(f.vis); - encode_def_id(self, f.did); - self.end_tag(); - } + fn encode_variant_fields(&mut self, + variant: ty::VariantDef) { + self.start_tag(tag_item_fields); + self.seq(&variant.fields, |_, f| f.did); + self.end_tag(); } } @@ -258,13 +266,13 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { self.encode_fields(enum_did); for (i, variant) in def.variants.iter().enumerate() { self.record(variant.did, - ItemContentBuilder::encode_enum_variant_info, + EncodeContext::encode_enum_variant_info, (enum_did, Untracked(i))); } } } -impl<'a, 'b, 'tcx> ItemContentBuilder<'a, 'b, 'tcx> { +impl<'a, 'tcx> EncodeContext<'a, 'tcx> { /// Encode data for the given variant of the given ADT. The /// index of the variant is untracked: this is ok because we /// will have to lookup the adt-def by its id, and that gives us @@ -278,11 +286,7 @@ impl<'a, 'b, 'tcx> ItemContentBuilder<'a, 'b, 'tcx> { let variant = &def.variants[index]; let vid = variant.did; encode_def_id_and_key(self, vid); - encode_family(self, match variant.kind { - ty::VariantKind::Struct => 'V', - ty::VariantKind::Tuple => 'v', - ty::VariantKind::Unit => 'w', - }); + encode_family(self, Family::Variant(variant.kind)); encode_name(self, variant.name); self.encode_parent_item(enum_did); @@ -299,51 +303,35 @@ impl<'a, 'b, 'tcx> ItemContentBuilder<'a, 'b, 'tcx> { encode_stability(self, stab); encode_deprecation(self, depr); - self.encode_struct_fields(variant); + self.encode_variant_fields(variant); self.encode_disr_val(variant.disr_val); self.encode_bounds_and_type_for_item(vid); } } -fn encode_reexports(ecx: &mut EncodeContext, id: NodeId) { - debug!("(encoding info for module) encoding reexports for {}", id); - match ecx.reexports.get(&id) { - Some(exports) => { - debug!("(encoding info for module) found reexports for {}", id); - for exp in exports { - debug!("(encoding info for module) reexport '{}' ({:?}) for \ - {}", - exp.name, - exp.def_id, - id); - ecx.start_tag(tag_items_data_item_reexport); - ecx.wr_tagged_u64(tag_items_data_item_reexport_def_id, - def_to_u64(exp.def_id)); - ecx.wr_tagged_str(tag_items_data_item_reexport_name, - &exp.name.as_str()); - ecx.end_tag(); - } - }, - None => debug!("(encoding info for module) found no reexports for {}", id), - } -} - -impl<'a, 'b, 'tcx> ItemContentBuilder<'a, 'b, 'tcx> { +impl<'a, 'tcx> EncodeContext<'a, 'tcx> { fn encode_info_for_mod(&mut self, FromId(id, (md, attrs, name, vis)): FromId<(&hir::Mod, &[ast::Attribute], Name, &hir::Visibility)>) { let tcx = self.tcx; encode_def_id_and_key(self, tcx.map.local_def_id(id)); - encode_family(self, 'm'); + encode_family(self, Family::Mod); encode_name(self, name); debug!("(encoding info for module) encoding info for module ID {}", id); // Encode info about all the module children. - for item_id in &md.item_ids { - self.wr_tagged_u64(tag_mod_child, - def_to_u64(tcx.map.local_def_id(item_id.id))); + self.start_tag(tag_mod_children); + self.seq(&md.item_ids, |_, item_id| { + tcx.map.local_def_id(item_id.id) + }); + + // Encode the reexports of this module, if this module is public. + match self.reexports.get(&id) { + Some(exports) if *vis == hir::Public => exports.encode(self).unwrap(), + _ => <[def::Export]>::encode(&[], self).unwrap() } + self.end_tag(); self.encode_visibility(vis); @@ -352,22 +340,27 @@ impl<'a, 'b, 'tcx> ItemContentBuilder<'a, 'b, 'tcx> { encode_stability(self, stab); encode_deprecation(self, depr); - // Encode the reexports of this module, if this module is public. - if *vis == hir::Public { - debug!("(encoding info for module) encoding reexports for {}", id); - encode_reexports(self, id); - } encode_attributes(self, attrs); } fn encode_struct_field_family(&mut self, visibility: ty::Visibility) { - encode_family(self, if visibility.is_public() { 'g' } else { 'N' }); + encode_family(self, if visibility.is_public() { + Family::PublicField + } else { + Family::InheritedField + }); } fn encode_visibility(&mut self, visibility: T) { - let ch = if visibility.is_public() { 'y' } else { 'i' }; - self.wr_tagged_u8(tag_items_data_item_visibility, ch as u8); + let vis = if visibility.is_public() { + ty::Visibility::Public + } else { + ty::Visibility::PrivateExternal + }; + self.start_tag(tag_items_data_item_visibility); + vis.encode(self).unwrap(); + self.end_tag(); } } @@ -389,54 +382,14 @@ impl HasVisibility for ty::Visibility { fn encode_constness(ecx: &mut EncodeContext, constness: hir::Constness) { ecx.start_tag(tag_items_data_item_constness); - let ch = match constness { - hir::Constness::Const => 'c', - hir::Constness::NotConst => 'n', - }; - ecx.wr_str(&ch.to_string()); + constness.encode(ecx).unwrap(); ecx.end_tag(); } fn encode_defaultness(ecx: &mut EncodeContext, defaultness: hir::Defaultness) { - let ch = match defaultness { - hir::Defaultness::Default => 'd', - hir::Defaultness::Final => 'f', - }; - ecx.wr_tagged_u8(tag_items_data_item_defaultness, ch as u8); -} - -fn encode_explicit_self(ecx: &mut EncodeContext, - explicit_self: &ty::ExplicitSelfCategory) { - let tag = tag_item_trait_method_explicit_self; - - // Encode the base self type. - match *explicit_self { - ty::ExplicitSelfCategory::Static => { - ecx.wr_tagged_bytes(tag, &['s' as u8]); - } - ty::ExplicitSelfCategory::ByValue => { - ecx.wr_tagged_bytes(tag, &['v' as u8]); - } - ty::ExplicitSelfCategory::ByBox => { - ecx.wr_tagged_bytes(tag, &['~' as u8]); - } - ty::ExplicitSelfCategory::ByReference(_, m) => { - // FIXME(#4846) encode custom lifetime - let ch = encode_mutability(m); - ecx.wr_tagged_bytes(tag, &['&' as u8, ch]); - } - } - - fn encode_mutability(m: hir::Mutability) -> u8 { - match m { - hir::MutImmutable => 'i' as u8, - hir::MutMutable => 'm' as u8, - } - } -} - -fn encode_item_sort(ecx: &mut EncodeContext, sort: char) { - ecx.wr_tagged_u8(tag_item_trait_item_sort, sort as u8); + ecx.start_tag(tag_items_data_item_defaultness); + defaultness.encode(ecx).unwrap(); + ecx.end_tag(); } impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { @@ -446,14 +399,14 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { for (variant_index, variant) in def.variants.iter().enumerate() { for (field_index, field) in variant.fields.iter().enumerate() { self.record(field.did, - ItemContentBuilder::encode_field, + EncodeContext::encode_field, (adt_def_id, Untracked((variant_index, field_index)))); } } } } -impl<'a, 'b, 'tcx> ItemContentBuilder<'a, 'b, 'tcx> { +impl<'a, 'tcx> EncodeContext<'a, 'tcx> { /// Encode data for the given field of the given variant of the /// given ADT. The indices of the variant/field are untracked: /// this is ok because we will have to lookup the adt-def by its @@ -476,6 +429,10 @@ impl<'a, 'b, 'tcx> ItemContentBuilder<'a, 'b, 'tcx> { self.encode_bounds_and_type_for_item(field.did); encode_def_id_and_key(self, field.did); + let variant_id = tcx.map.as_local_node_id(variant.did).unwrap(); + let variant_data = tcx.map.expect_variant_data(variant_id); + encode_attributes(self, &variant_data.fields()[field_index].attrs); + let stab = tcx.lookup_stability(field.did); let depr = tcx.lookup_deprecation(field.did); encode_stability(self, stab); @@ -491,11 +448,7 @@ impl<'a, 'b, 'tcx> ItemContentBuilder<'a, 'b, 'tcx> { let item = tcx.map.expect_item(struct_node_id); let ctor_def_id = tcx.map.local_def_id(ctor_node_id); encode_def_id_and_key(self, ctor_def_id); - encode_family(self, match variant.kind { - ty::VariantKind::Struct => 'S', - ty::VariantKind::Tuple => 's', - ty::VariantKind::Unit => 'u', - }); + encode_family(self, Family::Struct(variant.kind)); self.encode_bounds_and_type_for_item(ctor_def_id); encode_name(self, item.name); self.encode_parent_item(struct_def_id); @@ -510,7 +463,9 @@ impl<'a, 'b, 'tcx> ItemContentBuilder<'a, 'b, 'tcx> { // definition, but without this there is no way for them // to tell that they actually have a ctor rather than a // normal function - self.wr_tagged_bytes(tag_items_data_item_is_tuple_struct_ctor, &[]); + self.start_tag(tag_items_data_item_is_tuple_struct_ctor); + true.encode(self).unwrap(); + self.end_tag(); } fn encode_generics(&mut self, @@ -518,7 +473,7 @@ impl<'a, 'b, 'tcx> ItemContentBuilder<'a, 'b, 'tcx> { predicates: &ty::GenericPredicates<'tcx>) { self.start_tag(tag_item_generics); - generics.encode(self.ecx).unwrap(); + generics.encode(self).unwrap(); self.end_tag(); self.encode_predicates(predicates, tag_item_predicates); } @@ -527,13 +482,10 @@ impl<'a, 'b, 'tcx> ItemContentBuilder<'a, 'b, 'tcx> { predicates: &ty::GenericPredicates<'tcx>, tag: usize) { self.start_tag(tag); - if let Some(def_id) = predicates.parent { - self.wr_tagged_u64(tag_items_data_parent_item, def_to_u64(def_id)); - } - for predicate in &predicates.predicates { - let xref = self.add_xref(XRef::Predicate(predicate.clone())); - self.wr_tagged_u32(tag_predicate, xref); - } + predicates.parent.encode(self).unwrap(); + self.seq(&predicates.predicates, |ecx, predicate| { + ecx.add_xref(XRef::Predicate(predicate.clone())) + }); self.end_tag(); } @@ -542,13 +494,12 @@ impl<'a, 'b, 'tcx> ItemContentBuilder<'a, 'b, 'tcx> { encode_name(self, method_ty.name); self.encode_generics(&method_ty.generics, &method_ty.predicates); self.encode_visibility(method_ty.vis); - encode_explicit_self(self, &method_ty.explicit_self); - match method_ty.explicit_self { - ty::ExplicitSelfCategory::Static => { - encode_family(self, STATIC_METHOD_FAMILY); - } - _ => encode_family(self, METHOD_FAMILY) - } + + self.start_tag(tag_item_trait_method_explicit_self); + method_ty.explicit_self.encode(self).unwrap(); + self.end_tag(); + + encode_family(self, Family::Method); } fn encode_info_for_trait_item(&mut self, @@ -563,79 +514,47 @@ impl<'a, 'b, 'tcx> ItemContentBuilder<'a, 'b, 'tcx> { encode_stability(self, stab); encode_deprecation(self, depr); - let trait_item_type = - tcx.impl_or_trait_item(item_def_id); - let is_nonstatic_method; - match trait_item_type { + match tcx.impl_or_trait_item(item_def_id) { ty::ConstTraitItem(associated_const) => { encode_name(self, associated_const.name); - encode_def_id_and_key(self, associated_const.def_id); + encode_def_id_and_key(self, item_def_id); self.encode_visibility(associated_const.vis); - encode_family(self, 'C'); - - self.encode_bounds_and_type_for_item(associated_const.def_id); - - is_nonstatic_method = false; + encode_family(self, Family::AssociatedConst); + self.encode_bounds_and_type_for_item(item_def_id); } ty::MethodTraitItem(method_ty) => { - let method_def_id = item_def_id; - self.encode_method_ty_fields(&method_ty); - - match method_ty.explicit_self { - ty::ExplicitSelfCategory::Static => { - encode_family(self, STATIC_METHOD_FAMILY); - } - _ => { - encode_family(self, METHOD_FAMILY); - } - } - self.encode_bounds_and_type_for_item(method_def_id); - - is_nonstatic_method = method_ty.explicit_self != - ty::ExplicitSelfCategory::Static; + self.encode_bounds_and_type_for_item(item_def_id); } ty::TypeTraitItem(associated_type) => { encode_name(self, associated_type.name); - encode_def_id_and_key(self, associated_type.def_id); - encode_item_sort(self, 't'); - encode_family(self, 'y'); + encode_def_id_and_key(self, item_def_id); + encode_family(self, Family::AssociatedType); if let Some(ty) = associated_type.ty { self.encode_type(ty); } - - is_nonstatic_method = false; } } encode_attributes(self, &trait_item.attrs); match trait_item.node { hir::ConstTraitItem(_, ref default) => { - if default.is_some() { - encode_item_sort(self, 'C'); - } else { - encode_item_sort(self, 'c'); - } + self.start_tag(tag_item_trait_item_has_body); + default.is_some().encode(self).unwrap(); + self.end_tag(); encode_inlined_item(self, InlinedItemRef::TraitItem(trait_def_id, trait_item)); self.encode_mir(item_def_id); } hir::MethodTraitItem(ref sig, ref body) => { - // If this is a static method, we've already - // encoded self. - if is_nonstatic_method { - self.encode_bounds_and_type_for_item(item_def_id); - } + self.start_tag(tag_item_trait_item_has_body); + body.is_some().encode(self).unwrap(); + self.end_tag(); - if body.is_some() { - encode_item_sort(self, 'p'); - self.encode_mir(item_def_id); - } else { - encode_item_sort(self, 'r'); - } + self.encode_mir(item_def_id); self.encode_method_argument_names(&sig.decl); } @@ -654,7 +573,6 @@ impl<'a, 'b, 'tcx> ItemContentBuilder<'a, 'b, 'tcx> { } ty::MethodTraitItem(ref method_type) => { self.encode_info_for_method(&method_type, - false, impl_id, ast_item) } @@ -678,10 +596,13 @@ impl<'a, 'b, 'tcx> ItemContentBuilder<'a, 'b, 'tcx> { encode_def_id_and_key(self, associated_const.def_id); encode_name(self, associated_const.name); self.encode_visibility(associated_const.vis); - encode_family(self, 'C'); + encode_family(self, Family::AssociatedConst); self.encode_parent_item(tcx.map.local_def_id(parent_id)); - encode_item_sort(self, 'C'); + + self.start_tag(tag_item_trait_item_has_body); + true.encode(self).unwrap(); + self.end_tag(); self.encode_bounds_and_type_for_item(associated_const.def_id); @@ -702,7 +623,6 @@ impl<'a, 'b, 'tcx> ItemContentBuilder<'a, 'b, 'tcx> { fn encode_info_for_method(&mut self, m: &ty::Method<'tcx>, - is_default_impl: bool, parent_id: NodeId, impl_item_opt: Option<&hir::ImplItem>) { let tcx = self.tcx; @@ -711,7 +631,10 @@ impl<'a, 'b, 'tcx> ItemContentBuilder<'a, 'b, 'tcx> { m.name); self.encode_method_ty_fields(m); self.encode_parent_item(tcx.map.local_def_id(parent_id)); - encode_item_sort(self, 'r'); + + self.start_tag(tag_item_trait_item_has_body); + true.encode(self).unwrap(); + self.end_tag(); let stab = tcx.lookup_stability(m.def_id); let depr = tcx.lookup_deprecation(m.def_id); @@ -725,8 +648,7 @@ impl<'a, 'b, 'tcx> ItemContentBuilder<'a, 'b, 'tcx> { encode_attributes(self, &impl_item.attrs); let generics = tcx.lookup_generics(m.def_id); let types = generics.parent_types as usize + generics.types.len(); - let needs_inline = types > 0 || is_default_impl || - attr::requests_inline(&impl_item.attrs); + let needs_inline = types > 0 || attr::requests_inline(&impl_item.attrs); if sig.constness == hir::Constness::Const { encode_inlined_item( self, @@ -755,9 +677,8 @@ impl<'a, 'b, 'tcx> ItemContentBuilder<'a, 'b, 'tcx> { encode_def_id_and_key(self, associated_type.def_id); encode_name(self, associated_type.name); self.encode_visibility(associated_type.vis); - encode_family(self, 'y'); + encode_family(self, Family::AssociatedType); self.encode_parent_item(tcx.map.local_def_id(parent_id)); - encode_item_sort(self, 't'); let stab = tcx.lookup_stability(associated_type.def_id); let depr = tcx.lookup_deprecation(associated_type.def_id); @@ -777,15 +698,15 @@ impl<'a, 'b, 'tcx> ItemContentBuilder<'a, 'b, 'tcx> { fn encode_method_argument_names(&mut self, decl: &hir::FnDecl) { self.start_tag(tag_method_argument_names); - for arg in &decl.inputs { - let tag = tag_method_argument_name; + + self.seq(&decl.inputs, |_, arg| { if let PatKind::Binding(_, ref path1, _) = arg.pat.node { - let name = path1.node.as_str(); - self.wr_tagged_bytes(tag, name.as_bytes()); + path1.node } else { - self.wr_tagged_bytes(tag, &[]); + syntax::parse::token::intern("") } - } + }); + self.end_tag(); } @@ -797,36 +718,28 @@ impl<'a, 'b, 'tcx> ItemContentBuilder<'a, 'b, 'tcx> { attr)); } self.start_tag(tag_items_data_item_repr); - repr_attrs.encode(self.ecx); + repr_attrs.encode(self); self.end_tag(); } fn encode_mir(&mut self, def_id: DefId) { if let Some(mir) = self.mir_map.map.get(&def_id) { self.start_tag(tag_mir as usize); - mir.encode(self.ecx); + mir.encode(self); self.end_tag(); } } } -const FN_FAMILY: char = 'f'; -const STATIC_METHOD_FAMILY: char = 'F'; -const METHOD_FAMILY: char = 'h'; - // Encodes the inherent implementations of a structure, enumeration, or trait. fn encode_inherent_implementations(ecx: &mut EncodeContext, def_id: DefId) { + ecx.start_tag(tag_items_data_item_inherent_impls); match ecx.tcx.inherent_impls.borrow().get(&def_id) { - None => {} - Some(implementations) => { - for &impl_def_id in implementations.iter() { - ecx.start_tag(tag_items_data_item_inherent_impl); - encode_def_id(ecx, impl_def_id); - ecx.end_tag(); - } - } + None => <[DefId]>::encode(&[], ecx).unwrap(), + Some(implementations) => implementations.encode(ecx).unwrap() } + ecx.end_tag(); } fn encode_stability(ecx: &mut EncodeContext, stab_opt: Option<&attr::Stability>) { @@ -845,37 +758,35 @@ fn encode_deprecation(ecx: &mut EncodeContext, depr_opt: Option) { - parent_opt.map(|parent| { - ecx.wr_tagged_u64(tag_items_data_parent_impl, def_to_u64(parent)); - }); -} - -fn encode_xrefs<'a, 'tcx>(ecx: &mut EncodeContext<'a, 'tcx>, - xrefs: FnvHashMap, u32>) -{ - let mut xref_positions = vec![0; xrefs.len()]; - - // Encode XRefs sorted by their ID - let mut sorted_xrefs: Vec<_> = xrefs.into_iter().collect(); - sorted_xrefs.sort_by_key(|&(_, id)| id); - - ecx.start_tag(tag_xref_data); - for (xref, id) in sorted_xrefs.into_iter() { - xref_positions[id as usize] = ecx.mark_stable_position() as u32; - match xref { - XRef::Predicate(p) => p.encode(ecx).unwrap() - } +impl<'a, 'tcx> EncodeContext<'a, 'tcx> { + fn add_xref(&mut self, xref: XRef<'tcx>) -> u32 { + let old_len = self.xrefs.len() as u32; + *self.xrefs.entry(xref).or_insert(old_len) } - ecx.mark_stable_position(); - ecx.end_tag(); - ecx.start_tag(tag_xref_index); - index::write_dense_index(xref_positions, &mut ecx.opaque.cursor); - ecx.end_tag(); -} + fn encode_xrefs(&mut self) { + let xrefs = mem::replace(&mut self.xrefs, Default::default()); + let mut xref_positions = vec![0; xrefs.len()]; + + // Encode XRefs sorted by their ID + let mut sorted_xrefs: Vec<_> = xrefs.into_iter().collect(); + sorted_xrefs.sort_by_key(|&(_, id)| id); + + self.start_tag(tag_xref_data); + for (xref, id) in sorted_xrefs.into_iter() { + xref_positions[id as usize] = self.mark_stable_position() as u32; + match xref { + XRef::Predicate(p) => p.encode(self).unwrap() + } + } + self.mark_stable_position(); + self.end_tag(); + + self.start_tag(tag_xref_index); + index::write_dense_index(xref_positions, &mut self.opaque.cursor); + self.end_tag(); + } -impl<'a, 'b, 'tcx> ItemContentBuilder<'a, 'b, 'tcx> { fn encode_info_for_item(&mut self, (def_id, item): (DefId, &hir::Item)) { let tcx = self.tcx; @@ -893,11 +804,11 @@ impl<'a, 'b, 'tcx> ItemContentBuilder<'a, 'b, 'tcx> { match item.node { hir::ItemStatic(_, m, _) => { encode_def_id_and_key(self, def_id); - if m == hir::MutMutable { - encode_family(self, 'b'); + encode_family(self, if m == hir::MutMutable { + Family::MutStatic } else { - encode_family(self, 'c'); - } + Family::ImmStatic + }); self.encode_bounds_and_type_for_item(def_id); encode_name(self, item.name); self.encode_visibility(vis); @@ -907,7 +818,7 @@ impl<'a, 'b, 'tcx> ItemContentBuilder<'a, 'b, 'tcx> { } hir::ItemConst(..) => { encode_def_id_and_key(self, def_id); - encode_family(self, 'C'); + encode_family(self, Family::Const); self.encode_bounds_and_type_for_item(def_id); encode_name(self, item.name); encode_attributes(self, &item.attrs); @@ -919,7 +830,7 @@ impl<'a, 'b, 'tcx> ItemContentBuilder<'a, 'b, 'tcx> { } hir::ItemFn(ref decl, _, constness, _, ref generics, _) => { encode_def_id_and_key(self, def_id); - encode_family(self, FN_FAMILY); + encode_family(self, Family::Fn); let tps_len = generics.ty_params.len(); self.encode_bounds_and_type_for_item(def_id); encode_name(self, item.name); @@ -942,22 +853,24 @@ impl<'a, 'b, 'tcx> ItemContentBuilder<'a, 'b, 'tcx> { } hir::ItemForeignMod(ref fm) => { encode_def_id_and_key(self, def_id); - encode_family(self, 'n'); + encode_family(self, Family::ForeignMod); encode_name(self, item.name); // Encode all the items in self module. - for foreign_item in &fm.items { - self.wr_tagged_u64( - tag_mod_child, - def_to_u64(tcx.map.local_def_id(foreign_item.id))); - } + self.start_tag(tag_mod_children); + self.seq(&fm.items, |_, foreign_item| { + tcx.map.local_def_id(foreign_item.id) + }); + <[def::Export]>::encode(&[], self).unwrap(); + self.end_tag(); + self.encode_visibility(vis); encode_stability(self, stab); encode_deprecation(self, depr); } hir::ItemTy(..) => { encode_def_id_and_key(self, def_id); - encode_family(self, 'y'); + encode_family(self, Family::Type); self.encode_bounds_and_type_for_item(def_id); encode_name(self, item.name); self.encode_visibility(vis); @@ -966,15 +879,19 @@ impl<'a, 'b, 'tcx> ItemContentBuilder<'a, 'b, 'tcx> { } hir::ItemEnum(ref enum_definition, _) => { encode_def_id_and_key(self, def_id); - encode_family(self, 't'); + encode_family(self, Family::Enum); encode_item_variances(self, item.id); self.encode_bounds_and_type_for_item(def_id); encode_name(self, item.name); encode_attributes(self, &item.attrs); self.encode_repr_attrs(&item.attrs); - for v in &enum_definition.variants { - encode_variant_id(self, tcx.map.local_def_id(v.node.data.id())); - } + + self.start_tag(tag_mod_children); + self.seq(&enum_definition.variants, |_, v| { + tcx.map.local_def_id(v.node.data.id()) + }); + <[def::Export]>::encode(&[], self).unwrap(); + self.end_tag(); // Encode inherent implementations for self enumeration. encode_inherent_implementations(self, def_id); @@ -990,11 +907,7 @@ impl<'a, 'b, 'tcx> ItemContentBuilder<'a, 'b, 'tcx> { /* Now, make an item for the class itself */ encode_def_id_and_key(self, def_id); - encode_family(self, match *struct_def { - hir::VariantData::Struct(..) => 'S', - hir::VariantData::Tuple(..) => 's', - hir::VariantData::Unit(..) => 'u', - }); + encode_family(self, Family::Struct(variant.kind)); self.encode_bounds_and_type_for_item(def_id); encode_item_variances(self, item.id); @@ -1008,15 +921,16 @@ impl<'a, 'b, 'tcx> ItemContentBuilder<'a, 'b, 'tcx> { /* Encode def_ids for each field and method for methods, write all the stuff get_trait_method needs to know*/ - self.encode_struct_fields(variant); + self.encode_variant_fields(variant); // Encode inherent implementations for self structure. encode_inherent_implementations(self, def_id); if !struct_def.is_struct() { let ctor_did = tcx.map.local_def_id(struct_def.id()); - self.wr_tagged_u64(tag_items_data_item_struct_ctor, - def_to_u64(ctor_did)); + self.start_tag(tag_items_data_item_struct_ctor); + ctor_did.encode(self).unwrap(); + self.end_tag(); } } hir::ItemUnion(..) => { @@ -1024,7 +938,7 @@ impl<'a, 'b, 'tcx> ItemContentBuilder<'a, 'b, 'tcx> { let variant = def.struct_variant(); encode_def_id_and_key(self, def_id); - encode_family(self, 'U'); + encode_family(self, Family::Union); self.encode_bounds_and_type_for_item(def_id); encode_item_variances(self, item.id); @@ -1038,7 +952,7 @@ impl<'a, 'b, 'tcx> ItemContentBuilder<'a, 'b, 'tcx> { /* Encode def_ids for each field and method for methods, write all the stuff get_trait_method needs to know*/ - self.encode_struct_fields(variant); + self.encode_variant_fields(variant); encode_inlined_item(self, InlinedItemRef::Item(def_id, item)); self.encode_mir(def_id); @@ -1046,28 +960,24 @@ impl<'a, 'b, 'tcx> ItemContentBuilder<'a, 'b, 'tcx> { // Encode inherent implementations for self union. encode_inherent_implementations(self, def_id); } - hir::ItemDefaultImpl(unsafety, _) => { + hir::ItemDefaultImpl(..) => { encode_def_id_and_key(self, def_id); - encode_family(self, 'd'); + encode_family(self, Family::DefaultImpl); encode_name(self, item.name); - encode_unsafety(self, unsafety); let trait_ref = tcx.impl_trait_ref(tcx.map.local_def_id(item.id)).unwrap(); encode_trait_ref(self, trait_ref, tag_item_trait_ref); } - hir::ItemImpl(unsafety, polarity, ..) => { - // We need to encode information about the default methods we - // have inherited, so we drive self based on the impl structure. - let impl_items = tcx.impl_items.borrow(); - let items = &impl_items[&def_id]; - + hir::ItemImpl(_, polarity, ..) => { encode_def_id_and_key(self, def_id); - encode_family(self, 'i'); + encode_family(self, Family::Impl); self.encode_bounds_and_type_for_item(def_id); encode_name(self, item.name); encode_attributes(self, &item.attrs); - encode_unsafety(self, unsafety); - encode_polarity(self, polarity); + + self.start_tag(tag_polarity); + polarity.encode(self).unwrap(); + self.end_tag(); match tcx.custom_coerce_unsized_kinds @@ -1076,30 +986,17 @@ impl<'a, 'b, 'tcx> ItemContentBuilder<'a, 'b, 'tcx> { { Some(&kind) => { self.start_tag(tag_impl_coerce_unsized_kind); - kind.encode(self.ecx); + kind.encode(self); self.end_tag(); } None => {} } - for &item_def_id in items { - self.start_tag(tag_item_impl_item); - match item_def_id { - ty::ConstTraitItemId(item_def_id) => { - encode_def_id(self, item_def_id); - encode_item_sort(self, 'C'); - } - ty::MethodTraitItemId(item_def_id) => { - encode_def_id(self, item_def_id); - encode_item_sort(self, 'r'); - } - ty::TypeTraitItemId(item_def_id) => { - encode_def_id(self, item_def_id); - encode_item_sort(self, 't'); - } - } - self.end_tag(); - } + self.start_tag(tag_mod_children); + let items = tcx.impl_or_trait_items(def_id); + self.seq(&items[..], |_, id| id.def_id()); + <[def::Export]>::encode(&[], self).unwrap(); + self.end_tag(); let did = tcx.map.local_def_id(item.id); if let Some(trait_ref) = tcx.impl_trait_ref(did) { @@ -1114,20 +1011,34 @@ impl<'a, 'b, 'tcx> ItemContentBuilder<'a, 'b, 'tcx> { Some(parent), _ => None, }); - encode_parent_impl(self, parent); + parent.map(|parent| { + self.start_tag(tag_items_data_parent_impl); + parent.encode(self).unwrap(); + self.end_tag(); + }); } encode_stability(self, stab); encode_deprecation(self, depr); } hir::ItemTrait(..) => { encode_def_id_and_key(self, def_id); - encode_family(self, 'I'); + encode_family(self, Family::Trait); encode_item_variances(self, item.id); let trait_def = tcx.lookup_trait_def(def_id); let trait_predicates = tcx.lookup_predicates(def_id); - encode_unsafety(self, trait_def.unsafety); - encode_paren_sugar(self, trait_def.paren_sugar); - encode_defaulted(self, tcx.trait_has_default_impl(def_id)); + + self.start_tag(tag_unsafety); + trait_def.unsafety.encode(self).unwrap(); + self.end_tag(); + + self.start_tag(tag_paren_sugar); + trait_def.paren_sugar.encode(self).unwrap(); + self.end_tag(); + + self.start_tag(tag_defaulted_trait); + tcx.trait_has_default_impl(def_id).encode(self).unwrap(); + self.end_tag(); + encode_associated_type_names(self, &trait_def.associated_type_names); self.encode_generics(&trait_def.generics, &trait_predicates); self.encode_predicates(&tcx.lookup_super_predicates(def_id), @@ -1138,27 +1049,12 @@ impl<'a, 'b, 'tcx> ItemContentBuilder<'a, 'b, 'tcx> { self.encode_visibility(vis); encode_stability(self, stab); encode_deprecation(self, depr); - for &method_def_id in tcx.trait_item_def_ids(def_id).iter() { - self.start_tag(tag_item_trait_item); - match method_def_id { - ty::ConstTraitItemId(const_def_id) => { - encode_def_id(self, const_def_id); - encode_item_sort(self, 'C'); - } - ty::MethodTraitItemId(method_def_id) => { - encode_def_id(self, method_def_id); - encode_item_sort(self, 'r'); - } - ty::TypeTraitItemId(type_def_id) => { - encode_def_id(self, type_def_id); - encode_item_sort(self, 't'); - } - } - self.end_tag(); - self.wr_tagged_u64(tag_mod_child, - def_to_u64(method_def_id.def_id())); - } + self.start_tag(tag_mod_children); + let items = tcx.impl_or_trait_items(def_id); + self.seq(&items[..], |_, id| id.def_id()); + <[def::Export]>::encode(&[], self).unwrap(); + self.end_tag(); // Encode inherent implementations for self trait. encode_inherent_implementations(self, def_id); @@ -1227,7 +1123,7 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { // Foo()` and `struct Foo` let ctor_def_id = self.tcx.map.local_def_id(struct_node_id); self.record(ctor_def_id, - ItemContentBuilder::encode_struct_ctor, + EncodeContext::encode_struct_ctor, (def_id, item.id, struct_node_id)); } } @@ -1241,8 +1137,7 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { def_id: DefId, impl_id: ast::NodeId, ast_items: &[hir::ImplItem]) { - let impl_items = self.tcx.impl_items.borrow(); - let items = &impl_items[&def_id]; + let items = self.tcx.impl_or_trait_items(def_id); // Iterate down the trait items, emitting them. We rely on the // assumption that all of the actually implemented trait items @@ -1258,7 +1153,7 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { let trait_item_def_id = trait_item_def_id.def_id(); self.record(trait_item_def_id, - ItemContentBuilder::encode_info_for_impl_item, + EncodeContext::encode_info_for_impl_item, (impl_id, trait_item_def_id, ast_item)); } } @@ -1267,19 +1162,18 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { def_id: DefId, trait_items: &[hir::TraitItem]) { // Now output the trait item info for each trait item. - let tcx = self.tcx; - let r = tcx.trait_item_def_ids(def_id); + let r = self.tcx.impl_or_trait_items(def_id); for (item_def_id, trait_item) in r.iter().zip(trait_items) { let item_def_id = item_def_id.def_id(); assert!(item_def_id.is_local()); self.record(item_def_id, - ItemContentBuilder::encode_info_for_trait_item, + EncodeContext::encode_info_for_trait_item, (def_id, item_def_id, trait_item)); } } } -impl<'a, 'b, 'tcx> ItemContentBuilder<'a, 'b, 'tcx> { +impl<'a, 'tcx> EncodeContext<'a, 'tcx> { fn encode_info_for_foreign_item(&mut self, (def_id, nitem): (DefId, &hir::ForeignItem)) { let tcx = self.tcx; @@ -1292,7 +1186,7 @@ impl<'a, 'b, 'tcx> ItemContentBuilder<'a, 'b, 'tcx> { self.encode_visibility(&nitem.vis); match nitem.node { hir::ForeignItemFn(ref fndecl, _) => { - encode_family(self, FN_FAMILY); + encode_family(self, Family::Fn); self.encode_bounds_and_type_for_item(def_id); encode_name(self, nitem.name); encode_attributes(self, &nitem.attrs); @@ -1303,11 +1197,11 @@ impl<'a, 'b, 'tcx> ItemContentBuilder<'a, 'b, 'tcx> { self.encode_method_argument_names(&fndecl); } hir::ForeignItemStatic(_, mutbl) => { - if mutbl { - encode_family(self, 'b'); + encode_family(self, if mutbl { + Family::MutStatic } else { - encode_family(self, 'c'); - } + Family::ImmStatic + }); self.encode_bounds_and_type_for_item(def_id); encode_attributes(self, &nitem.attrs); let stab = tcx.lookup_stability(tcx.map.local_def_id(nitem.id)); @@ -1335,7 +1229,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for EncodeVisitor<'a, 'b, 'tcx> { match item.node { hir::ItemExternCrate(_) | hir::ItemUse(_) => (), // ignore these _ => self.index.record(def_id, - ItemContentBuilder::encode_info_for_item, + EncodeContext::encode_info_for_item, (def_id, item)), } self.index.encode_addl_info_for_item(item); @@ -1344,7 +1238,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for EncodeVisitor<'a, 'b, 'tcx> { intravisit::walk_foreign_item(self, ni); let def_id = self.index.tcx.map.local_def_id(ni.id); self.index.record(def_id, - ItemContentBuilder::encode_info_for_foreign_item, + EncodeContext::encode_info_for_foreign_item, (def_id, ni)); } fn visit_ty(&mut self, ty: &'tcx hir::Ty) { @@ -1358,7 +1252,7 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { if let hir::TyImplTrait(_) = ty.node { let def_id = self.tcx.map.local_def_id(ty.id); self.record(def_id, - ItemContentBuilder::encode_info_for_anon_ty, + EncodeContext::encode_info_for_anon_ty, def_id); } } @@ -1368,7 +1262,7 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { hir::ExprClosure(..) => { let def_id = self.tcx.map.local_def_id(expr.id); self.record(def_id, - ItemContentBuilder::encode_info_for_closure, + EncodeContext::encode_info_for_closure, def_id); } _ => { } @@ -1376,10 +1270,9 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { } } -impl<'a, 'b, 'tcx> ItemContentBuilder<'a, 'b, 'tcx> { +impl<'a, 'tcx> EncodeContext<'a, 'tcx> { fn encode_info_for_anon_ty(&mut self, def_id: DefId) { encode_def_id_and_key(self, def_id); - encode_family(self, 'y'); self.encode_bounds_and_type_for_item(def_id); } @@ -1389,11 +1282,11 @@ impl<'a, 'b, 'tcx> ItemContentBuilder<'a, 'b, 'tcx> { encode_name(self, syntax::parse::token::intern("")); self.start_tag(tag_items_closure_ty); - tcx.tables.borrow().closure_tys[&def_id].encode(self.ecx).unwrap(); + tcx.tables.borrow().closure_tys[&def_id].encode(self).unwrap(); self.end_tag(); self.start_tag(tag_items_closure_kind); - tcx.closure_kind(def_id).encode(self.ecx).unwrap(); + tcx.closure_kind(def_id).encode(self).unwrap(); self.end_tag(); assert!(self.mir_map.map.contains_key(&def_id)); @@ -1401,30 +1294,29 @@ impl<'a, 'b, 'tcx> ItemContentBuilder<'a, 'b, 'tcx> { } } -fn encode_info_for_items<'a, 'tcx>(ecx: &mut EncodeContext<'a, 'tcx>) - -> (IndexData, FnvHashMap, u32>) { +fn encode_info_for_items(ecx: &mut EncodeContext) -> IndexData { let krate = ecx.tcx.map.krate(); ecx.start_tag(tag_items_data); - let fields = { + let items = { let mut index = IndexBuilder::new(ecx); index.record(DefId::local(CRATE_DEF_INDEX), - ItemContentBuilder::encode_info_for_mod, + EncodeContext::encode_info_for_mod, FromId(CRATE_NODE_ID, (&krate.module, - &[], + &krate.attrs, syntax::parse::token::intern(&ecx.link_meta.crate_name), &hir::Public))); let mut visitor = EncodeVisitor { index: index, }; krate.visit_all_items(&mut visitor); - visitor.index.into_fields() + visitor.index.into_items() }; ecx.end_tag(); - fields + items } fn encode_item_index(ecx: &mut EncodeContext, index: IndexData) { @@ -1439,40 +1331,12 @@ fn encode_attributes(ecx: &mut EncodeContext, attrs: &[ast::Attribute]) { ecx.end_tag(); } -fn encode_unsafety(ecx: &mut EncodeContext, unsafety: hir::Unsafety) { - let byte: u8 = match unsafety { - hir::Unsafety::Normal => 0, - hir::Unsafety::Unsafe => 1, - }; - ecx.wr_tagged_u8(tag_unsafety, byte); -} - -fn encode_paren_sugar(ecx: &mut EncodeContext, paren_sugar: bool) { - let byte: u8 = if paren_sugar {1} else {0}; - ecx.wr_tagged_u8(tag_paren_sugar, byte); -} - -fn encode_defaulted(ecx: &mut EncodeContext, is_defaulted: bool) { - let byte: u8 = if is_defaulted {1} else {0}; - ecx.wr_tagged_u8(tag_defaulted_trait, byte); -} - fn encode_associated_type_names(ecx: &mut EncodeContext, names: &[Name]) { ecx.start_tag(tag_associated_type_names); - for &name in names { - ecx.wr_tagged_str(tag_associated_type_name, &name.as_str()); - } + names.encode(ecx).unwrap(); ecx.end_tag(); } -fn encode_polarity(ecx: &mut EncodeContext, polarity: hir::ImplPolarity) { - let byte: u8 = match polarity { - hir::ImplPolarity::Positive => 0, - hir::ImplPolarity::Negative => 1, - }; - ecx.wr_tagged_u8(tag_polarity, byte); -} - fn encode_crate_deps(ecx: &mut EncodeContext, cstore: &cstore::CStore) { fn get_ordered_deps(cstore: &cstore::CStore) -> Vec<(CrateNum, Rc)> { @@ -1500,48 +1364,56 @@ fn encode_crate_deps(ecx: &mut EncodeContext, cstore: &cstore::CStore) { // FIXME (#2166): This is not nearly enough to support correct versioning // but is enough to get transitive crate dependencies working. ecx.start_tag(tag_crate_deps); - for (_cnum, dep) in get_ordered_deps(cstore) { - encode_crate_dep(ecx, &dep); - } + ecx.seq(&get_ordered_deps(cstore), |_, &(_, ref dep)| { + (dep.name(), decoder::get_crate_hash(dep.data()), + dep.explicitly_linked.get()) + }); ecx.end_tag(); } fn encode_lang_items(ecx: &mut EncodeContext) { - ecx.start_tag(tag_lang_items); - - for (i, &opt_def_id) in ecx.tcx.lang_items.items().iter().enumerate() { - if let Some(def_id) = opt_def_id { - if def_id.is_local() { - ecx.start_tag(tag_lang_items_item); - ecx.wr_tagged_u32(tag_lang_items_item_id, i as u32); - ecx.wr_tagged_u32(tag_lang_items_item_index, def_id.index.as_u32()); - ecx.end_tag(); + let tcx = ecx.tcx; + let lang_items = || { + tcx.lang_items.items().iter().enumerate().filter_map(|(i, &opt_def_id)| { + if let Some(def_id) = opt_def_id { + if def_id.is_local() { + return Some((def_id.index, i)); + } } - } - } + None + }) + }; - for i in &ecx.tcx.lang_items.missing { - ecx.wr_tagged_u32(tag_lang_items_missing, *i as u32); - } + let count = lang_items().count(); + let mut lang_items = lang_items(); - ecx.end_tag(); // tag_lang_items + ecx.start_tag(tag_lang_items); + ecx.seq(0..count, |_, _| lang_items.next().unwrap()); + ecx.end_tag(); + + ecx.start_tag(tag_lang_items_missing); + tcx.lang_items.missing.encode(ecx).unwrap(); + ecx.end_tag(); } fn encode_native_libraries(ecx: &mut EncodeContext) { - ecx.start_tag(tag_native_libraries); - - for &(ref lib, kind) in ecx.tcx.sess.cstore.used_libraries().iter() { - match kind { - cstore::NativeStatic => {} // these libraries are not propagated - cstore::NativeFramework | cstore::NativeUnknown => { - ecx.start_tag(tag_native_libraries_lib); - ecx.wr_tagged_u32(tag_native_libraries_kind, kind as u32); - ecx.wr_tagged_str(tag_native_libraries_name, lib); - ecx.end_tag(); + let used_libraries = ecx.tcx.sess.cstore.used_libraries(); + let libs = || { + used_libraries.iter().filter_map(|&(ref lib, kind)| { + match kind { + cstore::NativeStatic => None, // these libraries are not propagated + cstore::NativeFramework | cstore::NativeUnknown => { + Some((kind, lib)) + } } - } - } + }) + }; + let count = libs().count(); + let mut libs = libs(); + + ecx.start_tag(tag_native_libraries); + ecx.seq(0..count, |_, _| libs.next().unwrap()); ecx.end_tag(); } @@ -1549,84 +1421,55 @@ fn encode_plugin_registrar_fn(ecx: &mut EncodeContext) { match ecx.tcx.sess.plugin_registrar_fn.get() { Some(id) => { let def_id = ecx.tcx.map.local_def_id(id); - ecx.wr_tagged_u32(tag_plugin_registrar_fn, def_id.index.as_u32()); + ecx.start_tag(tag_plugin_registrar_fn); + def_id.index.encode(ecx).unwrap(); + ecx.end_tag(); } None => {} } } fn encode_codemap(ecx: &mut EncodeContext) { - ecx.start_tag(tag_codemap); let codemap = ecx.tcx.sess.codemap(); + let all_filemaps = codemap.files.borrow(); + let filemaps = || { + // No need to export empty filemaps, as they can't contain spans + // that need translation. + // Also no need to re-export imported filemaps, as any downstream + // crate will import them from their original source. + all_filemaps.iter().filter(|filemap| { + !filemap.lines.borrow().is_empty() && !filemap.is_imported() + }) + }; - for filemap in &codemap.files.borrow()[..] { - - if filemap.lines.borrow().is_empty() || filemap.is_imported() { - // No need to export empty filemaps, as they can't contain spans - // that need translation. - // Also no need to re-export imported filemaps, as any downstream - // crate will import them from their original source. - continue; - } - - ecx.start_tag(tag_codemap_filemap); - filemap.encode(ecx).unwrap(); - ecx.end_tag(); - } + let count = filemaps().count(); + let mut filemaps = filemaps(); + ecx.start_tag(tag_codemap); + ecx.seq(0..count, |_, _| filemaps.next().unwrap()); ecx.end_tag(); } /// Serialize the text of the exported macros -fn encode_macro_defs(ecx: &mut EncodeContext, - krate: &hir::Crate) { +fn encode_macro_defs(ecx: &mut EncodeContext) { + let tcx = ecx.tcx; ecx.start_tag(tag_macro_defs); - for def in &krate.exported_macros { - ecx.start_tag(tag_macro_def); - - encode_name(ecx, def.name); - encode_attributes(ecx, &def.attrs); - let &BytePos(lo) = &def.span.lo; - let &BytePos(hi) = &def.span.hi; - ecx.wr_tagged_u32(tag_macro_def_span_lo, lo); - ecx.wr_tagged_u32(tag_macro_def_span_hi, hi); - - ecx.wr_tagged_str(tag_macro_def_body, - &::syntax::print::pprust::tts_to_string(&def.body)); - - ecx.end_tag(); - } + ecx.seq(&tcx.map.krate().exported_macros, |_, def| { + let body = ::syntax::print::pprust::tts_to_string(&def.body); + (def.name, &def.attrs, def.span, body) + }); ecx.end_tag(); if ecx.tcx.sess.crate_types.borrow().contains(&CrateTypeRustcMacro) { let id = ecx.tcx.sess.derive_registrar_fn.get().unwrap(); let did = ecx.tcx.map.local_def_id(id); - ecx.wr_tagged_u32(tag_macro_derive_registrar, did.index.as_u32()); + + ecx.start_tag(tag_macro_derive_registrar); + did.index.encode(ecx).unwrap(); + ecx.end_tag(); } } -fn encode_struct_field_attrs(ecx: &mut EncodeContext, krate: &hir::Crate) { - struct StructFieldVisitor<'a, 'b:'a, 'tcx:'b> { - ecx: &'a mut EncodeContext<'b, 'tcx> - } - - impl<'a, 'b, 'tcx, 'v> Visitor<'v> for StructFieldVisitor<'a, 'b, 'tcx> { - fn visit_struct_field(&mut self, field: &hir::StructField) { - self.ecx.start_tag(tag_struct_field); - let def_id = self.ecx.tcx.map.local_def_id(field.id); - encode_def_id(self.ecx, def_id); - encode_attributes(self.ecx, &field.attrs); - self.ecx.end_tag(); - } - } - - ecx.start_tag(tag_struct_fields); - krate.visit_all_items(&mut StructFieldVisitor { ecx: ecx }); - ecx.end_tag(); -} - - - struct ImplVisitor<'a, 'tcx:'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, impls: FnvHashMap> @@ -1646,20 +1489,19 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ImplVisitor<'a, 'tcx> { } /// Encodes an index, mapping each trait to its (local) implementations. -fn encode_impls(ecx: &mut EncodeContext, krate: &hir::Crate) { +fn encode_impls(ecx: &mut EncodeContext) { let mut visitor = ImplVisitor { tcx: ecx.tcx, impls: FnvHashMap() }; - krate.visit_all_items(&mut visitor); + ecx.tcx.map.krate().visit_all_items(&mut visitor); ecx.start_tag(tag_impls); - for (trait_, trait_impls) in visitor.impls { - ecx.start_tag(tag_impls_trait); - encode_def_id(ecx, trait_); - for impl_ in trait_impls { - ecx.wr_tagged_u64(tag_impls_trait_impl, def_to_u64(impl_)); - } + for (trait_def_id, trait_impls) in visitor.impls { + // FIXME(eddyb) Avoid wrapping the entries in docs. + ecx.start_tag(0); + (trait_def_id.krate.as_u32(), trait_def_id.index).encode(ecx).unwrap(); + trait_impls.encode(ecx).unwrap(); ecx.end_tag(); } ecx.end_tag(); @@ -1673,74 +1515,32 @@ fn encode_impls(ecx: &mut EncodeContext, krate: &hir::Crate) { // definition (as that's not defined in this crate). fn encode_reachable(ecx: &mut EncodeContext) { ecx.start_tag(tag_reachable_ids); - for &id in ecx.reachable { - let def_id = ecx.tcx.map.local_def_id(id); - ecx.wr_tagged_u32(tag_reachable_id, def_id.index.as_u32()); - } + + let reachable = ecx.reachable; + ecx.seq(reachable, |ecx, &id| ecx.tcx.map.local_def_id(id).index); + ecx.end_tag(); } -fn encode_crate_dep(ecx: &mut EncodeContext, - dep: &cstore::CrateMetadata) { - ecx.start_tag(tag_crate_dep); - ecx.wr_tagged_str(tag_crate_dep_crate_name, &dep.name()); - let hash = decoder::get_crate_hash(dep.data()); - ecx.wr_tagged_u64(tag_crate_dep_hash, hash.as_u64()); - ecx.wr_tagged_u8(tag_crate_dep_explicitly_linked, - dep.explicitly_linked.get() as u8); - ecx.end_tag(); -} - -fn encode_hash(ecx: &mut EncodeContext, hash: &Svh) { - ecx.wr_tagged_u64(tag_crate_hash, hash.as_u64()); -} - -fn encode_rustc_version(ecx: &mut EncodeContext) { - ecx.wr_tagged_str(tag_rustc_version, &rustc_version()); -} - -fn encode_crate_name(ecx: &mut EncodeContext, crate_name: &str) { - ecx.wr_tagged_str(tag_crate_crate_name, crate_name); -} - -fn encode_crate_disambiguator(ecx: &mut EncodeContext, crate_disambiguator: &str) { - ecx.wr_tagged_str(tag_crate_disambiguator, crate_disambiguator); -} - -fn encode_crate_triple(ecx: &mut EncodeContext, triple: &str) { - ecx.wr_tagged_str(tag_crate_triple, triple); -} - fn encode_dylib_dependency_formats(ecx: &mut EncodeContext) { - let tag = tag_dylib_dependency_formats; + ecx.start_tag(tag_dylib_dependency_formats); match ecx.tcx.sess.dependency_formats.borrow().get(&config::CrateTypeDylib) { Some(arr) => { - let s = arr.iter().enumerate().filter_map(|(i, slot)| { - let kind = match *slot { + ecx.seq(arr, |_, slot| { + match *slot { Linkage::NotLinked | - Linkage::IncludedFromDylib => return None, - Linkage::Dynamic => "d", - Linkage::Static => "s", - }; - Some(format!("{}:{}", i + 1, kind)) - }).collect::>(); - ecx.wr_tagged_str(tag, &s.join(",")); + Linkage::IncludedFromDylib => None, + + Linkage::Dynamic => Some(LinkagePreference::RequireDynamic), + Linkage::Static => Some(LinkagePreference::RequireStatic), + } + }); } None => { - ecx.wr_tagged_str(tag, ""); - } - } -} - -fn encode_panic_strategy(ecx: &mut EncodeContext) { - match ecx.tcx.sess.opts.cg.panic { - PanicStrategy::Unwind => { - ecx.wr_tagged_u8(tag_panic_strategy, b'U'); - } - PanicStrategy::Abort => { - ecx.wr_tagged_u8(tag_panic_strategy, b'A'); + <[Option]>::encode(&[], ecx).unwrap(); } } + ecx.end_tag(); } pub fn encode_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -1764,6 +1564,7 @@ pub fn encode_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, reachable: reachable, mir_map: mir_map, type_shorthands: Default::default(), + xrefs: Default::default() }); // RBML compacts the encoded bytes whenever appropriate, @@ -1806,24 +1607,34 @@ pub fn encode_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } fn encode_metadata_inner(ecx: &mut EncodeContext) { - encode_rustc_version(ecx); + ecx.wr_tagged_str(tag_rustc_version, &rustc_version()); let tcx = ecx.tcx; let link_meta = ecx.link_meta; - encode_crate_name(ecx, &link_meta.crate_name); - encode_crate_triple(ecx, &tcx.sess.opts.target_triple); - encode_hash(ecx, &link_meta.crate_hash); - encode_crate_disambiguator(ecx, &tcx.sess.local_crate_disambiguator()); - encode_dylib_dependency_formats(ecx); - encode_panic_strategy(ecx); - let krate = tcx.map.krate(); + ecx.start_tag(tag_crate_crate_name); + link_meta.crate_name.encode(ecx).unwrap(); + ecx.end_tag(); + + ecx.start_tag(tag_crate_triple); + tcx.sess.opts.target_triple.encode(ecx).unwrap(); + ecx.end_tag(); + + ecx.start_tag(tag_crate_hash); + link_meta.crate_hash.encode(ecx).unwrap(); + ecx.end_tag(); + + ecx.start_tag(tag_crate_disambiguator); + tcx.sess.local_crate_disambiguator().encode(ecx).unwrap(); + ecx.end_tag(); + + encode_dylib_dependency_formats(ecx); + + ecx.start_tag(tag_panic_strategy); + ecx.tcx.sess.opts.cg.panic.encode(ecx); + ecx.end_tag(); let mut i = ecx.position(); - encode_attributes(ecx, &krate.attrs); - let attr_bytes = ecx.position() - i; - - i = ecx.position(); encode_crate_deps(ecx, ecx.cstore); let dep_bytes = ecx.position() - i; @@ -1849,12 +1660,12 @@ fn encode_metadata_inner(ecx: &mut EncodeContext) { // Encode macro definitions i = ecx.position(); - encode_macro_defs(ecx, krate); + encode_macro_defs(ecx); let macro_defs_bytes = ecx.position() - i; // Encode the def IDs of impls, for coherence checking. i = ecx.position(); - encode_impls(ecx, krate); + encode_impls(ecx); let impl_bytes = ecx.position() - i; // Encode reachability info. @@ -1865,7 +1676,7 @@ fn encode_metadata_inner(ecx: &mut EncodeContext) { // Encode and index the items. ecx.start_tag(tag_items); i = ecx.position(); - let (items, xrefs) = encode_info_for_items(ecx); + let items = encode_info_for_items(ecx); let item_bytes = ecx.position() - i; ecx.end_tag(); @@ -1874,11 +1685,9 @@ fn encode_metadata_inner(ecx: &mut EncodeContext) { let index_bytes = ecx.position() - i; i = ecx.position(); - encode_xrefs(ecx, xrefs); + ecx.encode_xrefs(); let xref_bytes = ecx.position() - i; - encode_struct_field_attrs(ecx, krate); - let total_bytes = ecx.position(); if ecx.tcx.sess.meta_stats() { @@ -1890,7 +1699,6 @@ fn encode_metadata_inner(ecx: &mut EncodeContext) { } println!("metadata stats:"); - println!(" attribute bytes: {}", attr_bytes); println!(" dep bytes: {}", dep_bytes); println!(" lang item bytes: {}", lang_item_bytes); println!(" native bytes: {}", native_lib_bytes); diff --git a/src/librustc_metadata/index_builder.rs b/src/librustc_metadata/index_builder.rs index fd25128575f1..2cfa6f8d5d11 100644 --- a/src/librustc_metadata/index_builder.rs +++ b/src/librustc_metadata/index_builder.rs @@ -38,17 +38,11 @@ //! //! What record will do is to (a) record the current offset, (b) emit //! the `common::data_item` tag, and then call `callback_fn` with the -//! given data as well as an `ItemContentBuilder`. Once `callback_fn` +//! given data as well as the `EncodingContext`. Once `callback_fn` //! returns, the `common::data_item` tag will be closed. //! -//! The `ItemContentBuilder` is another type that just offers access -//! to the `ecx` that was given in, as well as maintaining a list of -//! `xref` instances, which are used to extract common data so it is -//! not re-serialized. -//! -//! `ItemContentBuilder` is a distinct type which does not offer the -//! `record` method, so that we can ensure that `common::data_item` elements -//! are never nested. +//! `EncodingContext` does not offer the `record` method, so that we +//! can ensure that `common::data_item` elements are never nested. //! //! In addition, while the `callback_fn` is executing, we will push a //! task `MetaData(some_def_id)`, which can then observe the @@ -67,8 +61,7 @@ use index::IndexData; use rustc::dep_graph::DepNode; use rustc::hir; use rustc::hir::def_id::DefId; -use rustc::ty::{self, TyCtxt}; -use rustc_data_structures::fnv::FnvHashMap; +use rustc::ty::TyCtxt; use syntax::ast; use std::ops::{Deref, DerefMut}; @@ -77,54 +70,27 @@ use std::ops::{Deref, DerefMut}; /// Item encoding cannot be nested. pub struct IndexBuilder<'a, 'b: 'a, 'tcx: 'b> { items: IndexData, - builder: ItemContentBuilder<'a, 'b, 'tcx>, -} - -/// Builder that can encode the content of items, but can't start a -/// new item itself. Most code is attached to here. -pub struct ItemContentBuilder<'a, 'b: 'a, 'tcx: 'b> { - xrefs: FnvHashMap, u32>, // sequentially-assigned pub ecx: &'a mut EncodeContext<'b, 'tcx>, } impl<'a, 'b, 'tcx> Deref for IndexBuilder<'a, 'b, 'tcx> { type Target = EncodeContext<'b, 'tcx>; fn deref(&self) -> &Self::Target { - self.builder.ecx + self.ecx } } impl<'a, 'b, 'tcx> DerefMut for IndexBuilder<'a, 'b, 'tcx> { fn deref_mut(&mut self) -> &mut Self::Target { - self.builder.ecx - } -} - -impl<'a, 'b, 'tcx> Deref for ItemContentBuilder<'a, 'b, 'tcx> { - type Target = EncodeContext<'b, 'tcx>; - fn deref(&self) -> &Self::Target { self.ecx } } -impl<'a, 'b, 'tcx> DerefMut for ItemContentBuilder<'a, 'b, 'tcx> { - fn deref_mut(&mut self) -> &mut Self::Target { - self.ecx - } -} - -/// "interned" entries referenced by id -#[derive(PartialEq, Eq, Hash)] -pub enum XRef<'tcx> { Predicate(ty::Predicate<'tcx>) } - impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { pub fn new(ecx: &'a mut EncodeContext<'b, 'tcx>) -> Self { IndexBuilder { items: IndexData::new(ecx.tcx.map.num_local_def_ids()), - builder: ItemContentBuilder { - ecx: ecx, - xrefs: FnvHashMap(), - }, + ecx: ecx, } } @@ -147,28 +113,21 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { /// content system. pub fn record(&mut self, id: DefId, - op: fn(&mut ItemContentBuilder<'a, 'b, 'tcx>, DATA), + op: fn(&mut EncodeContext<'b, 'tcx>, DATA), data: DATA) where DATA: DepGraphRead { - let position = self.builder.ecx.mark_stable_position(); + let position = self.ecx.mark_stable_position(); self.items.record(id, position); let _task = self.tcx.dep_graph.in_task(DepNode::MetaData(id)); - self.builder.ecx.start_tag(tag_items_data_item).unwrap(); + self.ecx.start_tag(tag_items_data_item).unwrap(); data.read(self.tcx); - op(&mut self.builder, data); - self.builder.ecx.end_tag().unwrap(); + op(&mut self.ecx, data); + self.ecx.end_tag().unwrap(); } - pub fn into_fields(self) -> (IndexData, FnvHashMap, u32>) { - (self.items, self.builder.xrefs) - } -} - -impl<'a, 'b, 'tcx> ItemContentBuilder<'a, 'b, 'tcx> { - pub fn add_xref(&mut self, xref: XRef<'tcx>) -> u32 { - let old_len = self.xrefs.len() as u32; - *self.xrefs.entry(xref).or_insert(old_len) + pub fn into_items(self) -> IndexData { + self.items } } diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs index e5f7aab38c36..b7125daa4ad5 100644 --- a/src/librustc_metadata/lib.rs +++ b/src/librustc_metadata/lib.rs @@ -17,6 +17,7 @@ html_root_url = "https://doc.rust-lang.org/nightly/")] #![cfg_attr(not(stage0), deny(warnings))] +#![feature(conservative_impl_trait)] #![feature(core_intrinsics)] #![feature(box_patterns)] #![feature(dotdot_in_tuple_patterns)] diff --git a/src/librustc_metadata/rbml/reader.rs b/src/librustc_metadata/rbml/reader.rs index 9bbeb73ce3ec..24a0329602be 100644 --- a/src/librustc_metadata/rbml/reader.rs +++ b/src/librustc_metadata/rbml/reader.rs @@ -80,19 +80,16 @@ impl<'doc> Doc<'doc> { } pub fn get(&self, tag: usize) -> Doc<'doc> { - get_doc(*self, tag) + match maybe_get_doc(*self, tag) { + Some(d) => d, + None => { + bug!("failed to find block with tag {:?}", tag); + } + } } - pub fn is_empty(&self) -> bool { - self.start == self.end - } - - pub fn as_str(&self) -> &'doc str { - str::from_utf8(&self.data[self.start..self.end]).unwrap() - } - - pub fn to_string(&self) -> String { - self.as_str().to_string() + pub fn children(self) -> DocsIterator<'doc> { + DocsIterator { d: self } } } @@ -129,7 +126,7 @@ pub struct Res { pub next: usize, } -pub fn tag_at(data: &[u8], start: usize) -> Result { +fn tag_at(data: &[u8], start: usize) -> Result { let v = data[start] as usize; if v < 0xf0 { Ok(Res { @@ -180,7 +177,7 @@ fn vuint_at_slow(data: &[u8], start: usize) -> Result { Err(Error::IntTooBig(a as usize)) } -pub fn vuint_at(data: &[u8], start: usize) -> Result { +fn vuint_at(data: &[u8], start: usize) -> Result { if data.len() - start < 4 { return vuint_at_slow(data, start); } @@ -234,7 +231,7 @@ pub fn vuint_at(data: &[u8], start: usize) -> Result { } } -pub fn tag_len_at(data: &[u8], next: usize) -> Result { +fn tag_len_at(data: &[u8], next: usize) -> Result { vuint_at(data, next) } @@ -255,27 +252,14 @@ pub fn maybe_get_doc<'a>(d: Doc<'a>, tg: usize) -> Option> { None } -pub fn get_doc<'a>(d: Doc<'a>, tg: usize) -> Doc<'a> { - match maybe_get_doc(d, tg) { - Some(d) => d, - None => { - bug!("failed to find block with tag {:?}", tg); - } - } -} - -pub fn docs<'a>(d: Doc<'a>) -> DocsIterator<'a> { - DocsIterator { d: d } -} - pub struct DocsIterator<'a> { d: Doc<'a>, } impl<'a> Iterator for DocsIterator<'a> { - type Item = (usize, Doc<'a>); + type Item = Doc<'a>; - fn next(&mut self) -> Option<(usize, Doc<'a>)> { + fn next(&mut self) -> Option> { if self.d.start >= self.d.end { return None; } @@ -297,98 +281,10 @@ impl<'a> Iterator for DocsIterator<'a> { }; self.d.start = end; - return Some((elt_tag.val, doc)); + return Some(doc); } } -pub fn tagged_docs<'a>(d: Doc<'a>, tag: usize) -> TaggedDocsIterator<'a> { - TaggedDocsIterator { - iter: docs(d), - tag: tag, - } -} - -pub struct TaggedDocsIterator<'a> { - iter: DocsIterator<'a>, - tag: usize, -} - -impl<'a> Iterator for TaggedDocsIterator<'a> { - type Item = Doc<'a>; - - fn next(&mut self) -> Option> { - while let Some((tag, doc)) = self.iter.next() { - if tag == self.tag { - return Some(doc); - } - } - None - } -} - -pub fn with_doc_data(d: Doc, f: F) -> T - where F: FnOnce(&[u8]) -> T -{ - f(&d.data[d.start..d.end]) -} - -pub fn doc_as_u8(d: Doc) -> u8 { - assert_eq!(d.end, d.start + 1); - d.data[d.start] -} - -pub fn doc_as_u64(d: Doc) -> u64 { - if d.end >= 8 { - // For performance, we read 8 big-endian bytes, - // and mask off the junk if there is any. This - // obviously won't work on the first 8 bytes - // of a file - we will fall of the start - // of the page and segfault. - - let mut b = [0; 8]; - b.copy_from_slice(&d.data[d.end - 8..d.end]); - let data = unsafe { (*(b.as_ptr() as *const u64)).to_be() }; - let len = d.end - d.start; - if len < 8 { - data & ((1 << (len * 8)) - 1) - } else { - data - } - } else { - let mut result = 0; - for b in &d.data[d.start..d.end] { - result = (result << 8) + (*b as u64); - } - result - } -} - -#[inline] -pub fn doc_as_u16(d: Doc) -> u16 { - doc_as_u64(d) as u16 -} -#[inline] -pub fn doc_as_u32(d: Doc) -> u32 { - doc_as_u64(d) as u32 -} - -#[inline] -pub fn doc_as_i8(d: Doc) -> i8 { - doc_as_u8(d) as i8 -} -#[inline] -pub fn doc_as_i16(d: Doc) -> i16 { - doc_as_u16(d) as i16 -} -#[inline] -pub fn doc_as_i32(d: Doc) -> i32 { - doc_as_u32(d) as i32 -} -#[inline] -pub fn doc_as_i64(d: Doc) -> i64 { - doc_as_u64(d) as i64 -} - #[test] fn test_vuint_at() { let data = &[ diff --git a/src/librustc_metadata/rbml/writer.rs b/src/librustc_metadata/rbml/writer.rs index 94e9b394f1f9..46b63cb13403 100644 --- a/src/librustc_metadata/rbml/writer.rs +++ b/src/librustc_metadata/rbml/writer.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::mem; use std::io::prelude::*; use std::io::{self, SeekFrom, Cursor}; @@ -112,50 +111,10 @@ impl<'a> Encoder<'a> { Ok(()) } - pub fn wr_tag(&mut self, tag_id: usize, blk: F) -> EncodeResult - where F: FnOnce() -> EncodeResult - { - self.start_tag(tag_id)?; - blk()?; - self.end_tag() - } - - pub fn wr_tagged_bytes(&mut self, tag_id: usize, b: &[u8]) -> EncodeResult { - write_tag(&mut self.opaque.cursor, tag_id)?; - write_vuint(&mut self.opaque.cursor, b.len())?; - self.opaque.cursor.write_all(b) - } - - pub fn wr_tagged_u64(&mut self, tag_id: usize, v: u64) -> EncodeResult { - let bytes: [u8; 8] = unsafe { mem::transmute(v.to_be()) }; - // tagged integers are emitted in big-endian, with no - // leading zeros. - let leading_zero_bytes = v.leading_zeros() / 8; - self.wr_tagged_bytes(tag_id, &bytes[leading_zero_bytes as usize..]) - } - - #[inline] - pub fn wr_tagged_u32(&mut self, tag_id: usize, v: u32) -> EncodeResult { - self.wr_tagged_u64(tag_id, v as u64) - } - - #[inline] - pub fn wr_tagged_u8(&mut self, tag_id: usize, v: u8) -> EncodeResult { - self.wr_tagged_bytes(tag_id, &[v]) - } - pub fn wr_tagged_str(&mut self, tag_id: usize, v: &str) -> EncodeResult { - self.wr_tagged_bytes(tag_id, v.as_bytes()) - } - - pub fn wr_bytes(&mut self, b: &[u8]) -> EncodeResult { - debug!("Write {:?} bytes", b.len()); - self.opaque.cursor.write_all(b) - } - - pub fn wr_str(&mut self, s: &str) -> EncodeResult { - debug!("Write str: {:?}", s); - self.opaque.cursor.write_all(s.as_bytes()) + write_tag(&mut self.opaque.cursor, tag_id)?; + write_vuint(&mut self.opaque.cursor, v.len())?; + self.opaque.cursor.write_all(v.as_bytes()) } pub fn position(&mut self) -> usize { diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 83f03e7cfc5a..3df3a2decba3 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -21,10 +21,10 @@ use ParentLink::{ModuleParentLink, BlockParentLink}; use Resolver; use {resolve_error, resolve_struct_error, ResolutionError}; -use rustc::middle::cstore::{ChildItem, DlDef}; +use rustc::middle::cstore::ChildItem; use rustc::hir::def::*; use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId}; -use rustc::ty::{self, VariantKind}; +use rustc::ty; use std::cell::Cell; @@ -201,7 +201,7 @@ impl<'b> Resolver<'b> { let module = self.new_extern_crate_module(parent_link, def, item.id); self.define(parent, name, TypeNS, (module, sp, vis)); - self.build_reduced_graph_for_external_crate(module); + self.populate_module_if_necessary(module); } } @@ -388,13 +388,8 @@ impl<'b> Resolver<'b> { } /// Builds the reduced graph for a single item in an external crate. - fn build_reduced_graph_for_external_crate_def(&mut self, parent: Module<'b>, xcdef: ChildItem) { - let def = match xcdef.def { - DlDef(def) => def, - _ => return, - }; - - if let Def::ForeignMod(def_id) = def { + fn build_reduced_graph_for_external_crate_def(&mut self, parent: Module<'b>, child: ChildItem) { + if let Def::ForeignMod(def_id) = child.def { // Foreign modules have no names. Recur and populate eagerly. for child in self.session.cstore.item_children(def_id) { self.build_reduced_graph_for_external_crate_def(parent, child); @@ -402,8 +397,9 @@ impl<'b> Resolver<'b> { return; } - let name = xcdef.name; - let vis = if parent.is_trait() { ty::Visibility::Public } else { xcdef.vis }; + let def = child.def; + let name = child.name; + let vis = if parent.is_trait() { ty::Visibility::Public } else { child.vis }; match def { Def::Mod(_) | Def::ForeignMod(_) | Def::Enum(..) => { @@ -413,16 +409,12 @@ impl<'b> Resolver<'b> { let module = self.new_module(parent_link, Some(def), None); let _ = self.try_define(parent, name, TypeNS, (module, DUMMY_SP, vis)); } - Def::Variant(_, variant_id) => { + Def::Variant(..) => { debug!("(building reduced graph for external crate) building variant {}", name); // Variants are always treated as importable to allow them to be glob used. // All variants are defined in both type and value namespaces as future-proofing. let _ = self.try_define(parent, name, TypeNS, (def, DUMMY_SP, vis)); let _ = self.try_define(parent, name, ValueNS, (def, DUMMY_SP, vis)); - if self.session.cstore.variant_kind(variant_id) == Some(VariantKind::Struct) { - // Not adding fields for variants as they are not accessed with a self receiver - self.structs.insert(variant_id, Vec::new()); - } } Def::Fn(..) | Def::Static(..) | @@ -439,7 +431,7 @@ impl<'b> Resolver<'b> { // If this is a trait, add all the trait item names to the trait // info. - let trait_item_def_ids = self.session.cstore.trait_item_def_ids(def_id); + let trait_item_def_ids = self.session.cstore.impl_or_trait_items(def_id); for trait_item_def in &trait_item_def_ids { let trait_item_name = self.session.cstore.item_name(trait_item_def.def_id()); @@ -493,15 +485,6 @@ impl<'b> Resolver<'b> { } } - /// Builds the reduced graph rooted at the 'use' directive for an external - /// crate. - fn build_reduced_graph_for_external_crate(&mut self, root: Module<'b>) { - let root_cnum = root.def_id().unwrap().krate; - for child in self.session.cstore.crate_top_level_items(root_cnum) { - self.build_reduced_graph_for_external_crate_def(root, child); - } - } - /// Ensures that the reduced graph rooted at the given external module /// is built, building it if it is not. pub fn populate_module_if_necessary(&mut self, module: Module<'b>) { diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 5e78ac7ca94c..b03e76c829a3 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1275,6 +1275,7 @@ impl<'a> Resolver<'a> { -> Module<'a> { let mut module = ModuleS::new(parent_link, Some(def), Some(local_node_id)); module.extern_crate_id = Some(local_node_id); + module.populated.set(false); self.arenas.modules.alloc(module) } diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 3764e26b020d..186183a8ad4d 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -543,10 +543,8 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { .map(|mr| mr.def_id()) } ty::ImplContainer(def_id) => { - let impl_items = self.tcx.impl_items.borrow(); - Some(impl_items.get(&def_id) - .unwrap() - .iter() + let impl_items = self.tcx.impl_or_trait_items(def_id); + Some(impl_items.iter() .find(|mr| { self.tcx.impl_or_trait_item(mr.def_id()).name() == ti.name() diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index a58de71ca41e..b9449eeecf42 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -627,25 +627,23 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { fn can_result_in_trans_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> bool { - if !match tcx.lookup_item_type(def_id).ty.sty { - ty::TyFnDef(def_id, ..) => { + match tcx.lookup_item_type(def_id).ty.sty { + ty::TyFnDef(def_id, _, f) => { // Some constructors also have type TyFnDef but they are // always instantiated inline and don't result in // translation item. Same for FFI functions. - match tcx.map.get_if_local(def_id) { - Some(hir_map::NodeVariant(_)) | - Some(hir_map::NodeStructCtor(_)) | - Some(hir_map::NodeForeignItem(_)) => false, - Some(_) => true, - None => { - tcx.sess.cstore.variant_kind(def_id).is_none() + if let Some(hir_map::NodeForeignItem(_)) = tcx.map.get_if_local(def_id) { + return false; + } + + if let Some(adt_def) = f.sig.output().skip_binder().ty_adt_def() { + if adt_def.variants.iter().any(|v| def_id == v.did) { + return false; } } } - ty::TyClosure(..) => true, - _ => false - } { - return false; + ty::TyClosure(..) => {} + _ => return false } can_have_local_instance(tcx, def_id) diff --git a/src/librustc_trans/meth.rs b/src/librustc_trans/meth.rs index ee2f24d21e07..9db5020747e1 100644 --- a/src/librustc_trans/meth.rs +++ b/src/librustc_trans/meth.rs @@ -230,7 +230,7 @@ pub fn get_vtable_methods<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, tcx.populate_implementations_for_trait_if_necessary(trait_id); - let trait_item_def_ids = tcx.trait_item_def_ids(trait_id); + let trait_item_def_ids = tcx.impl_or_trait_items(trait_id); trait_item_def_ids .iter() diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index e9f324c0b08f..999433db2407 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -247,11 +247,17 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { let vtable = common::fulfill_obligation(ccx.shared(), DUMMY_SP, trait_ref); if let traits::VtableImpl(vtable_impl) = vtable { let name = ccx.tcx().item_name(instance.def); - for ac in ccx.tcx().associated_consts(vtable_impl.impl_def_id) { - if ac.name == name { - instance = Instance::new(ac.def_id, vtable_impl.substs); - break; - } + let ac = ccx.tcx().impl_or_trait_items(vtable_impl.impl_def_id) + .iter().filter_map(|id| { + match *id { + ty::ConstTraitItemId(def_id) => { + Some(ccx.tcx().impl_or_trait_item(def_id)) + } + _ => None + } + }).find(|ic| ic.name() == name); + if let Some(ac) = ac { + instance = Instance::new(ac.def_id(), vtable_impl.substs); } } } diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index bcb410e1b8d0..71219d82668e 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -218,7 +218,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Trait must have a method named `m_name` and it should not have // type parameters or early-bound regions. let tcx = self.tcx; - let method_item = self.trait_item(trait_def_id, m_name).unwrap(); + let method_item = self.impl_or_trait_item(trait_def_id, m_name).unwrap(); let method_ty = method_item.as_opt_method().unwrap(); assert_eq!(method_ty.generics.types.len(), 0); assert_eq!(method_ty.generics.regions.len(), 0); @@ -359,27 +359,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { Ok(def) } - /// Find item with name `item_name` defined in `trait_def_id` - /// and return it, or `None`, if no such item. - pub fn trait_item(&self, - trait_def_id: DefId, - item_name: ast::Name) - -> Option> + /// Find item with name `item_name` defined in impl/trait `def_id` + /// and return it, or `None`, if no such item was defined there. + pub fn impl_or_trait_item(&self, + def_id: DefId, + item_name: ast::Name) + -> Option> { - let trait_items = self.tcx.trait_items(trait_def_id); - trait_items.iter() - .find(|item| item.name() == item_name) - .cloned() - } - - pub fn impl_item(&self, - impl_def_id: DefId, - item_name: ast::Name) - -> Option> - { - let impl_items = self.tcx.impl_items.borrow(); - let impl_items = impl_items.get(&impl_def_id).unwrap(); - impl_items + self.tcx.impl_or_trait_items(def_id) .iter() .map(|&did| self.tcx.impl_or_trait_item(did.def_id())) .find(|m| m.name() == item_name) diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 81e95c91e7ff..9fba9bcb757b 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -403,7 +403,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { debug!("assemble_inherent_impl_probe {:?}", impl_def_id); - let item = match self.impl_item(impl_def_id) { + let item = match self.impl_or_trait_item(impl_def_id) { Some(m) => m, None => { return; } // No method with correct name on this impl }; @@ -555,7 +555,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { let tcx = self.tcx; for bound_trait_ref in traits::transitive_bounds(tcx, bounds) { - let item = match self.trait_item(bound_trait_ref.def_id()) { + let item = match self.impl_or_trait_item(bound_trait_ref.def_id()) { Some(v) => v, None => { continue; } }; @@ -1292,18 +1292,12 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { self.tcx.erase_late_bound_regions(value) } - fn impl_item(&self, impl_def_id: DefId) - -> Option> + /// Find item with name `item_name` defined in impl/trait `def_id` + /// and return it, or `None`, if no such item was defined there. + fn impl_or_trait_item(&self, def_id: DefId) + -> Option> { - self.fcx.impl_item(impl_def_id, self.item_name) - } - - /// Find item with name `item_name` defined in `trait_def_id` - /// and return it, or `None`, if no such item. - fn trait_item(&self, trait_def_id: DefId) - -> Option> - { - self.fcx.trait_item(trait_def_id, self.item_name) + self.fcx.impl_or_trait_item(def_id, self.item_name) } } diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index 3692d6fbf73d..7ec491807023 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -16,9 +16,8 @@ use CrateCtxt; use check::{FnCtxt}; use rustc::hir::map as hir_map; use rustc::ty::{self, Ty, ToPolyTraitRef, ToPredicate, TypeFoldable}; -use middle::cstore; use hir::def::Def; -use hir::def_id::DefId; +use hir::def_id::{CRATE_DEF_INDEX, DefId}; use middle::lang_items::FnOnceTraitLangItem; use rustc::ty::subst::Substs; use rustc::traits::{Obligation, SelectionContext}; @@ -92,9 +91,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { CandidateSource::ImplSource(impl_did) => { // Provide the best span we can. Use the item, if local to crate, else // the impl, if local to crate (item may be defaulted), else nothing. - let item = self.impl_item(impl_did, item_name) + let item = self.impl_or_trait_item(impl_did, item_name) .or_else(|| { - self.trait_item( + self.impl_or_trait_item( self.tcx.impl_trait_ref(impl_did).unwrap().def_id, item_name @@ -127,7 +126,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } } CandidateSource::TraitSource(trait_did) => { - let item = self.trait_item(trait_did, item_name).unwrap(); + let item = self.impl_or_trait_item(trait_did, item_name).unwrap(); let item_span = self.tcx.map.def_id_span(item.def_id(), span); span_note!(err, item_span, "candidate #{} is defined in the trait `{}`", @@ -321,7 +320,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // implementing a trait would be legal but is rejected // here). (type_is_local || info.def_id.is_local()) - && self.trait_item(info.def_id, item_name).is_some() + && self.impl_or_trait_item(info.def_id, item_name).is_some() }) .collect::>(); @@ -449,34 +448,30 @@ pub fn all_traits<'a>(ccx: &'a CrateCtxt) -> AllTraits<'a> { // Cross-crate: let mut external_mods = FnvHashSet(); - fn handle_external_def(traits: &mut AllTraitsVec, + fn handle_external_def(ccx: &CrateCtxt, + traits: &mut AllTraitsVec, external_mods: &mut FnvHashSet, - ccx: &CrateCtxt, - cstore: &for<'a> cstore::CrateStore<'a>, - dl: cstore::DefLike) { - match dl { - cstore::DlDef(Def::Trait(did)) => { + def: Def) { + match def { + Def::Trait(did) => { traits.push(TraitInfo::new(did)); } - cstore::DlDef(Def::Mod(did)) => { + Def::Mod(did) => { if !external_mods.insert(did) { return; } - for child in cstore.item_children(did) { - handle_external_def(traits, external_mods, - ccx, cstore, child.def) + for child in ccx.tcx.sess.cstore.item_children(did) { + handle_external_def(ccx, traits, external_mods, child.def) } } _ => {} } } - let cstore = &*ccx.tcx.sess.cstore; - for cnum in ccx.tcx.sess.cstore.crates() { - for child in cstore.crate_top_level_items(cnum) { - handle_external_def(&mut traits, &mut external_mods, - ccx, cstore, child.def) - } + handle_external_def(ccx, &mut traits, &mut external_mods, Def::Mod(DefId { + krate: cnum, + index: CRATE_DEF_INDEX + })); } *ccx.all_traits.borrow_mut() = Some(traits); diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index 26c33c00b9cf..fb077d279c99 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -39,6 +39,8 @@ use rustc::hir::intravisit; use rustc::hir::{Item, ItemImpl}; use rustc::hir; +use std::rc::Rc; + mod orphan; mod overlap; mod unsafety; @@ -156,7 +158,7 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { } } - tcx.impl_items.borrow_mut().insert(impl_did, impl_items); + tcx.impl_or_trait_item_ids.borrow_mut().insert(impl_did, Rc::new(impl_items)); } fn add_inherent_impl(&self, base_def_id: DefId, impl_def_id: DefId) { @@ -208,7 +210,7 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { tcx.populate_implementations_for_trait_if_necessary(drop_trait); let drop_trait = tcx.lookup_trait_def(drop_trait); - let impl_items = tcx.impl_items.borrow(); + let impl_items = tcx.impl_or_trait_item_ids.borrow(); drop_trait.for_each_impl(tcx, |impl_did| { let items = impl_items.get(&impl_did).unwrap(); diff --git a/src/librustc_typeck/coherence/overlap.rs b/src/librustc_typeck/coherence/overlap.rs index 890b6c72e6fe..9d072491cc28 100644 --- a/src/librustc_typeck/coherence/overlap.rs +++ b/src/librustc_typeck/coherence/overlap.rs @@ -55,12 +55,12 @@ impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> { }) } - let impl_items = self.tcx.impl_items.borrow(); + let impl_items = self.tcx.impl_or_trait_item_ids.borrow(); - for item1 in &impl_items[&impl1] { + for item1 in &impl_items[&impl1][..] { let (name, namespace) = name_and_namespace(self.tcx, item1); - for item2 in &impl_items[&impl2] { + for item2 in &impl_items[&impl2][..] { if (name, namespace) == name_and_namespace(self.tcx, item2) { let msg = format!("duplicate definitions with name `{}`", name); let node_id = self.tcx.map.as_local_node_id(item1.def_id()).unwrap(); diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 04aca8c0947c..fa052bec7be3 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -563,6 +563,7 @@ fn convert_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, vis: &hir::Visibility, sig: &hir::MethodSig, defaultness: hir::Defaultness, + has_body: bool, untransformed_rcvr_ty: Ty<'tcx>, rcvr_ty_predicates: &ty::GenericPredicates<'tcx>) { let def_id = ccx.tcx.map.local_def_id(id); @@ -580,15 +581,18 @@ fn convert_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, sig, untransformed_rcvr_ty, anon_scope) }; - let ty_method = ty::Method::new(name, - ty_generics, - ty_generic_predicates, - fty, - explicit_self_category, - ty::Visibility::from_hir(vis, id, ccx.tcx), - defaultness, - def_id, - container); + let ty_method = ty::Method { + name: name, + generics: ty_generics, + predicates: ty_generic_predicates, + fty: fty, + explicit_self: explicit_self_category, + vis: ty::Visibility::from_hir(vis, id, ccx.tcx), + defaultness: defaultness, + has_body: has_body, + def_id: def_id, + container: container, + }; let substs = mk_item_substs(&ccx.icx(&(rcvr_ty_predicates, &sig.generics)), ccx.tcx.map.span(id), def_id); @@ -843,7 +847,7 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { convert_method(ccx, ImplContainer(def_id), impl_item.name, impl_item.id, method_vis, - sig, impl_item.defaultness, selfty, + sig, impl_item.defaultness, true, selfty, &ty_predicates); } } @@ -905,7 +909,7 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { // Convert all the methods for trait_item in trait_items { - if let hir::MethodTraitItem(ref sig, _) = trait_item.node { + if let hir::MethodTraitItem(ref sig, ref body) = trait_item.node { convert_method(ccx, container, trait_item.name, @@ -913,6 +917,7 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { &hir::Inherited, sig, hir::Defaultness::Default, + body.is_some(), tcx.mk_self_type(), &trait_predicates); @@ -928,8 +933,8 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { hir::TypeTraitItem(..) => ty::TypeTraitItemId(def_id) } }).collect()); - tcx.trait_item_def_ids.borrow_mut().insert(ccx.tcx.map.local_def_id(it.id), - trait_item_def_ids); + tcx.impl_or_trait_item_ids.borrow_mut().insert(ccx.tcx.map.local_def_id(it.id), + trait_item_def_ids); }, hir::ItemStruct(ref struct_def, _) | hir::ItemUnion(ref struct_def, _) => { diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 709e36989244..e992861b77bc 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -15,7 +15,6 @@ use std::iter::once; use syntax::ast; use rustc::hir; -use rustc::middle::cstore; use rustc::hir::def::Def; use rustc::hir::def_id::DefId; use rustc::hir::print as pprust; @@ -96,12 +95,12 @@ fn try_inline_def<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>, Def::TyAlias(did) => { record_extern_fqn(cx, did, clean::TypeTypedef); ret.extend(build_impls(cx, tcx, did)); - build_type(cx, tcx, did) + clean::TypedefItem(build_type_alias(cx, tcx, did), false) } Def::Enum(did) => { record_extern_fqn(cx, did, clean::TypeEnum); ret.extend(build_impls(cx, tcx, did)); - build_type(cx, tcx, did) + clean::EnumItem(build_enum(cx, tcx, did)) } // Assume that the enum type is reexported next to the variant, and // variants don't show up in documentation specially. @@ -200,6 +199,18 @@ fn build_external_function<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx } } +fn build_enum<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>, + did: DefId) -> clean::Enum { + let t = tcx.lookup_item_type(did); + let predicates = tcx.lookup_predicates(did); + + clean::Enum { + generics: (t.generics, &predicates).clean(cx), + variants_stripped: false, + variants: tcx.lookup_adt_def(did).variants.clean(cx), + } +} + fn build_struct<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>, did: DefId) -> clean::Struct { let t = tcx.lookup_item_type(did); @@ -232,25 +243,15 @@ fn build_union<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>, } } -fn build_type<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>, - did: DefId) -> clean::ItemEnum { +fn build_type_alias<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>, + did: DefId) -> clean::Typedef { let t = tcx.lookup_item_type(did); let predicates = tcx.lookup_predicates(did); - match t.ty.sty { - ty::TyAdt(edef, _) if edef.is_enum() && !tcx.sess.cstore.is_typedef(did) => { - return clean::EnumItem(clean::Enum { - generics: (t.generics, &predicates).clean(cx), - variants_stripped: false, - variants: edef.variants.clean(cx), - }) - } - _ => {} - } - clean::TypedefItem(clean::Typedef { + clean::Typedef { type_: t.ty.clean(cx), generics: (t.generics, &predicates).clean(cx), - }, false) + } } pub fn build_impls<'a, 'tcx>(cx: &DocContext, @@ -264,32 +265,49 @@ pub fn build_impls<'a, 'tcx>(cx: &DocContext, build_impl(cx, tcx, did, &mut impls); } } - - // If this is the first time we've inlined something from this crate, then - // we inline *all* impls from the crate into this crate. Note that there's + // If this is the first time we've inlined something from another crate, then + // we inline *all* impls from all the crates into this crate. Note that there's // currently no way for us to filter this based on type, and we likely need // many impls for a variety of reasons. // // Primarily, the impls will be used to populate the documentation for this // type being inlined, but impls can also be used when generating // documentation for primitives (no way to find those specifically). - if cx.populated_crate_impls.borrow_mut().insert(did.krate) { - for item in tcx.sess.cstore.crate_top_level_items(did.krate) { - populate_impls(cx, tcx, item.def, &mut impls); - } + if cx.populated_all_crate_impls.get() { + return impls; + } - fn populate_impls<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>, - def: cstore::DefLike, - impls: &mut Vec) { - match def { - cstore::DlImpl(did) => build_impl(cx, tcx, did, impls), - cstore::DlDef(Def::Mod(did)) => { - for item in tcx.sess.cstore.item_children(did) { - populate_impls(cx, tcx, item.def, impls) - } - } - _ => {} - } + cx.populated_all_crate_impls.set(true); + + for did in tcx.sess.cstore.implementations_of_trait(None) { + build_impl(cx, tcx, did, &mut impls); + } + + // Also try to inline primitive impls from other crates. + let primitive_impls = [ + tcx.lang_items.isize_impl(), + tcx.lang_items.i8_impl(), + tcx.lang_items.i16_impl(), + tcx.lang_items.i32_impl(), + tcx.lang_items.i64_impl(), + tcx.lang_items.usize_impl(), + tcx.lang_items.u8_impl(), + tcx.lang_items.u16_impl(), + tcx.lang_items.u32_impl(), + tcx.lang_items.u64_impl(), + tcx.lang_items.f32_impl(), + tcx.lang_items.f64_impl(), + tcx.lang_items.char_impl(), + tcx.lang_items.str_impl(), + tcx.lang_items.slice_impl(), + tcx.lang_items.slice_impl(), + tcx.lang_items.const_ptr_impl() + ]; + + for def_id in primitive_impls.iter().filter_map(|&def_id| def_id) { + if !def_id.is_local() { + tcx.populate_implementations_for_primitive_if_necessary(def_id); + build_impl(cx, tcx, def_id, &mut impls); } } @@ -348,7 +366,7 @@ pub fn build_impl<'a, 'tcx>(cx: &DocContext, } let predicates = tcx.lookup_predicates(did); - let trait_items = tcx.sess.cstore.impl_items(did) + let trait_items = tcx.sess.cstore.impl_or_trait_items(did) .iter() .filter_map(|did| { let did = did.def_id(); @@ -453,7 +471,7 @@ pub fn build_impl<'a, 'tcx>(cx: &DocContext, for_: for_, generics: (ty.generics, &predicates).clean(cx), items: trait_items, - polarity: polarity.map(|p| { p.clean(cx) }), + polarity: Some(polarity.clean(cx)), }), source: clean::Span::empty(), name: None, @@ -482,19 +500,17 @@ fn build_module<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>, let mut visited = FnvHashSet(); for item in tcx.sess.cstore.item_children(did) { match item.def { - cstore::DlDef(Def::ForeignMod(did)) => { + Def::ForeignMod(did) => { fill_in(cx, tcx, did, items); } - cstore::DlDef(def) if item.vis == ty::Visibility::Public => { - if !visited.insert(def) { continue } - if let Some(i) = try_inline_def(cx, tcx, def) { - items.extend(i) + def => { + if item.vis == ty::Visibility::Public { + if !visited.insert(def) { continue } + if let Some(i) = try_inline_def(cx, tcx, def) { + items.extend(i) + } } } - cstore::DlDef(..) => {} - // All impls were inlined above - cstore::DlImpl(..) => {} - cstore::DlField => panic!("unimplemented field"), } } } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 7eb7b24015e1..f9d7eb50edae 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -33,7 +33,6 @@ use syntax::print::pprust as syntax_pprust; use syntax_pos::{self, DUMMY_SP, Pos}; use rustc_trans::back::link; -use rustc::middle::cstore; use rustc::middle::privacy::AccessLevels; use rustc::middle::resolve_lifetime::DefRegion::*; use rustc::hir::def::Def; @@ -239,9 +238,10 @@ impl Clean for CrateNum { fn clean(&self, cx: &DocContext) -> ExternalCrate { let mut primitives = Vec::new(); cx.tcx_opt().map(|tcx| { - for item in tcx.sess.cstore.crate_top_level_items(self.0) { + let root = DefId { krate: self.0, index: CRATE_DEF_INDEX }; + for item in tcx.sess.cstore.item_children(root) { let did = match item.def { - cstore::DlDef(Def::Mod(did)) => did, + Def::Mod(did) => did, _ => continue }; let attrs = inline::load_attrs(cx, tcx, did); @@ -1877,11 +1877,9 @@ impl Clean for hir::StructField { impl<'tcx> Clean for ty::FieldDefData<'tcx, 'static> { fn clean(&self, cx: &DocContext) -> Item { - // FIXME: possible O(n^2)-ness! Not my fault. - let attr_map = cx.tcx().sess.cstore.crate_struct_field_attrs(self.did.krate); Item { name: Some(self.name).clean(cx), - attrs: attr_map.get(&self.did).unwrap_or(&Vec::new()).clean(cx), + attrs: cx.tcx().get_attrs(self.did).clean(cx), source: Span::empty(), visibility: self.vis.clean(cx), stability: get_stability(cx, self.did), diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 399702003ea4..c52497dc89bd 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -13,13 +13,13 @@ use rustc_lint; use rustc_driver::{driver, target_features, abort_on_err}; use rustc::dep_graph::DepGraph; use rustc::session::{self, config}; -use rustc::hir::def_id::{CrateNum, DefId}; +use rustc::hir::def_id::DefId; use rustc::hir::def::Def; use rustc::middle::privacy::AccessLevels; use rustc::ty::{self, TyCtxt}; use rustc::hir::map as hir_map; use rustc::lint; -use rustc::util::nodemap::{FnvHashMap, FnvHashSet}; +use rustc::util::nodemap::FnvHashMap; use rustc_trans::back::link; use rustc_resolve as resolve; use rustc_metadata::cstore::CStore; @@ -53,7 +53,7 @@ pub struct DocContext<'a, 'tcx: 'a> { pub map: &'a hir_map::Map<'tcx>, pub maybe_typed: MaybeTyped<'a, 'tcx>, pub input: Input, - pub populated_crate_impls: RefCell>, + pub populated_all_crate_impls: Cell, pub deref_trait_did: Cell>, pub deref_mut_trait_did: Cell>, // Note that external items for which `doc(hidden)` applies to are shown as @@ -205,7 +205,7 @@ pub fn run_core(search_paths: SearchPaths, map: &tcx.map, maybe_typed: Typed(tcx), input: input, - populated_crate_impls: Default::default(), + populated_all_crate_impls: Cell::new(false), deref_trait_did: Cell::new(None), deref_mut_trait_did: Cell::new(None), access_levels: RefCell::new(access_levels), diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 3d2caeda1468..4518945dd985 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -106,8 +106,8 @@ pub fn run(input: &str, map: &map, maybe_typed: core::NotTyped(&sess), input: input, + populated_all_crate_impls: Cell::new(false), external_traits: Default::default(), - populated_crate_impls: Default::default(), deref_trait_did: Cell::new(None), deref_mut_trait_did: Cell::new(None), access_levels: Default::default(), diff --git a/src/librustdoc/visit_lib.rs b/src/librustdoc/visit_lib.rs index cbc556730fb6..da11f652b4b3 100644 --- a/src/librustdoc/visit_lib.rs +++ b/src/librustdoc/visit_lib.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use rustc::middle::cstore::{CrateStore, ChildItem, DefLike}; +use rustc::middle::cstore::{CrateStore, ChildItem}; use rustc::middle::privacy::{AccessLevels, AccessLevel}; use rustc::hir::def::Def; use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId}; @@ -66,39 +66,32 @@ impl<'a, 'b, 'tcx> LibEmbargoVisitor<'a, 'b, 'tcx> { pub fn visit_mod(&mut self, did: DefId) { for item in self.cstore.item_children(did) { - if let DefLike::DlDef(def) = item.def { - match def { - Def::Mod(did) | - Def::ForeignMod(did) | - Def::Trait(did) | - Def::Struct(did) | - Def::Union(did) | - Def::Enum(did) | - Def::TyAlias(did) | - Def::Fn(did) | - Def::Method(did) | - Def::Static(did, _) | - Def::Const(did) => self.visit_item(did, item), - _ => {} - } + match item.def { + Def::Mod(did) | + Def::ForeignMod(did) | + Def::Trait(did) | + Def::Struct(did) | + Def::Union(did) | + Def::Enum(did) | + Def::TyAlias(did) | + Def::Fn(did) | + Def::Method(did) | + Def::Static(did, _) | + Def::Const(did) => self.visit_item(did, item), + _ => {} } } } fn visit_item(&mut self, did: DefId, item: ChildItem) { let inherited_item_level = match item.def { - DefLike::DlImpl(..) | DefLike::DlField => unreachable!(), - DefLike::DlDef(def) => { - match def { - Def::ForeignMod(..) => self.prev_level, - _ => if item.vis == Visibility::Public { self.prev_level } else { None } - } - } + Def::ForeignMod(..) => self.prev_level, + _ => if item.vis == Visibility::Public { self.prev_level } else { None } }; let item_level = self.update(did, inherited_item_level); - if let DefLike::DlDef(Def::Mod(did)) = item.def { + if let Def::Mod(did) = item.def { let orig_level = self.prev_level; self.prev_level = item_level; From 89736e86716808801732323f3aa848b97fc2b5ba Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Mon, 5 Sep 2016 10:54:38 +0300 Subject: [PATCH 420/443] rustc: remove ImplOrTraitItemId and TraitDef's associated_type_names. --- src/librustc/dep_graph/dep_node.rs | 6 +- src/librustc/middle/cstore.rs | 4 +- src/librustc/middle/dead.rs | 7 +-- src/librustc/middle/stability.rs | 7 +-- .../traits/specialize/specialization_graph.rs | 4 +- src/librustc/ty/context.rs | 6 +- src/librustc/ty/maps.rs | 3 +- src/librustc/ty/mod.rs | 55 ++++-------------- src/librustc/ty/trait_def.rs | 7 --- src/librustc_const_eval/eval.rs | 12 ++-- src/librustc_metadata/common.rs | 3 - src/librustc_metadata/csearch.rs | 11 +++- src/librustc_metadata/decoder.rs | 27 +-------- src/librustc_metadata/encoder.rs | 17 +----- src/librustc_resolve/build_reduced_graph.rs | 4 +- src/librustc_save_analysis/lib.rs | 14 ++--- src/librustc_trans/meth.rs | 18 +++--- src/librustc_trans/mir/constant.rs | 12 ++-- src/librustc_typeck/astconv.rs | 27 +++++---- src/librustc_typeck/check/method/mod.rs | 2 +- src/librustc_typeck/check/mod.rs | 8 ++- src/librustc_typeck/coherence/mod.rs | 24 ++------ src/librustc_typeck/coherence/overlap.rs | 22 ++++---- src/librustc_typeck/collect.rs | 56 ++++++++----------- src/librustc_typeck/lib.rs | 1 + src/librustdoc/clean/inline.rs | 6 +- 26 files changed, 130 insertions(+), 233 deletions(-) diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 3cf7548e3209..269f0ebb813c 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -108,7 +108,7 @@ pub enum DepNode { ItemSignature(D), FieldTy(D), SizedConstraint(D), - ImplOrTraitItemIds(D), + ImplOrTraitItemDefIds(D), InherentImpls(D), // The set of impls for a given trait. Ultimately, it would be @@ -157,7 +157,7 @@ impl DepNode { ImplOrTraitItems, ItemSignature, FieldTy, - ImplOrTraitItemIds, + ImplOrTraitItemDefIds, InherentImpls, TraitImpls, ReprHints, @@ -225,7 +225,7 @@ impl DepNode { ItemSignature(ref d) => op(d).map(ItemSignature), FieldTy(ref d) => op(d).map(FieldTy), SizedConstraint(ref d) => op(d).map(SizedConstraint), - ImplOrTraitItemIds(ref d) => op(d).map(ImplOrTraitItemIds), + ImplOrTraitItemDefIds(ref d) => op(d).map(ImplOrTraitItemDefIds), InherentImpls(ref d) => op(d).map(InherentImpls), TraitImpls(ref d) => op(d).map(TraitImpls), TraitItems(ref d) => op(d).map(TraitItems), diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 52cadd76c64c..e844ec37dc7c 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -157,7 +157,7 @@ pub trait CrateStore<'tcx> { fn implementations_of_trait(&self, filter: Option) -> Vec; // impl info - fn impl_or_trait_items(&self, def_id: DefId) -> Vec; + fn impl_or_trait_items(&self, def_id: DefId) -> Vec; fn impl_trait_ref<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> Option>; fn impl_polarity(&self, def: DefId) -> hir::ImplPolarity; @@ -329,7 +329,7 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { } // impl info - fn impl_or_trait_items(&self, def_id: DefId) -> Vec + fn impl_or_trait_items(&self, def_id: DefId) -> Vec { bug!("impl_or_trait_items") } fn impl_trait_ref<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> Option> { bug!("impl_trait_ref") } diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index 2c952e9f8634..70232d4f01e9 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -470,13 +470,12 @@ impl<'a, 'tcx> DeadVisitor<'a, 'tcx> { // This is done to handle the case where, for example, the static // method of a private type is used, but the type itself is never // called directly. - let impl_items = self.tcx.impl_or_trait_item_ids.borrow(); + let impl_items = self.tcx.impl_or_trait_item_def_ids.borrow(); if let Some(impl_list) = self.tcx.inherent_impls.borrow().get(&self.tcx.map.local_def_id(id)) { for impl_did in impl_list.iter() { - for item_did in impl_items.get(impl_did).unwrap().iter() { - if let Some(item_node_id) = - self.tcx.map.as_local_node_id(item_did.def_id()) { + for &item_did in &impl_items[impl_did][..] { + if let Some(item_node_id) = self.tcx.map.as_local_node_id(item_did) { if self.live_symbols.contains(&item_node_id) { return true; } diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index e2b997ed60f2..2c768db47f11 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -695,10 +695,9 @@ fn is_internal<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, span: Span) -> bool { fn is_staged_api<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefId) -> bool { match tcx.trait_item_of_item(id) { - Some(ty::MethodTraitItemId(trait_method_id)) - if trait_method_id != id => { - is_staged_api(tcx, trait_method_id) - } + Some(trait_method_id) if trait_method_id != id => { + is_staged_api(tcx, trait_method_id) + } _ => { *tcx.stability.borrow_mut().staged_api.entry(id.krate).or_insert_with( || tcx.sess.cstore.is_staged_api(id.krate)) diff --git a/src/librustc/traits/specialize/specialization_graph.rs b/src/librustc/traits/specialize/specialization_graph.rs index 4339b1a254f2..1374719ef49c 100644 --- a/src/librustc/traits/specialize/specialization_graph.rs +++ b/src/librustc/traits/specialize/specialization_graph.rs @@ -304,7 +304,7 @@ impl<'a, 'gcx, 'tcx> Node { /// An iterator over the items defined within a trait or impl. pub struct NodeItems<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, - items: Rc>, + items: Rc>, idx: usize } @@ -312,7 +312,7 @@ impl<'a, 'tcx> Iterator for NodeItems<'a, 'tcx> { type Item = ImplOrTraitItem<'tcx>; fn next(&mut self) -> Option> { if self.idx < self.items.len() { - let item_def_id = self.items[self.idx].def_id(); + let item_def_id = self.items[self.idx]; let items_table = self.tcx.impl_or_trait_items.borrow(); let item = items_table[&item_def_id].clone(); self.idx += 1; diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 0d6beb34c690..1c9238646df2 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -331,7 +331,7 @@ pub struct GlobalCtxt<'tcx> { pub impl_or_trait_items: RefCell>>, /// Maps from an impl/trait def-id to a list of the def-ids of its items - pub impl_or_trait_item_ids: RefCell>>, + pub impl_or_trait_item_def_ids: RefCell>>, /// A cache for the trait_items() routine; note that the routine /// itself pushes the `TraitItems` dependency node. @@ -728,7 +728,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { rcache: RefCell::new(FnvHashMap()), tc_cache: RefCell::new(FnvHashMap()), impl_or_trait_items: RefCell::new(DepTrackingMap::new(dep_graph.clone())), - impl_or_trait_item_ids: RefCell::new(DepTrackingMap::new(dep_graph.clone())), + impl_or_trait_item_def_ids: RefCell::new(DepTrackingMap::new(dep_graph.clone())), trait_items_cache: RefCell::new(DepTrackingMap::new(dep_graph.clone())), ty_param_defs: RefCell::new(NodeMap()), normalized_cache: RefCell::new(FnvHashMap()), @@ -1396,7 +1396,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.trait_items_cache.memoize(trait_did, || { let def_ids = self.impl_or_trait_items(trait_did); Rc::new(def_ids.iter() - .map(|d| self.impl_or_trait_item(d.def_id())) + .map(|&def_id| self.impl_or_trait_item(def_id)) .collect()) }) } diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index 5e029cf98dc6..3a552a8b437d 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -34,8 +34,7 @@ dep_map_ty! { Tcache: ItemSignature(DefId) -> Ty<'tcx> } dep_map_ty! { Generics: ItemSignature(DefId) -> &'tcx ty::Generics<'tcx> } dep_map_ty! { Predicates: ItemSignature(DefId) -> ty::GenericPredicates<'tcx> } dep_map_ty! { SuperPredicates: ItemSignature(DefId) -> ty::GenericPredicates<'tcx> } -dep_map_ty! { ImplOrTraitItemIds: ImplOrTraitItemIds(DefId) - -> Rc> } +dep_map_ty! { ImplOrTraitItemDefIds: ImplOrTraitItemDefIds(DefId) -> Rc> } dep_map_ty! { ImplTraitRefs: ItemSignature(DefId) -> Option> } dep_map_ty! { TraitDefs: ItemSignature(DefId) -> &'tcx ty::TraitDef<'tcx> } dep_map_ty! { AdtDefs: ItemSignature(DefId) -> ty::AdtDefMaster<'tcx> } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 3eb9f8593e3a..8aba6329b090 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -pub use self::ImplOrTraitItemId::*; pub use self::Variance::*; pub use self::DtorKind::*; pub use self::ImplOrTraitItemContainer::*; @@ -190,18 +189,6 @@ pub enum ImplOrTraitItem<'tcx> { } impl<'tcx> ImplOrTraitItem<'tcx> { - fn id(&self) -> ImplOrTraitItemId { - match *self { - ConstTraitItem(ref associated_const) => { - ConstTraitItemId(associated_const.def_id) - } - MethodTraitItem(ref method) => MethodTraitItemId(method.def_id), - TypeTraitItem(ref associated_type) => { - TypeTraitItemId(associated_type.def_id) - } - } - } - pub fn def(&self) -> Def { match *self { ConstTraitItem(ref associated_const) => Def::AssociatedConst(associated_const.def_id), @@ -250,23 +237,6 @@ impl<'tcx> ImplOrTraitItem<'tcx> { } } -#[derive(Clone, Copy, Debug, RustcEncodable, RustcDecodable)] -pub enum ImplOrTraitItemId { - ConstTraitItemId(DefId), - MethodTraitItemId(DefId), - TypeTraitItemId(DefId), -} - -impl ImplOrTraitItemId { - pub fn def_id(&self) -> DefId { - match *self { - ConstTraitItemId(def_id) => def_id, - MethodTraitItemId(def_id) => def_id, - TypeTraitItemId(def_id) => def_id, - } - } -} - #[derive(Clone, Debug, PartialEq, Eq, Copy, RustcEncodable, RustcDecodable)] pub enum Visibility { /// Visible everywhere (including in other crates). @@ -2276,8 +2246,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } pub fn provided_trait_methods(self, id: DefId) -> Vec>> { - self.impl_or_trait_items(id).iter().filter_map(|id| { - match self.impl_or_trait_item(id.def_id()) { + self.impl_or_trait_items(id).iter().filter_map(|&def_id| { + match self.impl_or_trait_item(def_id) { MethodTraitItem(ref m) if m.has_body => Some(m.clone()), _ => None } @@ -2321,9 +2291,9 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { .expect("missing ImplOrTraitItem in metadata")) } - pub fn impl_or_trait_items(self, id: DefId) -> Rc> { + pub fn impl_or_trait_items(self, id: DefId) -> Rc> { lookup_locally_or_in_crate_store( - "impl_or_trait_items", id, &self.impl_or_trait_item_ids, + "impl_or_trait_items", id, &self.impl_or_trait_item_def_ids, || Rc::new(self.sess.cstore.impl_or_trait_items(id))) } @@ -2600,7 +2570,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { let impl_items = self.sess.cstore.impl_or_trait_items(primitive_def_id); // Store the implementation info. - self.impl_or_trait_item_ids.borrow_mut().insert(primitive_def_id, Rc::new(impl_items)); + self.impl_or_trait_item_def_ids.borrow_mut().insert(primitive_def_id, Rc::new(impl_items)); self.populated_external_primitive_impls.borrow_mut().insert(primitive_def_id); } @@ -2627,7 +2597,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { for &impl_def_id in &inherent_impls { // Store the implementation info. let impl_items = self.sess.cstore.impl_or_trait_items(impl_def_id); - self.impl_or_trait_item_ids.borrow_mut().insert(impl_def_id, Rc::new(impl_items)); + self.impl_or_trait_item_def_ids.borrow_mut().insert(impl_def_id, Rc::new(impl_items)); } self.inherent_impls.borrow_mut().insert(type_id, inherent_impls); @@ -2669,15 +2639,14 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // For any methods that use a default implementation, add them to // the map. This is a bit unfortunate. - for impl_item_def_id in &impl_items { - let method_def_id = impl_item_def_id.def_id(); + for &impl_item_def_id in &impl_items { // load impl items eagerly for convenience // FIXME: we may want to load these lazily - self.impl_or_trait_item(method_def_id); + self.impl_or_trait_item(impl_item_def_id); } // Store the implementation info. - self.impl_or_trait_item_ids.borrow_mut().insert(impl_def_id, Rc::new(impl_items)); + self.impl_or_trait_item_def_ids.borrow_mut().insert(impl_def_id, Rc::new(impl_items)); } def.flags.set(def.flags.get() | TraitFlags::IMPLS_VALID); @@ -2766,19 +2735,19 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// is already that of the original trait method, then the return value is /// the same). /// Otherwise, return `None`. - pub fn trait_item_of_item(self, def_id: DefId) -> Option { + pub fn trait_item_of_item(self, def_id: DefId) -> Option { let impl_or_trait_item = match self.impl_or_trait_items.borrow().get(&def_id) { Some(m) => m.clone(), None => return None, }; match impl_or_trait_item.container() { - TraitContainer(_) => Some(impl_or_trait_item.id()), + TraitContainer(_) => Some(impl_or_trait_item.def_id()), ImplContainer(def_id) => { self.trait_id_of_impl(def_id).and_then(|trait_did| { let name = impl_or_trait_item.name(); self.trait_items(trait_did).iter() .find(|item| item.name() == name) - .map(|item| item.id()) + .map(|item| item.def_id()) }) } } diff --git a/src/librustc/ty/trait_def.rs b/src/librustc/ty/trait_def.rs index 268b2fcaa4ad..3ff2ed76e571 100644 --- a/src/librustc/ty/trait_def.rs +++ b/src/librustc/ty/trait_def.rs @@ -15,7 +15,6 @@ use ty; use ty::fast_reject; use ty::{Ty, TyCtxt, TraitRef}; use std::cell::{Cell, RefCell}; -use syntax::ast::Name; use hir; use util::nodemap::FnvHashMap; @@ -38,10 +37,6 @@ pub struct TraitDef<'tcx> { pub trait_ref: ty::TraitRef<'tcx>, - /// A list of the associated types defined in this trait. Useful - /// for resolving `X::Foo` type markers. - pub associated_type_names: Vec, - // Impls of a trait. To allow for quicker lookup, the impls are indexed by a // simplified version of their `Self` type: impls with a simplifiable `Self` // are stored in `nonblanket_impls` keyed by it, while all other impls are @@ -82,7 +77,6 @@ impl<'a, 'gcx, 'tcx> TraitDef<'tcx> { paren_sugar: bool, generics: &'tcx ty::Generics<'tcx>, trait_ref: ty::TraitRef<'tcx>, - associated_type_names: Vec, def_path_hash: u64) -> TraitDef<'tcx> { TraitDef { @@ -90,7 +84,6 @@ impl<'a, 'gcx, 'tcx> TraitDef<'tcx> { unsafety: unsafety, generics: generics, trait_ref: trait_ref, - associated_type_names: associated_type_names, nonblanket_impls: RefCell::new(FnvHashMap()), blanket_impls: RefCell::new(vec![]), flags: Cell::new(ty::TraitFlags::NO_TRAIT_FLAGS), diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index fe3c498d184b..aa53fdd6e7e2 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -1081,16 +1081,14 @@ fn resolve_trait_associated_const<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, match selection { traits::VtableImpl(ref impl_data) => { let ac = tcx.impl_or_trait_items(impl_data.impl_def_id) - .iter().filter_map(|id| { - match *id { - ty::ConstTraitItemId(def_id) => { - Some(tcx.impl_or_trait_item(def_id)) - } + .iter().filter_map(|&def_id| { + match tcx.impl_or_trait_item(def_id) { + ty::ConstTraitItem(ic) => Some(ic), _ => None } - }).find(|ic| ic.name() == ti.name); + }).find(|ic| ic.name == ti.name); match ac { - Some(ic) => lookup_const_by_id(tcx, ic.def_id(), None), + Some(ic) => lookup_const_by_id(tcx, ic.def_id, None), None => match ti.node { hir::ConstTraitItem(ref ty, Some(ref expr)) => { Some((&*expr, tcx.ast_ty_to_prim_ty(ty))) diff --git a/src/librustc_metadata/common.rs b/src/librustc_metadata/common.rs index 94581a3fc897..6df8c7de415a 100644 --- a/src/librustc_metadata/common.rs +++ b/src/librustc_metadata/common.rs @@ -166,9 +166,6 @@ pub const tag_item_predicates: usize = 0x95; pub const tag_unsafety: usize = 0x9a; -pub const tag_associated_type_names: usize = 0x9b; -pub const tag_associated_type_name: usize = 0x9c; - pub const tag_polarity: usize = 0x9d; pub const tag_macro_defs: usize = 0x10e; // top-level only diff --git a/src/librustc_metadata/csearch.rs b/src/librustc_metadata/csearch.rs index 38b18fa63e3e..c4ce7af269da 100644 --- a/src/librustc_metadata/csearch.rs +++ b/src/librustc_metadata/csearch.rs @@ -179,10 +179,15 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { result } - fn impl_or_trait_items(&self, def_id: DefId) -> Vec { + fn impl_or_trait_items(&self, def_id: DefId) -> Vec { self.dep_graph.read(DepNode::MetaData(def_id)); - let cdata = self.get_crate_data(def_id.krate); - decoder::get_impl_or_trait_items(&cdata, def_id.index) + let mut result = vec![]; + let crate_data = self.get_crate_data(def_id.krate); + let get_crate_data = |cnum| self.get_crate_data(cnum); + decoder::each_child_of_item(&crate_data, def_id.index, get_crate_data, |def, _, _| { + result.push(def.def_id()); + }); + result } fn impl_polarity(&self, def: DefId) -> hir::ImplPolarity diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 507e6414181b..8b87f0e718fb 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -453,10 +453,6 @@ fn item_to_def(cdata: Cmd, item: rbml::Doc, did: DefId) -> Option { }) } -fn parse_associated_type_names(item_doc: rbml::Doc) -> Vec { - item_doc.get(tag_associated_type_names).decoder().decode() -} - pub fn get_trait_def<'a, 'tcx>(cdata: Cmd, item_id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> ty::TraitDef<'tcx> @@ -464,16 +460,11 @@ pub fn get_trait_def<'a, 'tcx>(cdata: Cmd, let item_doc = cdata.lookup_item(item_id); let generics = doc_generics(item_doc, tcx, cdata); let unsafety = item_doc.get(tag_unsafety).decoder().decode(); - let associated_type_names = parse_associated_type_names(item_doc); let paren_sugar = item_doc.get(tag_paren_sugar).decoder().decode(); let trait_ref = doc_trait_ref(item_doc.get(tag_item_trait_ref), tcx, cdata); let def_path = def_path(cdata, item_id).unwrap(); - ty::TraitDef::new(unsafety, - paren_sugar, - generics, - trait_ref, - associated_type_names, + ty::TraitDef::new(unsafety, paren_sugar, generics, trait_ref, def_path.deterministic_hash(tcx)) } @@ -855,22 +846,6 @@ fn get_explicit_self<'a, 'tcx>(cdata: Cmd, item: rbml::Doc, tcx: TyCtxt<'a, 'tcx dcx.decode() } -/// Returns the def IDs of all the items in the given implementation. -pub fn get_impl_or_trait_items(cdata: Cmd, impl_id: DefIndex) - -> Vec { - let item = cdata.lookup_item(impl_id); - let mut dcx = item.get(tag_mod_children).decoder(); - dcx.cdata = Some(cdata); - dcx.seq().map(|def_id: DefId| { - match item_to_def(cdata, cdata.lookup_item(def_id.index), def_id) { - Some(Def::AssociatedConst(def_id)) => ty::ConstTraitItemId(def_id), - Some(Def::Method(def_id)) => ty::MethodTraitItemId(def_id), - Some(Def::AssociatedTy(_, def_id)) => ty::TypeTraitItemId(def_id), - def => bug!("get_impl_or_trait_items: invalid def {:?}", def) - } - }).collect() -} - pub fn get_trait_name(cdata: Cmd, id: DefIndex) -> ast::Name { let doc = cdata.lookup_item(id); item_name(doc) diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 7b4a6972d221..326eb0fe9a3a 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -993,8 +993,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } self.start_tag(tag_mod_children); - let items = tcx.impl_or_trait_items(def_id); - self.seq(&items[..], |_, id| id.def_id()); + tcx.impl_or_trait_items(def_id).encode(self).unwrap(); <[def::Export]>::encode(&[], self).unwrap(); self.end_tag(); @@ -1039,7 +1038,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { tcx.trait_has_default_impl(def_id).encode(self).unwrap(); self.end_tag(); - encode_associated_type_names(self, &trait_def.associated_type_names); self.encode_generics(&trait_def.generics, &trait_predicates); self.encode_predicates(&tcx.lookup_super_predicates(def_id), tag_item_super_predicates); @@ -1051,8 +1049,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { encode_deprecation(self, depr); self.start_tag(tag_mod_children); - let items = tcx.impl_or_trait_items(def_id); - self.seq(&items[..], |_, id| id.def_id()); + tcx.impl_or_trait_items(def_id).encode(self).unwrap(); <[def::Export]>::encode(&[], self).unwrap(); self.end_tag(); @@ -1151,7 +1148,6 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { None }; - let trait_item_def_id = trait_item_def_id.def_id(); self.record(trait_item_def_id, EncodeContext::encode_info_for_impl_item, (impl_id, trait_item_def_id, ast_item)); @@ -1163,8 +1159,7 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { trait_items: &[hir::TraitItem]) { // Now output the trait item info for each trait item. let r = self.tcx.impl_or_trait_items(def_id); - for (item_def_id, trait_item) in r.iter().zip(trait_items) { - let item_def_id = item_def_id.def_id(); + for (&item_def_id, trait_item) in r.iter().zip(trait_items) { assert!(item_def_id.is_local()); self.record(item_def_id, EncodeContext::encode_info_for_trait_item, @@ -1331,12 +1326,6 @@ fn encode_attributes(ecx: &mut EncodeContext, attrs: &[ast::Attribute]) { ecx.end_tag(); } -fn encode_associated_type_names(ecx: &mut EncodeContext, names: &[Name]) { - ecx.start_tag(tag_associated_type_names); - names.encode(ecx).unwrap(); - ecx.end_tag(); -} - fn encode_crate_deps(ecx: &mut EncodeContext, cstore: &cstore::CStore) { fn get_ordered_deps(cstore: &cstore::CStore) -> Vec<(CrateNum, Rc)> { diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 3df3a2decba3..7264dcea9553 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -432,9 +432,9 @@ impl<'b> Resolver<'b> { // info. let trait_item_def_ids = self.session.cstore.impl_or_trait_items(def_id); - for trait_item_def in &trait_item_def_ids { + for &trait_item_def in &trait_item_def_ids { let trait_item_name = - self.session.cstore.item_name(trait_item_def.def_id()); + self.session.cstore.item_name(trait_item_def); debug!("(building reduced graph for external crate) ... adding trait item \ '{}'", diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 186183a8ad4d..aa68a873120e 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -374,8 +374,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { let qualname = format!("{}::{}", qualname, name); let def_id = self.tcx.map.local_def_id(id); - let decl_id = self.tcx.trait_item_of_item(def_id).and_then(|new_id| { - let new_def_id = new_id.def_id(); + let decl_id = self.tcx.trait_item_of_item(def_id).and_then(|new_def_id| { if new_def_id != def_id { Some(new_def_id) } else { @@ -543,14 +542,9 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { .map(|mr| mr.def_id()) } ty::ImplContainer(def_id) => { - let impl_items = self.tcx.impl_or_trait_items(def_id); - Some(impl_items.iter() - .find(|mr| { - self.tcx.impl_or_trait_item(mr.def_id()).name() == - ti.name() - }) - .unwrap() - .def_id()) + Some(*self.tcx.impl_or_trait_items(def_id).iter().find(|&&mr| { + self.tcx.impl_or_trait_item(mr).name() == ti.name() + }).unwrap()) } } } else { diff --git a/src/librustc_trans/meth.rs b/src/librustc_trans/meth.rs index 9db5020747e1..8540c7a99db1 100644 --- a/src/librustc_trans/meth.rs +++ b/src/librustc_trans/meth.rs @@ -235,24 +235,20 @@ pub fn get_vtable_methods<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, .iter() // Filter out non-method items. - .filter_map(|item_def_id| { - match *item_def_id { - ty::MethodTraitItemId(def_id) => Some(def_id), - _ => None, + .filter_map(|&item_def_id| { + match tcx.impl_or_trait_item(item_def_id) { + ty::MethodTraitItem(m) => Some(m), + _ => None } }) // Now produce pointers for each remaining method. If the // method could never be called from this object, just supply // null. - .map(|trait_method_def_id| { + .map(|trait_method_type| { debug!("get_vtable_methods: trait_method_def_id={:?}", - trait_method_def_id); + trait_method_type.def_id); - let trait_method_type = match tcx.impl_or_trait_item(trait_method_def_id) { - ty::MethodTraitItem(m) => m, - _ => bug!("should be a method, not other assoc item"), - }; let name = trait_method_type.name; // Some methods cannot be called on an object; skip those. @@ -266,7 +262,7 @@ pub fn get_vtable_methods<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // the method may have some early-bound lifetimes, add // regions for those - let method_substs = Substs::for_item(tcx, trait_method_def_id, + let method_substs = Substs::for_item(tcx, trait_method_type.def_id, |_, _| tcx.mk_region(ty::ReErased), |_, _| tcx.types.err); diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index 999433db2407..cad5ed4f2e65 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -248,16 +248,14 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> { if let traits::VtableImpl(vtable_impl) = vtable { let name = ccx.tcx().item_name(instance.def); let ac = ccx.tcx().impl_or_trait_items(vtable_impl.impl_def_id) - .iter().filter_map(|id| { - match *id { - ty::ConstTraitItemId(def_id) => { - Some(ccx.tcx().impl_or_trait_item(def_id)) - } + .iter().filter_map(|&def_id| { + match ccx.tcx().impl_or_trait_item(def_id) { + ty::ConstTraitItem(ac) => Some(ac), _ => None } - }).find(|ic| ic.name() == name); + }).find(|ic| ic.name == name); if let Some(ac) = ac { - instance = Instance::new(ac.def_id(), vtable_impl.substs); + instance = Instance::new(ac.def_id, vtable_impl.substs); } } } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 675c863a3bf0..00c9ea3af182 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1134,16 +1134,23 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { return tcx.types.err; } - let mut associated_types: FnvHashSet<(DefId, ast::Name)> = - traits::supertraits(tcx, principal) - .flat_map(|tr| { - let trait_def = tcx.lookup_trait_def(tr.def_id()); - trait_def.associated_type_names - .clone() - .into_iter() - .map(move |associated_type_name| (tr.def_id(), associated_type_name)) - }) - .collect(); + let mut associated_types = FnvHashSet::default(); + for tr in traits::supertraits(tcx, principal) { + if let Some(trait_id) = tcx.map.as_local_node_id(tr.def_id()) { + use collect::trait_associated_type_names; + + associated_types.extend(trait_associated_type_names(tcx, trait_id) + .map(|name| (tr.def_id(), name))) + } else { + let trait_items = tcx.impl_or_trait_items(tr.def_id()); + associated_types.extend(trait_items.iter().filter_map(|&def_id| { + match tcx.impl_or_trait_item(def_id) { + ty::TypeTraitItem(ref item) => Some(item.name), + _ => None + } + }).map(|name| (tr.def_id(), name))); + } + } for projection_bound in &projection_bounds { let pair = (projection_bound.0.projection_ty.trait_ref.def_id, diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index 71219d82668e..73caf79c9f8d 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -368,7 +368,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { { self.tcx.impl_or_trait_items(def_id) .iter() - .map(|&did| self.tcx.impl_or_trait_item(did.def_id())) + .map(|&did| self.tcx.impl_or_trait_item(did)) .find(|m| m.name() == item_name) } } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 8d9fd523a8f5..3a854da1d480 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1348,8 +1348,12 @@ impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> { assoc_name: ast::Name) -> bool { - let trait_def = self.tcx().lookup_trait_def(trait_def_id); - trait_def.associated_type_names.contains(&assoc_name) + self.tcx().impl_or_trait_items(trait_def_id).iter().any(|&def_id| { + match self.tcx().impl_or_trait_item(def_id) { + ty::TypeTraitItem(ref item) => item.name == assoc_name, + _ => false + } + }) } fn ty_infer(&self, _span: Span) -> Ty<'tcx> { diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index fb077d279c99..3b4c98fc71e4 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -20,8 +20,7 @@ use middle::lang_items::UnsizeTraitLangItem; use rustc::ty::subst::Subst; use rustc::ty::{self, TyCtxt, TypeFoldable}; use rustc::traits::{self, Reveal}; -use rustc::ty::{ImplOrTraitItemId, ConstTraitItemId}; -use rustc::ty::{MethodTraitItemId, TypeTraitItemId, ParameterEnvironment}; +use rustc::ty::{ParameterEnvironment}; use rustc::ty::{Ty, TyBool, TyChar, TyError}; use rustc::ty::{TyParam, TyRawPtr}; use rustc::ty::{TyRef, TyAdt, TyTrait, TyNever, TyTuple}; @@ -158,7 +157,7 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { } } - tcx.impl_or_trait_item_ids.borrow_mut().insert(impl_did, Rc::new(impl_items)); + tcx.impl_or_trait_item_def_ids.borrow_mut().insert(impl_did, Rc::new(impl_items)); } fn add_inherent_impl(&self, base_def_id: DefId, impl_def_id: DefId) { @@ -174,22 +173,11 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { } // Converts an implementation in the AST to a vector of items. - fn create_impl_from_item(&self, item: &Item) -> Vec { + fn create_impl_from_item(&self, item: &Item) -> Vec { match item.node { ItemImpl(.., ref impl_items) => { impl_items.iter().map(|impl_item| { - let impl_def_id = self.crate_context.tcx.map.local_def_id(impl_item.id); - match impl_item.node { - hir::ImplItemKind::Const(..) => { - ConstTraitItemId(impl_def_id) - } - hir::ImplItemKind::Method(..) => { - MethodTraitItemId(impl_def_id) - } - hir::ImplItemKind::Type(_) => { - TypeTraitItemId(impl_def_id) - } - } + self.crate_context.tcx.map.local_def_id(impl_item.id) }).collect() } _ => { @@ -210,7 +198,7 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { tcx.populate_implementations_for_trait_if_necessary(drop_trait); let drop_trait = tcx.lookup_trait_def(drop_trait); - let impl_items = tcx.impl_or_trait_item_ids.borrow(); + let impl_items = tcx.impl_or_trait_item_def_ids.borrow(); drop_trait.for_each_impl(tcx, |impl_did| { let items = impl_items.get(&impl_did).unwrap(); @@ -223,7 +211,7 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { let self_type = tcx.lookup_item_type(impl_did); match self_type.ty.sty { ty::TyAdt(type_def, _) => { - type_def.set_destructor(method_def_id.def_id()); + type_def.set_destructor(method_def_id); } _ => { // Destructors only work on nominal types. diff --git a/src/librustc_typeck/coherence/overlap.rs b/src/librustc_typeck/coherence/overlap.rs index 9d072491cc28..c42b8f884002 100644 --- a/src/librustc_typeck/coherence/overlap.rs +++ b/src/librustc_typeck/coherence/overlap.rs @@ -44,29 +44,29 @@ impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> { enum Namespace { Type, Value } fn name_and_namespace<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - item: &ty::ImplOrTraitItemId) + def_id: DefId) -> (ast::Name, Namespace) { - let name = tcx.impl_or_trait_item(item.def_id()).name(); - (name, match *item { - ty::TypeTraitItemId(..) => Namespace::Type, - ty::ConstTraitItemId(..) => Namespace::Value, - ty::MethodTraitItemId(..) => Namespace::Value, + let item = tcx.impl_or_trait_item(def_id); + (item.name(), match item { + ty::TypeTraitItem(..) => Namespace::Type, + ty::ConstTraitItem(..) => Namespace::Value, + ty::MethodTraitItem(..) => Namespace::Value, }) } - let impl_items = self.tcx.impl_or_trait_item_ids.borrow(); + let impl_items = self.tcx.impl_or_trait_item_def_ids.borrow(); - for item1 in &impl_items[&impl1][..] { + for &item1 in &impl_items[&impl1][..] { let (name, namespace) = name_and_namespace(self.tcx, item1); - for item2 in &impl_items[&impl2][..] { + for &item2 in &impl_items[&impl2][..] { if (name, namespace) == name_and_namespace(self.tcx, item2) { let msg = format!("duplicate definitions with name `{}`", name); - let node_id = self.tcx.map.as_local_node_id(item1.def_id()).unwrap(); + let node_id = self.tcx.map.as_local_node_id(item1).unwrap(); self.tcx.sess.add_lint(lint::builtin::OVERLAPPING_INHERENT_IMPLS, node_id, - self.tcx.span_of_impl(item1.def_id()).unwrap(), + self.tcx.span_of_impl(item1).unwrap(), msg); } } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index fa052bec7be3..d67dcbb4baf0 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -361,10 +361,15 @@ impl<'a, 'tcx> AstConv<'tcx, 'tcx> for ItemCtxt<'a, 'tcx> { -> bool { if let Some(trait_id) = self.tcx().map.as_local_node_id(trait_def_id) { - trait_defines_associated_type_named(self.ccx, trait_id, assoc_name) + trait_associated_type_names(self.tcx(), trait_id) + .any(|name| name == assoc_name) } else { - let trait_def = self.tcx().lookup_trait_def(trait_def_id); - trait_def.associated_type_names.contains(&assoc_name) + self.tcx().impl_or_trait_items(trait_def_id).iter().any(|&def_id| { + match self.tcx().impl_or_trait_item(def_id) { + ty::TypeTraitItem(ref item) => item.name == assoc_name, + _ => false + } + }) } } @@ -926,15 +931,10 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { // Add an entry mapping let trait_item_def_ids = Rc::new(trait_items.iter().map(|trait_item| { - let def_id = ccx.tcx.map.local_def_id(trait_item.id); - match trait_item.node { - hir::ConstTraitItem(..) => ty::ConstTraitItemId(def_id), - hir::MethodTraitItem(..) => ty::MethodTraitItemId(def_id), - hir::TypeTraitItem(..) => ty::TypeTraitItemId(def_id) - } + ccx.tcx.map.local_def_id(trait_item.id) }).collect()); - tcx.impl_or_trait_item_ids.borrow_mut().insert(ccx.tcx.map.local_def_id(it.id), - trait_item_def_ids); + tcx.impl_or_trait_item_def_ids.borrow_mut().insert(ccx.tcx.map.local_def_id(it.id), + trait_item_def_ids); }, hir::ItemStruct(ref struct_def, _) | hir::ItemUnion(ref struct_def, _) => { @@ -1266,9 +1266,9 @@ fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, return def.clone(); } - let (unsafety, generics, items) = match it.node { - hir::ItemTrait(unsafety, ref generics, _, ref items) => { - (unsafety, generics, items) + let (unsafety, generics) = match it.node { + hir::ItemTrait(unsafety, ref generics, _, _) => { + (unsafety, generics) } _ => span_bug!(it.span, "trait_def_of_item invoked on non-trait"), }; @@ -1288,32 +1288,20 @@ fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let ty_generics = generics_of_def_id(ccx, def_id); let substs = mk_item_substs(&ccx.icx(generics), it.span, def_id); - let associated_type_names: Vec<_> = items.iter().filter_map(|trait_item| { - match trait_item.node { - hir::TypeTraitItem(..) => Some(trait_item.name), - _ => None, - } - }).collect(); - let def_path_hash = tcx.def_path(def_id).deterministic_hash(tcx); let trait_ref = ty::TraitRef::new(def_id, substs); - let trait_def = ty::TraitDef::new(unsafety, - paren_sugar, - ty_generics, - trait_ref, - associated_type_names, + let trait_def = ty::TraitDef::new(unsafety, paren_sugar, ty_generics, trait_ref, def_path_hash); tcx.intern_trait_def(trait_def) } -fn trait_defines_associated_type_named(ccx: &CrateCtxt, - trait_node_id: ast::NodeId, - assoc_name: ast::Name) - -> bool +pub fn trait_associated_type_names<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, + trait_node_id: ast::NodeId) + -> impl Iterator + 'a { - let item = match ccx.tcx.map.get(trait_node_id) { + let item = match tcx.map.get(trait_node_id) { hir_map::NodeItem(item) => item, _ => bug!("trait_node_id {} is not an item", trait_node_id) }; @@ -1323,10 +1311,10 @@ fn trait_defines_associated_type_named(ccx: &CrateCtxt, _ => bug!("trait_node_id {} is not a trait", trait_node_id) }; - trait_items.iter().any(|trait_item| { + trait_items.iter().filter_map(|trait_item| { match trait_item.node { - hir::TypeTraitItem(..) => trait_item.name == assoc_name, - _ => false, + hir::TypeTraitItem(..) => Some(trait_item.name), + _ => None, } }) } diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index d2e2d578fced..1f34cee5143c 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -76,6 +76,7 @@ This API is completely unstable and subject to change. #![feature(box_patterns)] #![feature(box_syntax)] +#![feature(conservative_impl_trait)] #![feature(dotdot_in_tuple_patterns)] #![feature(quote)] #![feature(rustc_diagnostic_macros)] diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index e992861b77bc..e72ea60072e0 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -368,10 +368,8 @@ pub fn build_impl<'a, 'tcx>(cx: &DocContext, let predicates = tcx.lookup_predicates(did); let trait_items = tcx.sess.cstore.impl_or_trait_items(did) .iter() - .filter_map(|did| { - let did = did.def_id(); - let impl_item = tcx.impl_or_trait_item(did); - match impl_item { + .filter_map(|&did| { + match tcx.impl_or_trait_item(did) { ty::ConstTraitItem(ref assoc_const) => { let did = assoc_const.def_id; let type_scheme = tcx.lookup_item_type(did); From d2ea3daad1372cffa5caf9f20fe36667e334662b Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Mon, 5 Sep 2016 12:18:45 +0300 Subject: [PATCH 421/443] rustc_metadata: group the tags into root tags and item tags. --- src/librustc_metadata/astencode.rs | 2 +- src/librustc_metadata/common.rs | 226 +++++++------------------ src/librustc_metadata/decoder.rs | 151 ++++++++--------- src/librustc_metadata/encoder.rs | 134 ++++++++------- src/librustc_metadata/index_builder.rs | 4 +- 5 files changed, 205 insertions(+), 312 deletions(-) diff --git a/src/librustc_metadata/astencode.rs b/src/librustc_metadata/astencode.rs index f00c4b82a851..9d4ed84993f1 100644 --- a/src/librustc_metadata/astencode.rs +++ b/src/librustc_metadata/astencode.rs @@ -33,7 +33,7 @@ use rustc_serialize::{Decodable, Encodable}; // Top-level methods. pub fn encode_inlined_item(ecx: &mut EncodeContext, ii: InlinedItemRef) { - ecx.tag(::common::tag_ast, |ecx| { + ecx.tag(::common::item_tag::ast, |ecx| { let mut visitor = IdRangeComputingVisitor::new(); match ii { InlinedItemRef::Item(_, i) => visitor.visit_item(i), diff --git a/src/librustc_metadata/common.rs b/src/librustc_metadata/common.rs index 6df8c7de415a..04b9b7f7c671 100644 --- a/src/librustc_metadata/common.rs +++ b/src/librustc_metadata/common.rs @@ -35,164 +35,12 @@ pub enum Family { AssociatedConst, } -// GAP 0x00...0x19 - -pub const tag_items: usize = 0x100; // top-level only - -pub const tag_paths_data_name: usize = 0x20; - -pub const tag_def_index: usize = 0x21; - -pub const tag_items_data: usize = 0x22; - -pub const tag_items_data_item: usize = 0x23; - -pub const tag_items_data_item_family: usize = 0x24; - -pub const tag_items_data_item_type: usize = 0x25; - -// GAP 0x26, 0x27 - -pub const tag_items_data_parent_item: usize = 0x28; - -pub const tag_items_data_item_is_tuple_struct_ctor: usize = 0x29; - -pub const tag_items_closure_kind: usize = 0x2a; -pub const tag_items_closure_ty: usize = 0x2b; -pub const tag_def_key: usize = 0x2c; - -// GAP 0x2d 0x34 - -pub const tag_index: usize = 0x110; // top-level only -pub const tag_xref_index: usize = 0x111; // top-level only -pub const tag_xref_data: usize = 0x112; // top-level only -pub const tag_attributes: usize = 0x101; // top-level only - -// The list of crates that this crate depends on -pub const tag_crate_deps: usize = 0x102; // top-level only -pub const tag_crate_hash: usize = 0x103; // top-level only -pub const tag_crate_crate_name: usize = 0x104; // top-level only -pub const tag_crate_disambiguator: usize = 0x113; // top-level only - -// GAP 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a - -pub const tag_item_trait_ref: usize = 0x3b; - -// discriminator value for variants -pub const tag_disr_val: usize = 0x3c; - -// GAP 0x3d, 0x3e, 0x3f, 0x40 - -pub const tag_item_fields: usize = 0x41; -// GAP 0x42 -pub const tag_item_variances: usize = 0x43; -// GAP 0x44 -pub const tag_item_trait_method_explicit_self: usize = 0x45; - -// GAP 0x46, 0x47, 0x48 - -// used to encode crate_ctxt side tables -pub const tag_ast: usize = 0x50; - -// GAP 0x51 - -pub const tag_mir: usize = 0x52; - -// GAP 0x53...0x6a - -pub const tag_item_trait_item_has_body: usize = 0x70; - -pub const tag_crate_triple: usize = 0x105; // top-level only - -pub const tag_dylib_dependency_formats: usize = 0x106; // top-level only - -pub const tag_lang_items: usize = 0x107; // top-level only - -// GAP 0x73, 0x74, 0x75 - -pub const tag_lang_items_missing: usize = 0x76; // top-level only - -// GAP 0x77 - -pub const tag_items_data_item_visibility: usize = 0x78; -pub const tag_items_data_item_inherent_impls: usize = 0x79; - -// GAP 0x7a +// NB: increment this if you change the format of metadata such that +// rustc_version can't be found. +pub const metadata_encoding_version : &'static [u8] = &[b'r', b'u', b's', b't', 0, 0, 0, 2]; // GAP 0x7c -pub const tag_mod_children: usize = 0x7b; - -// GAP 0x108 // top-level only - -// GAP 0x7c - // GAP 0x108 -pub const tag_impls: usize = 0x109; // top-level only - -// GAP 0x7d, 0x7e, 0x7f, 0x80, 0x81 - -pub const tag_native_libraries: usize = 0x10a; // top-level only - -// GAP 0x82, 0x83, 0x84 - -pub const tag_plugin_registrar_fn: usize = 0x10b; // top-level only - -pub const tag_method_argument_names: usize = 0x85; - -// GAP 0x86 - -pub const tag_reachable_ids: usize = 0x10c; // top-level only - -// GAP 0x87 - -pub const tag_items_data_item_stability: usize = 0x88; - -pub const tag_items_data_item_repr: usize = 0x89; - -// GAP 0x10d // top-level only - -// GAP 0x8a - -pub const tag_items_data_item_struct_ctor: usize = 0x8b; -pub const tag_attribute_is_sugared_doc: usize = 0x8c; -// GAP 0x8d -pub const tag_items_data_region: usize = 0x8e; - -pub const tag_item_generics: usize = 0x8f; -// GAP 0x90, 0x91, 0x92, 0x93, 0x94 - -pub const tag_item_predicates: usize = 0x95; -// GAP 0x96, 0x97, 0x98, 0x99 - -pub const tag_unsafety: usize = 0x9a; - -pub const tag_polarity: usize = 0x9d; - -pub const tag_macro_defs: usize = 0x10e; // top-level only - -// GAP 0x9e, 0x9f - -pub const tag_paren_sugar: usize = 0xa0; - -pub const tag_codemap: usize = 0xa1; - -// GAP 0xa2 - -pub const tag_item_super_predicates: usize = 0xa3; - -pub const tag_defaulted_trait: usize = 0xa4; - -pub const tag_impl_coerce_unsized_kind: usize = 0xa5; - -pub const tag_items_data_item_constness: usize = 0xa6; - -pub const tag_items_data_item_deprecation: usize = 0xa7; - -pub const tag_items_data_item_defaultness: usize = 0xa8; - -pub const tag_items_data_parent_impl: usize = 0xa9; - -pub const tag_rustc_version: usize = 0x10f; pub fn rustc_version() -> String { format!( "rustc {}", @@ -200,13 +48,69 @@ pub fn rustc_version() -> String { ) } -pub const tag_panic_strategy: usize = 0x114; +pub mod root_tag { + pub const rustc_version: usize = 0x10f; + pub const crate_deps: usize = 0x102; + pub const crate_hash: usize = 0x103; + pub const crate_crate_name: usize = 0x104; + pub const crate_disambiguator: usize = 0x113; + pub const items: usize = 0x100; + pub const index: usize = 0x110; + pub const xref_index: usize = 0x111; + pub const xref_data: usize = 0x112; + pub const crate_triple: usize = 0x105; + pub const dylib_dependency_formats: usize = 0x106; + pub const lang_items: usize = 0x107; + pub const lang_items_missing: usize = 0x76; + pub const impls: usize = 0x109; + pub const native_libraries: usize = 0x10a; + pub const plugin_registrar_fn: usize = 0x10b; + pub const panic_strategy: usize = 0x114; + pub const macro_derive_registrar: usize = 0x115; + pub const reachable_ids: usize = 0x10c; + pub const macro_defs: usize = 0x10e; + pub const codemap: usize = 0xa1; +} -pub const tag_macro_derive_registrar: usize = 0x115; - -// NB: increment this if you change the format of metadata such that -// rustc_version can't be found. -pub const metadata_encoding_version : &'static [u8] = &[b'r', b'u', b's', b't', 0, 0, 0, 2]; +pub mod item_tag { + pub const name: usize = 0x20; + pub const def_index: usize = 0x21; + pub const family: usize = 0x24; + pub const ty: usize = 0x25; + pub const parent_item: usize = 0x28; + pub const is_tuple_struct_ctor: usize = 0x29; + pub const closure_kind: usize = 0x2a; + pub const closure_ty: usize = 0x2b; + pub const def_key: usize = 0x2c; + pub const attributes: usize = 0x101; + pub const trait_ref: usize = 0x3b; + pub const disr_val: usize = 0x3c; + pub const fields: usize = 0x41; + pub const variances: usize = 0x43; + pub const trait_method_explicit_self: usize = 0x45; + pub const ast: usize = 0x50; + pub const mir: usize = 0x52; + pub const trait_item_has_body: usize = 0x70; + pub const visibility: usize = 0x78; + pub const inherent_impls: usize = 0x79; + pub const children: usize = 0x7b; + pub const method_argument_names: usize = 0x85; + pub const stability: usize = 0x88; + pub const repr: usize = 0x89; + pub const struct_ctor: usize = 0x8b; + pub const generics: usize = 0x8f; + pub const predicates: usize = 0x95; + pub const unsafety: usize = 0x9a; + pub const polarity: usize = 0x9d; + pub const paren_sugar: usize = 0xa0; + pub const super_predicates: usize = 0xa3; + pub const defaulted_trait: usize = 0xa4; + pub const impl_coerce_unsized_kind: usize = 0xa5; + pub const constness: usize = 0xa6; + pub const deprecation: usize = 0xa7; + pub const defaultness: usize = 0xa8; + pub const parent_impl: usize = 0xa9; +} /// The shorthand encoding of `Ty` uses `TypeVariants`' variant `usize` /// and is offset by this value so it never matches a real variant. diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 8b87f0e718fb..662236be0f0d 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -324,53 +324,53 @@ impl CrateMetadata { } pub fn load_index(data: &[u8]) -> index::Index { - index::Index::from_rbml(rbml::Doc::new(data).get(tag_index)) + index::Index::from_rbml(rbml::Doc::new(data).get(root_tag::index)) } pub fn crate_rustc_version(data: &[u8]) -> Option { let doc = rbml::Doc::new(data); - reader::maybe_get_doc(doc, tag_rustc_version).map(|s| { + reader::maybe_get_doc(doc, root_tag::rustc_version).map(|s| { str::from_utf8(&s.data[s.start..s.end]).unwrap().to_string() }) } pub fn load_xrefs(data: &[u8]) -> index::DenseIndex { - let index = rbml::Doc::new(data).get(tag_xref_index); + let index = rbml::Doc::new(data).get(root_tag::xref_index); index::DenseIndex::from_buf(index.data, index.start, index.end) } // Go through each item in the metadata and create a map from that // item's def-key to the item's DefIndex. pub fn load_key_map(data: &[u8]) -> FnvHashMap { - rbml::Doc::new(data).get(tag_items).get(tag_items_data).children().map(|item_doc| { + rbml::Doc::new(data).get(root_tag::items).children().map(|item_doc| { // load def-key from item let key = item_def_key(item_doc); // load def-index from item - (key, item_doc.get(tag_def_index).decoder().decode()) + (key, item_doc.get(item_tag::def_index).decoder().decode()) }).collect() } fn item_family(item: rbml::Doc) -> Family { - item.get(tag_items_data_item_family).decoder().decode() + item.get(item_tag::family).decoder().decode() } fn item_visibility(item: rbml::Doc) -> ty::Visibility { - match reader::maybe_get_doc(item, tag_items_data_item_visibility) { + match reader::maybe_get_doc(item, item_tag::visibility) { None => ty::Visibility::Public, Some(visibility_doc) => visibility_doc.decoder().decode() } } fn item_defaultness(item: rbml::Doc) -> hir::Defaultness { - match reader::maybe_get_doc(item, tag_items_data_item_defaultness) { + match reader::maybe_get_doc(item, item_tag::defaultness) { None => hir::Defaultness::Default, // should occur only for default impls on traits Some(defaultness_doc) => defaultness_doc.decoder().decode() } } fn item_parent_item(cdata: Cmd, d: rbml::Doc) -> Option { - reader::maybe_get_doc(d, tag_items_data_parent_item).map(|did| { + reader::maybe_get_doc(d, item_tag::parent_item).map(|did| { let mut dcx = did.decoder(); dcx.cdata = Some(cdata); dcx.decode() @@ -378,7 +378,7 @@ fn item_parent_item(cdata: Cmd, d: rbml::Doc) -> Option { } fn item_require_parent_item(cdata: Cmd, d: rbml::Doc) -> DefId { - let mut dcx = d.get(tag_items_data_parent_item).decoder(); + let mut dcx = d.get(item_tag::parent_item).decoder(); dcx.cdata = Some(cdata); dcx.decode() } @@ -386,17 +386,17 @@ fn item_require_parent_item(cdata: Cmd, d: rbml::Doc) -> DefId { fn item_def_id(d: rbml::Doc, cdata: Cmd) -> DefId { DefId { krate: cdata.cnum, - index: d.get(tag_def_index).decoder().decode() + index: d.get(item_tag::def_index).decoder().decode() } } fn doc_type<'a, 'tcx>(doc: rbml::Doc, tcx: TyCtxt<'a, 'tcx, 'tcx>, cdata: Cmd) -> Ty<'tcx> { - maybe_doc_type(doc, tcx, cdata).expect("missing tag_items_data_item_type") + maybe_doc_type(doc, tcx, cdata).expect("missing item_tag::ty") } fn maybe_doc_type<'a, 'tcx>(doc: rbml::Doc, tcx: TyCtxt<'a, 'tcx, 'tcx>, cdata: Cmd) -> Option> { - reader::maybe_get_doc(doc, tag_items_data_item_type).map(|tp| { + reader::maybe_get_doc(doc, item_tag::ty).map(|tp| { let mut dcx = tp.decoder(); dcx.tcx = Some(tcx); dcx.cdata = Some(cdata); @@ -417,7 +417,7 @@ fn item_name(item: rbml::Doc) -> ast::Name { } fn maybe_item_name(item: rbml::Doc) -> Option { - reader::maybe_get_doc(item, tag_paths_data_name).map(|name| { + reader::maybe_get_doc(item, item_tag::name).map(|name| { name.decoder().decode() }) } @@ -459,9 +459,9 @@ pub fn get_trait_def<'a, 'tcx>(cdata: Cmd, { let item_doc = cdata.lookup_item(item_id); let generics = doc_generics(item_doc, tcx, cdata); - let unsafety = item_doc.get(tag_unsafety).decoder().decode(); - let paren_sugar = item_doc.get(tag_paren_sugar).decoder().decode(); - let trait_ref = doc_trait_ref(item_doc.get(tag_item_trait_ref), tcx, cdata); + let unsafety = item_doc.get(item_tag::unsafety).decoder().decode(); + let paren_sugar = item_doc.get(item_tag::paren_sugar).decoder().decode(); + let trait_ref = doc_trait_ref(item_doc.get(item_tag::trait_ref), tcx, cdata); let def_path = def_path(cdata, item_id).unwrap(); ty::TraitDef::new(unsafety, paren_sugar, generics, trait_ref, @@ -481,12 +481,12 @@ pub fn get_adt_def<'a, 'tcx>(cdata: Cmd, } } fn get_enum_variants<'tcx>(cdata: Cmd, doc: rbml::Doc) -> Vec> { - let mut dcx = doc.get(tag_mod_children).decoder(); + let mut dcx = doc.get(item_tag::children).decoder(); dcx.cdata = Some(cdata); dcx.seq().map(|did: DefId| { let item = cdata.lookup_item(did.index); - let disr = item.get(tag_disr_val).decoder().decode(); + let disr = item.get(item_tag::disr_val).decoder().decode(); ty::VariantDefData { did: did, name: item_name(item), @@ -497,7 +497,7 @@ pub fn get_adt_def<'a, 'tcx>(cdata: Cmd, }).collect() } fn get_variant_fields<'tcx>(cdata: Cmd, doc: rbml::Doc) -> Vec> { - let mut dcx = doc.get(tag_item_fields).decoder(); + let mut dcx = doc.get(item_tag::fields).decoder(); dcx.cdata = Some(cdata); dcx.seq().map(|did: DefId| { @@ -531,7 +531,7 @@ pub fn get_adt_def<'a, 'tcx>(cdata: Cmd, } Struct(..) => { // Use separate constructor id for unit/tuple structs and reuse did for braced structs. - ctor_did = reader::maybe_get_doc(doc, tag_items_data_item_struct_ctor).map(|ctor_doc| { + ctor_did = reader::maybe_get_doc(doc, item_tag::struct_ctor).map(|ctor_doc| { let mut dcx = ctor_doc.decoder(); dcx.cdata = Some(cdata); dcx.decode() @@ -595,7 +595,7 @@ pub fn get_predicates<'a, 'tcx>(cdata: Cmd, -> ty::GenericPredicates<'tcx> { let item_doc = cdata.lookup_item(item_id); - doc_predicates(item_doc, tcx, cdata, tag_item_predicates) + doc_predicates(item_doc, tcx, cdata, item_tag::predicates) } pub fn get_super_predicates<'a, 'tcx>(cdata: Cmd, @@ -604,7 +604,7 @@ pub fn get_super_predicates<'a, 'tcx>(cdata: Cmd, -> ty::GenericPredicates<'tcx> { let item_doc = cdata.lookup_item(item_id); - doc_predicates(item_doc, tcx, cdata, tag_item_super_predicates) + doc_predicates(item_doc, tcx, cdata, item_tag::super_predicates) } pub fn get_generics<'a, 'tcx>(cdata: Cmd, @@ -625,14 +625,14 @@ pub fn get_type<'a, 'tcx>(cdata: Cmd, id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>) pub fn get_stability(cdata: Cmd, id: DefIndex) -> Option { let item = cdata.lookup_item(id); - reader::maybe_get_doc(item, tag_items_data_item_stability).map(|doc| { + reader::maybe_get_doc(item, item_tag::stability).map(|doc| { doc.decoder().decode() }) } pub fn get_deprecation(cdata: Cmd, id: DefIndex) -> Option { let item = cdata.lookup_item(id); - reader::maybe_get_doc(item, tag_items_data_item_deprecation).map(|doc| { + reader::maybe_get_doc(item, item_tag::deprecation).map(|doc| { doc.decoder().decode() }) } @@ -643,7 +643,7 @@ pub fn get_visibility(cdata: Cmd, id: DefIndex) -> ty::Visibility { pub fn get_parent_impl(cdata: Cmd, id: DefIndex) -> Option { let item = cdata.lookup_item(id); - reader::maybe_get_doc(item, tag_items_data_parent_impl).map(|doc| { + reader::maybe_get_doc(item, item_tag::parent_impl).map(|doc| { let mut dcx = doc.decoder(); dcx.cdata = Some(cdata); dcx.decode() @@ -652,13 +652,13 @@ pub fn get_parent_impl(cdata: Cmd, id: DefIndex) -> Option { pub fn get_repr_attrs(cdata: Cmd, id: DefIndex) -> Vec { let item = cdata.lookup_item(id); - reader::maybe_get_doc(item, tag_items_data_item_repr).map_or(vec![], |doc| { + reader::maybe_get_doc(item, item_tag::repr).map_or(vec![], |doc| { doc.decoder().decode() }) } pub fn get_impl_polarity(cdata: Cmd, id: DefIndex) -> hir::ImplPolarity { - cdata.lookup_item(id).get(tag_polarity).decoder().decode() + cdata.lookup_item(id).get(item_tag::polarity).decoder().decode() } pub fn get_custom_coerce_unsized_kind( @@ -667,7 +667,7 @@ pub fn get_custom_coerce_unsized_kind( -> Option { let item_doc = cdata.lookup_item(id); - reader::maybe_get_doc(item_doc, tag_impl_coerce_unsized_kind).map(|kind_doc| { + reader::maybe_get_doc(item_doc, item_tag::impl_coerce_unsized_kind).map(|kind_doc| { kind_doc.decoder().decode() }) } @@ -678,14 +678,14 @@ pub fn get_impl_trait<'a, 'tcx>(cdata: Cmd, -> Option> { let item_doc = cdata.lookup_item(id); - reader::maybe_get_doc(item_doc, tag_item_trait_ref).map(|tp| { + reader::maybe_get_doc(item_doc, item_tag::trait_ref).map(|tp| { doc_trait_ref(tp, tcx, cdata) }) } /// Iterates over the language items in the given crate. pub fn get_lang_items(cdata: Cmd) -> Vec<(DefIndex, usize)> { - rbml::Doc::new(cdata.data()).get(tag_lang_items).decoder().decode() + rbml::Doc::new(cdata.data()).get(root_tag::lang_items).decoder().decode() } @@ -702,7 +702,7 @@ pub fn each_child_of_item(cdata: Cmd, id: DefIndex, Some(item_doc) => item_doc, }; - let mut dcx = match reader::maybe_get_doc(item_doc, tag_mod_children) { + let mut dcx = match reader::maybe_get_doc(item_doc, item_tag::children) { Some(doc) => doc.decoder(), None => return }; @@ -782,7 +782,7 @@ pub fn maybe_get_item_ast<'a, 'tcx>(cdata: Cmd, tcx: TyCtxt<'a, 'tcx, 'tcx>, id: }; let mut parent_def_path = def_path(cdata, id).unwrap(); parent_def_path.data.pop(); - if let Some(ast_doc) = reader::maybe_get_doc(item_doc, tag_ast as usize) { + if let Some(ast_doc) = reader::maybe_get_doc(item_doc, item_tag::ast as usize) { let ii = decode_inlined_item(cdata, tcx, parent_def_path, @@ -800,7 +800,7 @@ pub fn maybe_get_item_ast<'a, 'tcx>(cdata: Cmd, tcx: TyCtxt<'a, 'tcx, 'tcx>, id: let mut grandparent_def_path = parent_def_path; grandparent_def_path.data.pop(); let parent_doc = cdata.lookup_item(parent_did.index); - if let Some(ast_doc) = reader::maybe_get_doc(parent_doc, tag_ast as usize) { + if let Some(ast_doc) = reader::maybe_get_doc(parent_doc, item_tag::ast as usize) { let ii = decode_inlined_item(cdata, tcx, grandparent_def_path, @@ -817,7 +817,7 @@ pub fn maybe_get_item_ast<'a, 'tcx>(cdata: Cmd, tcx: TyCtxt<'a, 'tcx, 'tcx>, id: pub fn is_item_mir_available<'tcx>(cdata: Cmd, id: DefIndex) -> bool { if let Some(item_doc) = cdata.get_item(id) { - return reader::maybe_get_doc(item_doc, tag_mir as usize).is_some(); + return reader::maybe_get_doc(item_doc, item_tag::mir as usize).is_some(); } false @@ -829,7 +829,7 @@ pub fn maybe_get_item_mir<'a, 'tcx>(cdata: Cmd, -> Option> { let item_doc = cdata.lookup_item(id); - reader::maybe_get_doc(item_doc, tag_mir).map(|mir_doc| { + reader::maybe_get_doc(item_doc, item_tag::mir).map(|mir_doc| { let mut dcx = mir_doc.decoder(); dcx.tcx = Some(tcx); dcx.cdata = Some(cdata); @@ -839,7 +839,7 @@ pub fn maybe_get_item_mir<'a, 'tcx>(cdata: Cmd, fn get_explicit_self<'a, 'tcx>(cdata: Cmd, item: rbml::Doc, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> ty::ExplicitSelfCategory<'tcx> { - let mut dcx = item.get(tag_item_trait_method_explicit_self).decoder(); + let mut dcx = item.get(item_tag::trait_method_explicit_self).decoder(); dcx.cdata = Some(cdata); dcx.tcx = Some(tcx); @@ -881,12 +881,12 @@ pub fn get_impl_or_trait_item<'a, 'tcx>(cdata: Cmd, id: DefIndex, tcx: TyCtxt<'a defaultness: defaultness, def_id: def_id, container: container, - has_value: item_doc.get(tag_item_trait_item_has_body).decoder().decode(), + has_value: item_doc.get(item_tag::trait_item_has_body).decoder().decode(), })) } Family::Method => { let generics = doc_generics(item_doc, tcx, cdata); - let predicates = doc_predicates(item_doc, tcx, cdata, tag_item_predicates); + let predicates = doc_predicates(item_doc, tcx, cdata, item_tag::predicates); let ity = tcx.lookup_item_type(def_id).ty; let fty = match ity.sty { ty::TyFnDef(.., fty) => fty, @@ -904,7 +904,7 @@ pub fn get_impl_or_trait_item<'a, 'tcx>(cdata: Cmd, id: DefIndex, tcx: TyCtxt<'a explicit_self: explicit_self, vis: vis, defaultness: defaultness, - has_body: item_doc.get(tag_item_trait_item_has_body).decoder().decode(), + has_body: item_doc.get(item_tag::trait_item_has_body).decoder().decode(), def_id: def_id, container: container, })) @@ -926,13 +926,13 @@ pub fn get_impl_or_trait_item<'a, 'tcx>(cdata: Cmd, id: DefIndex, tcx: TyCtxt<'a pub fn get_item_variances(cdata: Cmd, id: DefIndex) -> Vec { let item_doc = cdata.lookup_item(id); - item_doc.get(tag_item_variances).decoder().decode() + item_doc.get(item_tag::variances).decoder().decode() } pub fn get_struct_ctor_def_id(cdata: Cmd, node_id: DefIndex) -> Option { let item = cdata.lookup_item(node_id); - reader::maybe_get_doc(item, tag_items_data_item_struct_ctor).map(|ctor_doc| { + reader::maybe_get_doc(item, item_tag::struct_ctor).map(|ctor_doc| { let mut dcx = ctor_doc.decoder(); dcx.cdata = Some(cdata); dcx.decode() @@ -946,7 +946,7 @@ pub fn get_tuple_struct_definition_if_ctor(cdata: Cmd, -> Option { let item = cdata.lookup_item(node_id); - reader::maybe_get_doc(item, tag_items_data_item_is_tuple_struct_ctor).and_then(|doc| { + reader::maybe_get_doc(item, item_tag::is_tuple_struct_ctor).and_then(|doc| { if doc.decoder().decode() { Some(item_require_parent_item(cdata, item)) } else { @@ -968,7 +968,7 @@ pub fn get_item_attrs(cdata: Cmd, } pub fn get_struct_field_names(cdata: Cmd, id: DefIndex) -> Vec { - let mut dcx = cdata.lookup_item(id).get(tag_item_fields).decoder(); + let mut dcx = cdata.lookup_item(id).get(item_tag::fields).decoder(); dcx.cdata = Some(cdata); dcx.seq().map(|did: DefId| { @@ -977,7 +977,7 @@ pub fn get_struct_field_names(cdata: Cmd, id: DefIndex) -> Vec { } fn get_attributes(md: rbml::Doc) -> Vec { - reader::maybe_get_doc(md, tag_attributes).map_or(vec![], |attrs_doc| { + reader::maybe_get_doc(md, item_tag::attributes).map_or(vec![], |attrs_doc| { let mut attrs = attrs_doc.decoder().decode::>(); // Need new unique IDs: old thread-local IDs won't map to new threads. @@ -998,7 +998,7 @@ pub struct CrateDep { } pub fn get_crate_deps(data: &[u8]) -> Vec { - let dcx = rbml::Doc::new(data).get(tag_crate_deps).decoder(); + let dcx = rbml::Doc::new(data).get(root_tag::crate_deps).decoder(); dcx.seq().enumerate().map(|(crate_num, (name, hash, explicitly_linked))| { CrateDep { @@ -1021,29 +1021,29 @@ fn list_crate_deps(data: &[u8], out: &mut io::Write) -> io::Result<()> { pub fn maybe_get_crate_hash(data: &[u8]) -> Option { let cratedoc = rbml::Doc::new(data); - reader::maybe_get_doc(cratedoc, tag_crate_hash).map(|doc| { + reader::maybe_get_doc(cratedoc, root_tag::crate_hash).map(|doc| { doc.decoder().decode() }) } pub fn get_crate_hash(data: &[u8]) -> Svh { - rbml::Doc::new(data).get(tag_crate_hash).decoder().decode() + rbml::Doc::new(data).get(root_tag::crate_hash).decoder().decode() } pub fn maybe_get_crate_name(data: &[u8]) -> Option { let cratedoc = rbml::Doc::new(data); - reader::maybe_get_doc(cratedoc, tag_crate_crate_name).map(|doc| { + reader::maybe_get_doc(cratedoc, root_tag::crate_crate_name).map(|doc| { doc.decoder().decode() }) } pub fn get_crate_disambiguator(data: &[u8]) -> String { - rbml::Doc::new(data).get(tag_crate_disambiguator).decoder().decode() + rbml::Doc::new(data).get(root_tag::crate_disambiguator).decoder().decode() } pub fn get_crate_triple(data: &[u8]) -> Option { let cratedoc = rbml::Doc::new(data); - let triple_doc = reader::maybe_get_doc(cratedoc, tag_crate_triple); + let triple_doc = reader::maybe_get_doc(cratedoc, root_tag::crate_triple); triple_doc.map(|s| s.decoder().decode()) } @@ -1073,7 +1073,7 @@ pub fn each_inherent_implementation_for_type(cdata: Cmd, where F: FnMut(DefId), { let item_doc = cdata.lookup_item(id); - let mut dcx = item_doc.get(tag_items_data_item_inherent_impls).decoder(); + let mut dcx = item_doc.get(item_tag::inherent_impls).decoder(); dcx.cdata = Some(cdata); for impl_def_id in dcx.seq() { @@ -1095,7 +1095,7 @@ pub fn each_implementation_for_trait(cdata: Cmd, }; // FIXME(eddyb) Make this O(1) instead of O(n). - for trait_doc in rbml::Doc::new(cdata.data()).get(tag_impls).children() { + for trait_doc in rbml::Doc::new(cdata.data()).get(root_tag::impls).children() { let mut dcx = trait_doc.decoder(); dcx.cdata = Some(cdata); @@ -1128,18 +1128,18 @@ pub fn get_trait_of_item(cdata: Cmd, id: DefIndex) -> Option { pub fn get_native_libraries(cdata: Cmd) -> Vec<(cstore::NativeLibraryKind, String)> { - rbml::Doc::new(cdata.data()).get(tag_native_libraries).decoder().decode() + rbml::Doc::new(cdata.data()).get(root_tag::native_libraries).decoder().decode() } pub fn get_plugin_registrar_fn(data: &[u8]) -> Option { - reader::maybe_get_doc(rbml::Doc::new(data), tag_plugin_registrar_fn) + reader::maybe_get_doc(rbml::Doc::new(data), root_tag::plugin_registrar_fn) .map(|doc| doc.decoder().decode()) } pub fn each_exported_macro(data: &[u8], mut f: F) where F: FnMut(ast::Name, Vec, Span, String) -> bool, { - let dcx = rbml::Doc::new(data).get(tag_macro_defs).decoder(); + let dcx = rbml::Doc::new(data).get(root_tag::macro_defs).decoder(); for (name, attrs, span, body) in dcx.seq() { if !f(name, attrs, span, body) { break; @@ -1148,14 +1148,14 @@ pub fn each_exported_macro(data: &[u8], mut f: F) where } pub fn get_derive_registrar_fn(data: &[u8]) -> Option { - reader::maybe_get_doc(rbml::Doc::new(data), tag_macro_derive_registrar) + reader::maybe_get_doc(rbml::Doc::new(data), root_tag::macro_derive_registrar) .map(|doc| doc.decoder().decode()) } pub fn get_dylib_dependency_formats(cdata: Cmd) -> Vec<(CrateNum, LinkagePreference)> { - let dcx = rbml::Doc::new(cdata.data()).get(tag_dylib_dependency_formats).decoder(); + let dcx = rbml::Doc::new(cdata.data()).get(root_tag::dylib_dependency_formats).decoder(); dcx.seq::>().enumerate().flat_map(|(i, link)| { let cnum = CrateNum::new(i + 1); @@ -1164,19 +1164,19 @@ pub fn get_dylib_dependency_formats(cdata: Cmd) } pub fn get_missing_lang_items(cdata: Cmd) -> Vec { - rbml::Doc::new(cdata.data()).get(tag_lang_items_missing).decoder().decode() + rbml::Doc::new(cdata.data()).get(root_tag::lang_items_missing).decoder().decode() } pub fn get_method_arg_names(cdata: Cmd, id: DefIndex) -> Vec { let method_doc = cdata.lookup_item(id); - match reader::maybe_get_doc(method_doc, tag_method_argument_names) { + match reader::maybe_get_doc(method_doc, item_tag::method_argument_names) { Some(args_doc) => args_doc.decoder().decode(), None => vec![], } } pub fn get_reachable_ids(cdata: Cmd) -> Vec { - let dcx = rbml::Doc::new(cdata.data()).get(tag_reachable_ids).decoder(); + let dcx = rbml::Doc::new(cdata.data()).get(root_tag::reachable_ids).decoder(); dcx.seq().map(|index| { DefId { @@ -1187,7 +1187,7 @@ pub fn get_reachable_ids(cdata: Cmd) -> Vec { } pub fn is_const_fn(cdata: Cmd, id: DefIndex) -> bool { - match reader::maybe_get_doc(cdata.lookup_item(id), tag_items_data_item_constness) { + match reader::maybe_get_doc(cdata.lookup_item(id), item_tag::constness) { None => false, Some(doc) => { match doc.decoder().decode() { @@ -1235,7 +1235,7 @@ fn doc_generics<'a, 'tcx>(base_doc: rbml::Doc, cdata: Cmd) -> &'tcx ty::Generics<'tcx> { - let mut dcx = base_doc.get(tag_item_generics).decoder(); + let mut dcx = base_doc.get(item_tag::generics).decoder(); dcx.tcx = Some(tcx); dcx.cdata = Some(cdata); tcx.alloc_generics(dcx.decode()) @@ -1268,7 +1268,7 @@ fn doc_predicates<'a, 'tcx>(base_doc: rbml::Doc, } pub fn is_defaulted_trait(cdata: Cmd, trait_id: DefIndex) -> bool { - cdata.lookup_item(trait_id).get(tag_defaulted_trait).decoder().decode() + cdata.lookup_item(trait_id).get(item_tag::defaulted_trait).decoder().decode() } pub fn is_default_impl(cdata: Cmd, impl_id: DefIndex) -> bool { @@ -1276,17 +1276,17 @@ pub fn is_default_impl(cdata: Cmd, impl_id: DefIndex) -> bool { } pub fn get_imported_filemaps(metadata: &[u8]) -> Vec { - rbml::Doc::new(metadata).get(tag_codemap).decoder().decode() + rbml::Doc::new(metadata).get(root_tag::codemap).decoder().decode() } pub fn closure_kind(cdata: Cmd, closure_id: DefIndex) -> ty::ClosureKind { - cdata.lookup_item(closure_id).get(tag_items_closure_kind).decoder().decode() + cdata.lookup_item(closure_id).get(item_tag::closure_kind).decoder().decode() } pub fn closure_ty<'a, 'tcx>(cdata: Cmd, closure_id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> ty::ClosureTy<'tcx> { let closure_doc = cdata.lookup_item(closure_id); - let closure_ty_doc = closure_doc.get(tag_items_closure_ty); + let closure_ty_doc = closure_doc.get(item_tag::closure_ty); let mut dcx = closure_ty_doc.decoder(); dcx.tcx = Some(tcx); dcx.cdata = Some(cdata); @@ -1300,18 +1300,9 @@ pub fn def_key(cdata: Cmd, id: DefIndex) -> hir_map::DefKey { } fn item_def_key(item_doc: rbml::Doc) -> hir_map::DefKey { - match reader::maybe_get_doc(item_doc, tag_def_key) { - Some(def_key_doc) => { - let simple_key = def_key_doc.decoder().decode(); - let name = maybe_item_name(item_doc).map(|name| name.as_str()); - def_key::recover_def_key(simple_key, name) - } - None => { - bug!("failed to find block with tag {:?} for item with family {:?}", - tag_def_key, - item_family(item_doc)) - } - } + let simple_key = item_doc.get(item_tag::def_key).decoder().decode(); + let name = maybe_item_name(item_doc).map(|name| name.as_str()); + def_key::recover_def_key(simple_key, name) } // Returns the path leading to the thing with this `id`. Note that @@ -1327,5 +1318,5 @@ pub fn def_path(cdata: Cmd, id: DefIndex) -> Option { } pub fn get_panic_strategy(data: &[u8]) -> PanicStrategy { - rbml::Doc::new(data).get(tag_panic_strategy).decoder().decode() + rbml::Doc::new(data).get(root_tag::panic_strategy).decoder().decode() } diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 326eb0fe9a3a..1e4c61e0b2e1 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -169,21 +169,21 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } fn encode_name(ecx: &mut EncodeContext, name: Name) { - ecx.start_tag(tag_paths_data_name); + ecx.start_tag(item_tag::name); name.encode(ecx).unwrap(); ecx.end_tag(); } fn encode_def_id(ecx: &mut EncodeContext, def_id: DefId) { assert!(def_id.is_local()); - ecx.start_tag(tag_def_index); + ecx.start_tag(item_tag::def_index); def_id.index.encode(ecx).unwrap(); ecx.end_tag(); } fn encode_def_key(ecx: &mut EncodeContext, key: DefKey) { let simple_key = def_key::simplify_def_key(key); - ecx.start_tag(tag_def_key); + ecx.start_tag(item_tag::def_key); simple_key.encode(ecx); ecx.end_tag(); } @@ -206,14 +206,14 @@ fn encode_trait_ref<'a, 'tcx>(ecx: &mut EncodeContext<'a, 'tcx>, // Item info table encoding fn encode_family(ecx: &mut EncodeContext, f: Family) { - ecx.start_tag(tag_items_data_item_family); + ecx.start_tag(item_tag::family); f.encode(ecx).unwrap(); ecx.end_tag(); } fn encode_item_variances(ecx: &mut EncodeContext, id: NodeId) { let v = ecx.tcx.item_variances(ecx.tcx.map.local_def_id(id)); - ecx.start_tag(tag_item_variances); + ecx.start_tag(item_tag::variances); v.encode(ecx); ecx.end_tag(); } @@ -233,27 +233,27 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } fn encode_type(&mut self, typ: Ty<'tcx>) { - self.start_tag(tag_items_data_item_type); + self.start_tag(item_tag::ty); typ.encode(self).unwrap(); self.end_tag(); } fn encode_disr_val(&mut self, disr_val: ty::Disr) { - self.start_tag(tag_disr_val); + self.start_tag(item_tag::disr_val); disr_val.to_u64_unchecked().encode(self).unwrap(); self.end_tag(); } fn encode_parent_item(&mut self, id: DefId) { - self.start_tag(tag_items_data_parent_item); + self.start_tag(item_tag::parent_item); id.encode(self).unwrap(); self.end_tag(); } fn encode_variant_fields(&mut self, variant: ty::VariantDef) { - self.start_tag(tag_item_fields); + self.start_tag(item_tag::fields); self.seq(&variant.fields, |_, f| f.did); self.end_tag(); } @@ -321,7 +321,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { debug!("(encoding info for module) encoding info for module ID {}", id); // Encode info about all the module children. - self.start_tag(tag_mod_children); + self.start_tag(item_tag::children); self.seq(&md.item_ids, |_, item_id| { tcx.map.local_def_id(item_id.id) }); @@ -358,7 +358,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } else { ty::Visibility::PrivateExternal }; - self.start_tag(tag_items_data_item_visibility); + self.start_tag(item_tag::visibility); vis.encode(self).unwrap(); self.end_tag(); } @@ -381,13 +381,13 @@ impl HasVisibility for ty::Visibility { } fn encode_constness(ecx: &mut EncodeContext, constness: hir::Constness) { - ecx.start_tag(tag_items_data_item_constness); + ecx.start_tag(item_tag::constness); constness.encode(ecx).unwrap(); ecx.end_tag(); } fn encode_defaultness(ecx: &mut EncodeContext, defaultness: hir::Defaultness) { - ecx.start_tag(tag_items_data_item_defaultness); + ecx.start_tag(item_tag::defaultness); defaultness.encode(ecx).unwrap(); ecx.end_tag(); } @@ -463,7 +463,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { // definition, but without this there is no way for them // to tell that they actually have a ctor rather than a // normal function - self.start_tag(tag_items_data_item_is_tuple_struct_ctor); + self.start_tag(item_tag::is_tuple_struct_ctor); true.encode(self).unwrap(); self.end_tag(); } @@ -472,10 +472,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { generics: &ty::Generics<'tcx>, predicates: &ty::GenericPredicates<'tcx>) { - self.start_tag(tag_item_generics); + self.start_tag(item_tag::generics); generics.encode(self).unwrap(); self.end_tag(); - self.encode_predicates(predicates, tag_item_predicates); + self.encode_predicates(predicates, item_tag::predicates); } fn encode_predicates(&mut self, @@ -495,7 +495,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.encode_generics(&method_ty.generics, &method_ty.predicates); self.encode_visibility(method_ty.vis); - self.start_tag(tag_item_trait_method_explicit_self); + self.start_tag(item_tag::trait_method_explicit_self); method_ty.explicit_self.encode(self).unwrap(); self.end_tag(); @@ -541,7 +541,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { encode_attributes(self, &trait_item.attrs); match trait_item.node { hir::ConstTraitItem(_, ref default) => { - self.start_tag(tag_item_trait_item_has_body); + self.start_tag(item_tag::trait_item_has_body); default.is_some().encode(self).unwrap(); self.end_tag(); @@ -550,7 +550,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.encode_mir(item_def_id); } hir::MethodTraitItem(ref sig, ref body) => { - self.start_tag(tag_item_trait_item_has_body); + self.start_tag(item_tag::trait_item_has_body); body.is_some().encode(self).unwrap(); self.end_tag(); @@ -600,7 +600,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.encode_parent_item(tcx.map.local_def_id(parent_id)); - self.start_tag(tag_item_trait_item_has_body); + self.start_tag(item_tag::trait_item_has_body); true.encode(self).unwrap(); self.end_tag(); @@ -632,7 +632,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.encode_method_ty_fields(m); self.encode_parent_item(tcx.map.local_def_id(parent_id)); - self.start_tag(tag_item_trait_item_has_body); + self.start_tag(item_tag::trait_item_has_body); true.encode(self).unwrap(); self.end_tag(); @@ -697,7 +697,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { fn encode_method_argument_names(&mut self, decl: &hir::FnDecl) { - self.start_tag(tag_method_argument_names); + self.start_tag(item_tag::method_argument_names); self.seq(&decl.inputs, |_, arg| { if let PatKind::Binding(_, ref path1, _) = arg.pat.node { @@ -717,14 +717,14 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { repr_attrs.extend(attr::find_repr_attrs(self.tcx.sess.diagnostic(), attr)); } - self.start_tag(tag_items_data_item_repr); + self.start_tag(item_tag::repr); repr_attrs.encode(self); self.end_tag(); } fn encode_mir(&mut self, def_id: DefId) { if let Some(mir) = self.mir_map.map.get(&def_id) { - self.start_tag(tag_mir as usize); + self.start_tag(item_tag::mir as usize); mir.encode(self); self.end_tag(); } @@ -734,7 +734,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { // Encodes the inherent implementations of a structure, enumeration, or trait. fn encode_inherent_implementations(ecx: &mut EncodeContext, def_id: DefId) { - ecx.start_tag(tag_items_data_item_inherent_impls); + ecx.start_tag(item_tag::inherent_impls); match ecx.tcx.inherent_impls.borrow().get(&def_id) { None => <[DefId]>::encode(&[], ecx).unwrap(), Some(implementations) => implementations.encode(ecx).unwrap() @@ -744,7 +744,7 @@ fn encode_inherent_implementations(ecx: &mut EncodeContext, fn encode_stability(ecx: &mut EncodeContext, stab_opt: Option<&attr::Stability>) { stab_opt.map(|stab| { - ecx.start_tag(tag_items_data_item_stability); + ecx.start_tag(item_tag::stability); stab.encode(ecx).unwrap(); ecx.end_tag(); }); @@ -752,7 +752,7 @@ fn encode_stability(ecx: &mut EncodeContext, stab_opt: Option<&attr::Stability>) fn encode_deprecation(ecx: &mut EncodeContext, depr_opt: Option) { depr_opt.map(|depr| { - ecx.start_tag(tag_items_data_item_deprecation); + ecx.start_tag(item_tag::deprecation); depr.encode(ecx).unwrap(); ecx.end_tag(); }); @@ -772,7 +772,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let mut sorted_xrefs: Vec<_> = xrefs.into_iter().collect(); sorted_xrefs.sort_by_key(|&(_, id)| id); - self.start_tag(tag_xref_data); + self.start_tag(root_tag::xref_data); for (xref, id) in sorted_xrefs.into_iter() { xref_positions[id as usize] = self.mark_stable_position() as u32; match xref { @@ -782,7 +782,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.mark_stable_position(); self.end_tag(); - self.start_tag(tag_xref_index); + self.start_tag(root_tag::xref_index); index::write_dense_index(xref_positions, &mut self.opaque.cursor); self.end_tag(); } @@ -857,7 +857,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { encode_name(self, item.name); // Encode all the items in self module. - self.start_tag(tag_mod_children); + self.start_tag(item_tag::children); self.seq(&fm.items, |_, foreign_item| { tcx.map.local_def_id(foreign_item.id) }); @@ -886,7 +886,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { encode_attributes(self, &item.attrs); self.encode_repr_attrs(&item.attrs); - self.start_tag(tag_mod_children); + self.start_tag(item_tag::children); self.seq(&enum_definition.variants, |_, v| { tcx.map.local_def_id(v.node.data.id()) }); @@ -928,7 +928,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { if !struct_def.is_struct() { let ctor_did = tcx.map.local_def_id(struct_def.id()); - self.start_tag(tag_items_data_item_struct_ctor); + self.start_tag(item_tag::struct_ctor); ctor_did.encode(self).unwrap(); self.end_tag(); } @@ -966,7 +966,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { encode_name(self, item.name); let trait_ref = tcx.impl_trait_ref(tcx.map.local_def_id(item.id)).unwrap(); - encode_trait_ref(self, trait_ref, tag_item_trait_ref); + encode_trait_ref(self, trait_ref, item_tag::trait_ref); } hir::ItemImpl(_, polarity, ..) => { encode_def_id_and_key(self, def_id); @@ -975,7 +975,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { encode_name(self, item.name); encode_attributes(self, &item.attrs); - self.start_tag(tag_polarity); + self.start_tag(item_tag::polarity); polarity.encode(self).unwrap(); self.end_tag(); @@ -985,21 +985,21 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { .get(&tcx.map.local_def_id(item.id)) { Some(&kind) => { - self.start_tag(tag_impl_coerce_unsized_kind); + self.start_tag(item_tag::impl_coerce_unsized_kind); kind.encode(self); self.end_tag(); } None => {} } - self.start_tag(tag_mod_children); + self.start_tag(item_tag::children); tcx.impl_or_trait_items(def_id).encode(self).unwrap(); <[def::Export]>::encode(&[], self).unwrap(); self.end_tag(); let did = tcx.map.local_def_id(item.id); if let Some(trait_ref) = tcx.impl_trait_ref(did) { - encode_trait_ref(self, trait_ref, tag_item_trait_ref); + encode_trait_ref(self, trait_ref, item_tag::trait_ref); let trait_def = tcx.lookup_trait_def(trait_ref.def_id); let parent = trait_def.ancestors(did) @@ -1011,7 +1011,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { _ => None, }); parent.map(|parent| { - self.start_tag(tag_items_data_parent_impl); + self.start_tag(item_tag::parent_impl); parent.encode(self).unwrap(); self.end_tag(); }); @@ -1026,29 +1026,29 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let trait_def = tcx.lookup_trait_def(def_id); let trait_predicates = tcx.lookup_predicates(def_id); - self.start_tag(tag_unsafety); + self.start_tag(item_tag::unsafety); trait_def.unsafety.encode(self).unwrap(); self.end_tag(); - self.start_tag(tag_paren_sugar); + self.start_tag(item_tag::paren_sugar); trait_def.paren_sugar.encode(self).unwrap(); self.end_tag(); - self.start_tag(tag_defaulted_trait); + self.start_tag(item_tag::defaulted_trait); tcx.trait_has_default_impl(def_id).encode(self).unwrap(); self.end_tag(); self.encode_generics(&trait_def.generics, &trait_predicates); self.encode_predicates(&tcx.lookup_super_predicates(def_id), - tag_item_super_predicates); - encode_trait_ref(self, trait_def.trait_ref, tag_item_trait_ref); + item_tag::super_predicates); + encode_trait_ref(self, trait_def.trait_ref, item_tag::trait_ref); encode_name(self, item.name); encode_attributes(self, &item.attrs); self.encode_visibility(vis); encode_stability(self, stab); encode_deprecation(self, depr); - self.start_tag(tag_mod_children); + self.start_tag(item_tag::children); tcx.impl_or_trait_items(def_id).encode(self).unwrap(); <[def::Export]>::encode(&[], self).unwrap(); self.end_tag(); @@ -1276,11 +1276,11 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { encode_def_id_and_key(self, def_id); encode_name(self, syntax::parse::token::intern("")); - self.start_tag(tag_items_closure_ty); + self.start_tag(item_tag::closure_ty); tcx.tables.borrow().closure_tys[&def_id].encode(self).unwrap(); self.end_tag(); - self.start_tag(tag_items_closure_kind); + self.start_tag(item_tag::closure_kind); tcx.closure_kind(def_id).encode(self).unwrap(); self.end_tag(); @@ -1292,7 +1292,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { fn encode_info_for_items(ecx: &mut EncodeContext) -> IndexData { let krate = ecx.tcx.map.krate(); - ecx.start_tag(tag_items_data); + ecx.start_tag(root_tag::items); let items = { let mut index = IndexBuilder::new(ecx); @@ -1315,13 +1315,13 @@ fn encode_info_for_items(ecx: &mut EncodeContext) -> IndexData { } fn encode_item_index(ecx: &mut EncodeContext, index: IndexData) { - ecx.start_tag(tag_index); + ecx.start_tag(root_tag::index); index.write_index(&mut ecx.opaque.cursor); ecx.end_tag(); } fn encode_attributes(ecx: &mut EncodeContext, attrs: &[ast::Attribute]) { - ecx.start_tag(tag_attributes); + ecx.start_tag(item_tag::attributes); attrs.encode(ecx).unwrap(); ecx.end_tag(); } @@ -1352,7 +1352,7 @@ fn encode_crate_deps(ecx: &mut EncodeContext, cstore: &cstore::CStore) { // the assumption that they are numbered 1 to n. // FIXME (#2166): This is not nearly enough to support correct versioning // but is enough to get transitive crate dependencies working. - ecx.start_tag(tag_crate_deps); + ecx.start_tag(root_tag::crate_deps); ecx.seq(&get_ordered_deps(cstore), |_, &(_, ref dep)| { (dep.name(), decoder::get_crate_hash(dep.data()), dep.explicitly_linked.get()) @@ -1376,11 +1376,11 @@ fn encode_lang_items(ecx: &mut EncodeContext) { let count = lang_items().count(); let mut lang_items = lang_items(); - ecx.start_tag(tag_lang_items); + ecx.start_tag(root_tag::lang_items); ecx.seq(0..count, |_, _| lang_items.next().unwrap()); ecx.end_tag(); - ecx.start_tag(tag_lang_items_missing); + ecx.start_tag(root_tag::lang_items_missing); tcx.lang_items.missing.encode(ecx).unwrap(); ecx.end_tag(); } @@ -1401,7 +1401,7 @@ fn encode_native_libraries(ecx: &mut EncodeContext) { let count = libs().count(); let mut libs = libs(); - ecx.start_tag(tag_native_libraries); + ecx.start_tag(root_tag::native_libraries); ecx.seq(0..count, |_, _| libs.next().unwrap()); ecx.end_tag(); } @@ -1410,7 +1410,7 @@ fn encode_plugin_registrar_fn(ecx: &mut EncodeContext) { match ecx.tcx.sess.plugin_registrar_fn.get() { Some(id) => { let def_id = ecx.tcx.map.local_def_id(id); - ecx.start_tag(tag_plugin_registrar_fn); + ecx.start_tag(root_tag::plugin_registrar_fn); def_id.index.encode(ecx).unwrap(); ecx.end_tag(); } @@ -1434,7 +1434,7 @@ fn encode_codemap(ecx: &mut EncodeContext) { let count = filemaps().count(); let mut filemaps = filemaps(); - ecx.start_tag(tag_codemap); + ecx.start_tag(root_tag::codemap); ecx.seq(0..count, |_, _| filemaps.next().unwrap()); ecx.end_tag(); } @@ -1442,7 +1442,7 @@ fn encode_codemap(ecx: &mut EncodeContext) { /// Serialize the text of the exported macros fn encode_macro_defs(ecx: &mut EncodeContext) { let tcx = ecx.tcx; - ecx.start_tag(tag_macro_defs); + ecx.start_tag(root_tag::macro_defs); ecx.seq(&tcx.map.krate().exported_macros, |_, def| { let body = ::syntax::print::pprust::tts_to_string(&def.body); (def.name, &def.attrs, def.span, body) @@ -1453,7 +1453,7 @@ fn encode_macro_defs(ecx: &mut EncodeContext) { let id = ecx.tcx.sess.derive_registrar_fn.get().unwrap(); let did = ecx.tcx.map.local_def_id(id); - ecx.start_tag(tag_macro_derive_registrar); + ecx.start_tag(root_tag::macro_derive_registrar); did.index.encode(ecx).unwrap(); ecx.end_tag(); } @@ -1485,7 +1485,7 @@ fn encode_impls(ecx: &mut EncodeContext) { }; ecx.tcx.map.krate().visit_all_items(&mut visitor); - ecx.start_tag(tag_impls); + ecx.start_tag(root_tag::impls); for (trait_def_id, trait_impls) in visitor.impls { // FIXME(eddyb) Avoid wrapping the entries in docs. ecx.start_tag(0); @@ -1503,7 +1503,7 @@ fn encode_impls(ecx: &mut EncodeContext) { // symbol associated with them (they weren't translated) or if they're an FFI // definition (as that's not defined in this crate). fn encode_reachable(ecx: &mut EncodeContext) { - ecx.start_tag(tag_reachable_ids); + ecx.start_tag(root_tag::reachable_ids); let reachable = ecx.reachable; ecx.seq(reachable, |ecx, &id| ecx.tcx.map.local_def_id(id).index); @@ -1512,7 +1512,7 @@ fn encode_reachable(ecx: &mut EncodeContext) { } fn encode_dylib_dependency_formats(ecx: &mut EncodeContext) { - ecx.start_tag(tag_dylib_dependency_formats); + ecx.start_tag(root_tag::dylib_dependency_formats); match ecx.tcx.sess.dependency_formats.borrow().get(&config::CrateTypeDylib) { Some(arr) => { ecx.seq(arr, |_, slot| { @@ -1596,30 +1596,30 @@ pub fn encode_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } fn encode_metadata_inner(ecx: &mut EncodeContext) { - ecx.wr_tagged_str(tag_rustc_version, &rustc_version()); + ecx.wr_tagged_str(root_tag::rustc_version, &rustc_version()); let tcx = ecx.tcx; let link_meta = ecx.link_meta; - ecx.start_tag(tag_crate_crate_name); + ecx.start_tag(root_tag::crate_crate_name); link_meta.crate_name.encode(ecx).unwrap(); ecx.end_tag(); - ecx.start_tag(tag_crate_triple); + ecx.start_tag(root_tag::crate_triple); tcx.sess.opts.target_triple.encode(ecx).unwrap(); ecx.end_tag(); - ecx.start_tag(tag_crate_hash); + ecx.start_tag(root_tag::crate_hash); link_meta.crate_hash.encode(ecx).unwrap(); ecx.end_tag(); - ecx.start_tag(tag_crate_disambiguator); + ecx.start_tag(root_tag::crate_disambiguator); tcx.sess.local_crate_disambiguator().encode(ecx).unwrap(); ecx.end_tag(); encode_dylib_dependency_formats(ecx); - ecx.start_tag(tag_panic_strategy); + ecx.start_tag(root_tag::panic_strategy); ecx.tcx.sess.opts.cg.panic.encode(ecx); ecx.end_tag(); @@ -1663,11 +1663,9 @@ fn encode_metadata_inner(ecx: &mut EncodeContext) { let reachable_bytes = ecx.position() - i; // Encode and index the items. - ecx.start_tag(tag_items); i = ecx.position(); let items = encode_info_for_items(ecx); let item_bytes = ecx.position() - i; - ecx.end_tag(); i = ecx.position(); encode_item_index(ecx, items); diff --git a/src/librustc_metadata/index_builder.rs b/src/librustc_metadata/index_builder.rs index 2cfa6f8d5d11..372577e21f11 100644 --- a/src/librustc_metadata/index_builder.rs +++ b/src/librustc_metadata/index_builder.rs @@ -55,7 +55,6 @@ //! give a callback fn, rather than taking a closure: it allows us to //! easily control precisely what data is given to that fn. -use common::tag_items_data_item; use encoder::EncodeContext; use index::IndexData; use rustc::dep_graph::DepNode; @@ -120,7 +119,8 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { let position = self.ecx.mark_stable_position(); self.items.record(id, position); let _task = self.tcx.dep_graph.in_task(DepNode::MetaData(id)); - self.ecx.start_tag(tag_items_data_item).unwrap(); + // FIXME(eddyb) Avoid wrapping the entries in docs. + self.ecx.start_tag(0).unwrap(); data.read(self.tcx); op(&mut self.ecx, data); self.ecx.end_tag().unwrap(); From 6742b239ac0e1fad2e3981b6201d5789b7298554 Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Mon, 5 Sep 2016 13:38:26 +0300 Subject: [PATCH 422/443] rustc_metadata: remove all unnecessary tables from astencode. --- src/librustc_metadata/astencode.rs | 82 +----------------------------- 1 file changed, 2 insertions(+), 80 deletions(-) diff --git a/src/librustc_metadata/astencode.rs b/src/librustc_metadata/astencode.rs index 9d4ed84993f1..c687353d437c 100644 --- a/src/librustc_metadata/astencode.rs +++ b/src/librustc_metadata/astencode.rs @@ -19,10 +19,9 @@ use decoder::DecodeContext; use encoder::EncodeContext; use middle::cstore::{InlinedItem, InlinedItemRef}; -use rustc::ty::adjustment; use rustc::hir::def; use rustc::hir::def_id::DefId; -use rustc::ty::{self, TyCtxt}; +use rustc::ty::TyCtxt; use syntax::ast; @@ -128,12 +127,8 @@ enum Table { Def, NodeType, ItemSubsts, - Freevars, - MethodMap, Adjustment, - UpvarCaptureMap, - ConstQualif, - CastKind + ConstQualif } fn encode_side_tables_for_id(ecx: &mut EncodeContext, id: ast::NodeId) { @@ -156,60 +151,11 @@ fn encode_side_tables_for_id(ecx: &mut EncodeContext, id: ast::NodeId) { item_substs.substs.encode(ecx).unwrap(); } - if let Some(fv) = tcx.freevars.borrow().get(&id) { - ecx.entry(Table::Freevars, id); - fv.encode(ecx).unwrap(); - - for freevar in fv { - ecx.entry(Table::UpvarCaptureMap, id); - let def_id = freevar.def.def_id(); - let var_id = tcx.map.as_local_node_id(def_id).unwrap(); - let upvar_id = ty::UpvarId { - var_id: var_id, - closure_expr_id: id - }; - let upvar_capture = tcx.tables - .borrow() - .upvar_capture_map - .get(&upvar_id) - .unwrap() - .clone(); - var_id.encode(ecx).unwrap(); - upvar_capture.encode(ecx).unwrap(); - } - } - - let method_call = ty::MethodCall::expr(id); - if let Some(method) = tcx.tables.borrow().method_map.get(&method_call) { - ecx.entry(Table::MethodMap, id); - method_call.autoderef.encode(ecx).unwrap(); - method.encode(ecx).unwrap(); - } - if let Some(adjustment) = tcx.tables.borrow().adjustments.get(&id) { - match *adjustment { - adjustment::AdjustDerefRef(ref adj) => { - for autoderef in 0..adj.autoderefs { - let method_call = ty::MethodCall::autoderef(id, autoderef as u32); - if let Some(method) = tcx.tables.borrow().method_map.get(&method_call) { - ecx.entry(Table::MethodMap, id); - method_call.autoderef.encode(ecx).unwrap(); - method.encode(ecx).unwrap(); - } - } - } - _ => {} - } - ecx.entry(Table::Adjustment, id); adjustment.encode(ecx).unwrap(); } - if let Some(cast_kind) = tcx.cast_kinds.borrow().get(&id) { - ecx.entry(Table::CastKind, id); - cast_kind.encode(ecx).unwrap(); - } - if let Some(qualif) = tcx.const_qualif_map.borrow().get(&id) { ecx.entry(Table::ConstQualif, id); qualif.encode(ecx).unwrap(); @@ -234,34 +180,10 @@ fn decode_side_tables(dcx: &mut DecodeContext, ast_doc: rbml::Doc) { let item_substs = Decodable::decode(dcx).unwrap(); dcx.tcx().tables.borrow_mut().item_substs.insert(id, item_substs); } - Table::Freevars => { - let fv_info = Decodable::decode(dcx).unwrap(); - dcx.tcx().freevars.borrow_mut().insert(id, fv_info); - } - Table::UpvarCaptureMap => { - let upvar_id = ty::UpvarId { - var_id: Decodable::decode(dcx).unwrap(), - closure_expr_id: id - }; - let ub = Decodable::decode(dcx).unwrap(); - dcx.tcx().tables.borrow_mut().upvar_capture_map.insert(upvar_id, ub); - } - Table::MethodMap => { - let method_call = ty::MethodCall { - expr_id: id, - autoderef: Decodable::decode(dcx).unwrap() - }; - let method = Decodable::decode(dcx).unwrap(); - dcx.tcx().tables.borrow_mut().method_map.insert(method_call, method); - } Table::Adjustment => { let adj = Decodable::decode(dcx).unwrap(); dcx.tcx().tables.borrow_mut().adjustments.insert(id, adj); } - Table::CastKind => { - let cast_kind = Decodable::decode(dcx).unwrap(); - dcx.tcx().cast_kinds.borrow_mut().insert(id, cast_kind); - } Table::ConstQualif => { let qualif = Decodable::decode(dcx).unwrap(); dcx.tcx().const_qualif_map.borrow_mut().insert(id, qualif); From ef4352fba6f0a93b55eeaf2c2cdf10f0e0401719 Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Thu, 8 Sep 2016 19:05:50 +0300 Subject: [PATCH 423/443] rustc_metadata: group information into less tags. --- src/librustc/hir/def.rs | 10 +- src/librustc/hir/pat_util.rs | 2 +- src/librustc/middle/cstore.rs | 11 +- src/librustc/middle/dead.rs | 6 +- src/librustc/middle/expr_use_visitor.rs | 3 +- src/librustc/middle/mem_categorization.rs | 13 +- src/librustc/ty/context.rs | 10 +- src/librustc/ty/item_path.rs | 2 +- src/librustc/ty/mod.rs | 18 +- src/librustc_const_eval/check_match.rs | 6 +- src/librustc_const_eval/eval.rs | 11 +- .../calculate_svh/svh_visitor.rs | 1 - src/librustc_metadata/astencode.rs | 2 +- src/librustc_metadata/common.rs | 176 ++- src/librustc_metadata/creader.rs | 65 +- src/librustc_metadata/csearch.rs | 92 +- src/librustc_metadata/cstore.rs | 20 +- src/librustc_metadata/decoder.rs | 687 ++++------- src/librustc_metadata/def_key.rs | 110 -- src/librustc_metadata/encoder.rs | 1071 ++++++----------- src/librustc_metadata/index.rs | 12 + src/librustc_metadata/lib.rs | 20 +- src/librustc_metadata/loader.rs | 33 +- src/librustc_mir/hair/cx/expr.rs | 8 +- src/librustc_mir/hair/cx/pattern.rs | 3 +- src/librustc_passes/static_recursion.rs | 14 +- src/librustc_privacy/lib.rs | 18 +- src/librustc_resolve/build_reduced_graph.rs | 26 +- src/librustc_resolve/lib.rs | 4 +- src/librustc_save_analysis/dump_visitor.rs | 3 +- src/librustc_typeck/astconv.rs | 5 +- src/librustc_typeck/check/mod.rs | 11 +- src/librustdoc/clean/inline.rs | 18 +- src/librustdoc/clean/mod.rs | 10 +- src/librustdoc/visit_lib.rs | 8 +- 35 files changed, 974 insertions(+), 1535 deletions(-) delete mode 100644 src/librustc_metadata/def_key.rs diff --git a/src/librustc/hir/def.rs b/src/librustc/hir/def.rs index fddf09c99056..dec8ea8a29c3 100644 --- a/src/librustc/hir/def.rs +++ b/src/librustc/hir/def.rs @@ -18,15 +18,14 @@ pub enum Def { Fn(DefId), SelfTy(Option /* trait */, Option /* impl */), Mod(DefId), - ForeignMod(DefId), Static(DefId, bool /* is_mutbl */), Const(DefId), AssociatedConst(DefId), Local(DefId), - Variant(DefId /* enum */, DefId /* variant */), + Variant(DefId), Enum(DefId), TyAlias(DefId), - AssociatedTy(DefId /* trait */, DefId), + AssociatedTy(DefId), Trait(DefId), PrimTy(hir::PrimTy), TyParam(DefId), @@ -101,8 +100,8 @@ pub struct Export { impl Def { pub fn def_id(&self) -> DefId { match *self { - Def::Fn(id) | Def::Mod(id) | Def::ForeignMod(id) | Def::Static(id, _) | - Def::Variant(_, id) | Def::Enum(id) | Def::TyAlias(id) | Def::AssociatedTy(_, id) | + Def::Fn(id) | Def::Mod(id) | Def::Static(id, _) | + Def::Variant(id) | Def::Enum(id) | Def::TyAlias(id) | Def::AssociatedTy(id) | Def::TyParam(id) | Def::Struct(id) | Def::Union(id) | Def::Trait(id) | Def::Method(id) | Def::Const(id) | Def::AssociatedConst(id) | Def::Local(id) | Def::Upvar(id, ..) => { @@ -122,7 +121,6 @@ impl Def { match *self { Def::Fn(..) => "function", Def::Mod(..) => "module", - Def::ForeignMod(..) => "foreign module", Def::Static(..) => "static", Def::Variant(..) => "variant", Def::Enum(..) => "enum", diff --git a/src/librustc/hir/pat_util.rs b/src/librustc/hir/pat_util.rs index a63bf14cb023..dec41fdfc3b5 100644 --- a/src/librustc/hir/pat_util.rs +++ b/src/librustc/hir/pat_util.rs @@ -174,7 +174,7 @@ pub fn necessary_variants(dm: &DefMap, pat: &hir::Pat) -> Vec { PatKind::Path(..) | PatKind::Struct(..) => { match dm.get(&p.id) { - Some(&PathResolution { base_def: Def::Variant(_, id), .. }) => { + Some(&PathResolution { base_def: Def::Variant(id), .. }) => { variants.push(id); } _ => () diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index e844ec37dc7c..87fdc858cf0f 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -135,11 +135,9 @@ pub trait CrateStore<'tcx> { fn closure_ty<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> ty::ClosureTy<'tcx>; fn item_variances(&self, def: DefId) -> Vec; - fn repr_attrs(&self, def: DefId) -> Vec; fn item_type<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> Ty<'tcx>; fn visible_parent_map<'a>(&'a self) -> ::std::cell::RefMut<'a, DefIdMap>; - fn item_name(&self, def: DefId) -> ast::Name; fn opt_item_name(&self, def: DefId) -> Option; fn item_predicates<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> ty::GenericPredicates<'tcx>; @@ -150,7 +148,7 @@ pub trait CrateStore<'tcx> { fn item_attrs(&self, def_id: DefId) -> Vec; fn trait_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)-> ty::TraitDef<'tcx>; fn adt_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> ty::AdtDefMaster<'tcx>; - fn method_arg_names(&self, did: DefId) -> Vec; + fn fn_arg_names(&self, did: DefId) -> Vec; fn inherent_implementations_for_type(&self, def_id: DefId) -> Vec; // trait info @@ -211,7 +209,6 @@ pub trait CrateStore<'tcx> { fn def_key(&self, def: DefId) -> hir_map::DefKey; fn relative_def_path(&self, def: DefId) -> Option; fn struct_ctor_def_id(&self, struct_def_id: DefId) -> Option; - fn tuple_struct_definition_if_ctor(&self, did: DefId) -> Option; fn struct_field_names(&self, def: DefId) -> Vec; fn item_children(&self, did: DefId) -> Vec; @@ -297,13 +294,11 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { fn closure_ty<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> ty::ClosureTy<'tcx> { bug!("closure_ty") } fn item_variances(&self, def: DefId) -> Vec { bug!("item_variances") } - fn repr_attrs(&self, def: DefId) -> Vec { bug!("repr_attrs") } fn item_type<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> Ty<'tcx> { bug!("item_type") } fn visible_parent_map<'a>(&'a self) -> ::std::cell::RefMut<'a, DefIdMap> { bug!("visible_parent_map") } - fn item_name(&self, def: DefId) -> ast::Name { bug!("item_name") } fn opt_item_name(&self, def: DefId) -> Option { bug!("opt_item_name") } fn item_predicates<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> ty::GenericPredicates<'tcx> { bug!("item_predicates") } @@ -316,7 +311,7 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { { bug!("trait_def") } fn adt_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> ty::AdtDefMaster<'tcx> { bug!("adt_def") } - fn method_arg_names(&self, did: DefId) -> Vec { bug!("method_arg_names") } + fn fn_arg_names(&self, did: DefId) -> Vec { bug!("fn_arg_names") } fn inherent_implementations_for_type(&self, def_id: DefId) -> Vec { vec![] } // trait info @@ -393,8 +388,6 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { } fn struct_ctor_def_id(&self, struct_def_id: DefId) -> Option { bug!("struct_ctor_def_id") } - fn tuple_struct_definition_if_ctor(&self, did: DefId) -> Option - { bug!("tuple_struct_definition_if_ctor") } fn struct_field_names(&self, def: DefId) -> Vec { bug!("struct_field_names") } fn item_children(&self, did: DefId) -> Vec { bug!("item_children") } diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index 70232d4f01e9..30a0c6a9dc93 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -108,8 +108,10 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { _ if self.ignore_non_const_paths => (), Def::PrimTy(_) => (), Def::SelfTy(..) => (), - Def::Variant(enum_id, variant_id) => { - self.check_def_id(enum_id); + Def::Variant(variant_id) => { + if let Some(enum_id) = self.tcx.parent_def_id(variant_id) { + self.check_def_id(enum_id); + } if !self.ignore_variant_stack.contains(&variant_id) { self.check_def_id(variant_id); } diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index ec3fe3903179..5b5c3da8f05b 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -1003,7 +1003,8 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { // the leaves of the pattern tree structure. return_if_err!(mc.cat_pattern(cmt_discr, pat, |mc, cmt_pat, pat| { match tcx.expect_def_or_none(pat.id) { - Some(Def::Variant(enum_did, variant_did)) => { + Some(Def::Variant(variant_did)) => { + let enum_did = tcx.parent_def_id(variant_did).unwrap(); let downcast_cmt = if tcx.lookup_adt_def(enum_did).is_univariant() { cmt_pat } else { diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 26cc6007ed07..340a5ac8f87b 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -529,7 +529,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { Ok(self.cat_rvalue_node(id, span, expr_ty)) } - Def::Mod(_) | Def::ForeignMod(_) | + Def::Mod(_) | Def::Trait(_) | Def::Enum(..) | Def::TyAlias(..) | Def::PrimTy(_) | Def::TyParam(..) | Def::Label(_) | Def::SelfTy(..) | @@ -1077,18 +1077,23 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { // alone) because PatKind::Struct can also refer to variants. let cmt = match self.tcx().expect_def_or_none(pat.id) { Some(Def::Err) => return Err(()), - Some(Def::Variant(enum_did, variant_did)) + Some(Def::Variant(variant_did)) => { // univariant enums do not need downcasts - if !self.tcx().lookup_adt_def(enum_did).is_univariant() => { + let enum_did = self.tcx().parent_def_id(variant_did).unwrap(); + if !self.tcx().lookup_adt_def(enum_did).is_univariant() { self.cat_downcast(pat, cmt.clone(), cmt.ty, variant_did) + } else { + cmt } + } _ => cmt }; match pat.node { PatKind::TupleStruct(_, ref subpats, ddpos) => { let expected_len = match self.tcx().expect_def(pat.id) { - Def::Variant(enum_def, def_id) => { + Def::Variant(def_id) => { + let enum_def = self.tcx().parent_def_id(def_id).unwrap(); self.tcx().lookup_adt_def(enum_def).variant_with_id(def_id).fields.len() } Def::Struct(..) => { diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 1c9238646df2..0faf6750abd9 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -1404,13 +1404,9 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// Obtain the representation annotation for a struct definition. pub fn lookup_repr_hints(self, did: DefId) -> Rc> { self.repr_hint_cache.memoize(did, || { - Rc::new(if did.is_local() { - self.get_attrs(did).iter().flat_map(|meta| { - attr::find_repr_attrs(self.sess.diagnostic(), meta).into_iter() - }).collect() - } else { - self.sess.cstore.repr_attrs(did) - }) + Rc::new(self.get_attrs(did).iter().flat_map(|meta| { + attr::find_repr_attrs(self.sess.diagnostic(), meta).into_iter() + }).collect()) }) } } diff --git a/src/librustc/ty/item_path.rs b/src/librustc/ty/item_path.rs index e4247a60b15e..5f121b568c3a 100644 --- a/src/librustc/ty/item_path.rs +++ b/src/librustc/ty/item_path.rs @@ -303,7 +303,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// Returns the def-id of `def_id`'s parent in the def tree. If /// this returns `None`, then `def_id` represents a crate root or /// inlined root. - fn parent_def_id(&self, def_id: DefId) -> Option { + pub fn parent_def_id(self, def_id: DefId) -> Option { let key = self.def_key(def_id); key.parent.map(|index| DefId { krate: def_id.krate, index: index }) } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 8aba6329b090..8171a99beb90 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -193,7 +193,7 @@ impl<'tcx> ImplOrTraitItem<'tcx> { match *self { ConstTraitItem(ref associated_const) => Def::AssociatedConst(associated_const.def_id), MethodTraitItem(ref method) => Def::Method(method.def_id), - TypeTraitItem(ref ty) => Def::AssociatedTy(ty.container.id(), ty.def_id), + TypeTraitItem(ref ty) => Def::AssociatedTy(ty.def_id), } } @@ -1666,7 +1666,7 @@ impl<'a, 'gcx, 'tcx, 'container> AdtDefData<'gcx, 'container> { pub fn variant_of_def(&self, def: Def) -> &VariantDefData<'gcx, 'container> { match def { - Def::Variant(_, vid) => self.variant_with_id(vid), + Def::Variant(vid) => self.variant_with_id(vid), Def::Struct(..) | Def::Union(..) | Def::TyAlias(..) | Def::AssociatedTy(..) => self.struct_variant(), _ => bug!("unexpected def {:?} in variant_of_def", def) @@ -2325,7 +2325,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // or variant or their constructors, panics otherwise. pub fn expect_variant_def(self, def: Def) -> VariantDef<'tcx> { match def { - Def::Variant(enum_did, did) => { + Def::Variant(did) => { + let enum_did = self.parent_def_id(did).unwrap(); self.lookup_adt_def(enum_did).variant_with_id(did) } Def::Struct(did) | Def::Union(did) => { @@ -2387,7 +2388,9 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { if let Some(id) = self.map.as_local_node_id(id) { self.map.name(id) } else { - self.sess.cstore.item_name(id) + self.sess.cstore.opt_item_name(id).unwrap_or_else(|| { + bug!("item_name: no name for {:?}", self.def_path(id)); + }) } } @@ -2631,11 +2634,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { let trait_ref = self.impl_trait_ref(impl_def_id).unwrap(); // Record the trait->implementation mapping. - if let Some(parent) = self.sess.cstore.impl_parent(impl_def_id) { - def.record_remote_impl(self, impl_def_id, trait_ref, parent); - } else { - def.record_remote_impl(self, impl_def_id, trait_ref, trait_id); - } + let parent = self.sess.cstore.impl_parent(impl_def_id).unwrap_or(trait_id); + def.record_remote_impl(self, impl_def_id, trait_ref, parent); // For any methods that use a default implementation, add them to // the map. This is a bit unfortunate. diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs index 8af06286189b..eb74936d8c90 100644 --- a/src/librustc_const_eval/check_match.rs +++ b/src/librustc_const_eval/check_match.rs @@ -801,7 +801,7 @@ fn pat_constructors(cx: &MatchCheckCtxt, p: &Pat, match pat.node { PatKind::Struct(..) | PatKind::TupleStruct(..) | PatKind::Path(..) => match cx.tcx.expect_def(pat.id) { - Def::Variant(_, id) => vec![Variant(id)], + Def::Variant(id) => vec![Variant(id)], Def::Struct(..) | Def::Union(..) | Def::TyAlias(..) | Def::AssociatedTy(..) => vec![Single], Def::Const(..) | Def::AssociatedConst(..) => @@ -913,7 +913,7 @@ pub fn specialize<'a, 'b, 'tcx>( Def::Const(..) | Def::AssociatedConst(..) => span_bug!(pat_span, "const pattern should've \ been rewritten"), - Def::Variant(_, id) if *constructor != Variant(id) => None, + Def::Variant(id) if *constructor != Variant(id) => None, Def::Variant(..) | Def::Struct(..) => Some(Vec::new()), def => span_bug!(pat_span, "specialize: unexpected \ definition {:?}", def), @@ -925,7 +925,7 @@ pub fn specialize<'a, 'b, 'tcx>( Def::Const(..) | Def::AssociatedConst(..) => span_bug!(pat_span, "const pattern should've \ been rewritten"), - Def::Variant(_, id) if *constructor != Variant(id) => None, + Def::Variant(id) if *constructor != Variant(id) => None, Def::Variant(..) | Def::Struct(..) => { match ddpos { Some(ddpos) => { diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index aa53fdd6e7e2..dce3882004c6 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -57,7 +57,6 @@ macro_rules! math { } fn lookup_variant_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - enum_def: DefId, variant_def: DefId) -> Option<&'tcx Expr> { fn variant_expr<'a>(variants: &'a [hir::Variant], id: ast::NodeId) @@ -70,8 +69,8 @@ fn lookup_variant_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, None } - if let Some(enum_node_id) = tcx.map.as_local_node_id(enum_def) { - let variant_node_id = tcx.map.as_local_node_id(variant_def).unwrap(); + if let Some(variant_node_id) = tcx.map.as_local_node_id(variant_def) { + let enum_node_id = tcx.map.get_parent(variant_node_id); match tcx.map.find(enum_node_id) { None => None, Some(ast_map::NodeItem(it)) => match it.node { @@ -289,7 +288,7 @@ pub fn const_expr_to_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } let path = match def { Def::Struct(def_id) => def_to_path(tcx, def_id), - Def::Variant(_, variant_did) => def_to_path(tcx, variant_did), + Def::Variant(variant_did) => def_to_path(tcx, variant_did), Def::Fn(..) | Def::Method(..) => return Ok(P(hir::Pat { id: expr.id, node: PatKind::Lit(P(expr.clone())), @@ -808,8 +807,8 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, signal!(e, NonConstPath); } }, - Def::Variant(enum_def, variant_def) => { - if let Some(const_expr) = lookup_variant_by_id(tcx, enum_def, variant_def) { + Def::Variant(variant_def) => { + if let Some(const_expr) = lookup_variant_by_id(tcx, variant_def) { match eval_const_expr_partial(tcx, const_expr, ty_hint, None) { Ok(val) => val, Err(err) => { diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs index af8ec6c62578..9950f470a82c 100644 --- a/src/librustc_incremental/calculate_svh/svh_visitor.rs +++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs @@ -602,7 +602,6 @@ impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> { // def-id is the same, so it suffices to hash the def-id Def::Fn(..) | Def::Mod(..) | - Def::ForeignMod(..) | Def::Static(..) | Def::Variant(..) | Def::Enum(..) | diff --git a/src/librustc_metadata/astencode.rs b/src/librustc_metadata/astencode.rs index c687353d437c..518e66244121 100644 --- a/src/librustc_metadata/astencode.rs +++ b/src/librustc_metadata/astencode.rs @@ -18,7 +18,7 @@ use cstore::CrateMetadata; use decoder::DecodeContext; use encoder::EncodeContext; -use middle::cstore::{InlinedItem, InlinedItemRef}; +use rustc::middle::cstore::{InlinedItem, InlinedItemRef}; use rustc::hir::def; use rustc::hir::def_id::DefId; use rustc::ty::TyCtxt; diff --git a/src/librustc_metadata/common.rs b/src/librustc_metadata/common.rs index 04b9b7f7c671..e068395f729a 100644 --- a/src/librustc_metadata/common.rs +++ b/src/librustc_metadata/common.rs @@ -10,29 +10,36 @@ #![allow(non_camel_case_types, non_upper_case_globals)] +use rustc::hir; +use rustc::hir::def; +use rustc::hir::def_id::{DefIndex, DefId}; use rustc::ty; +use rustc::session::config::PanicStrategy; #[derive(Clone, Copy, Debug, PartialEq, RustcEncodable, RustcDecodable)] pub enum Family { ImmStatic, MutStatic, + ForeignImmStatic, + ForeignMutStatic, Fn, + ForeignFn, Method, AssociatedType, Type, Mod, ForeignMod, Enum, - Variant(ty::VariantKind), + Variant, Impl, DefaultImpl, Trait, - Struct(ty::VariantKind), + Struct, Union, - PublicField, - InheritedField, + Field, Const, AssociatedConst, + Closure } // NB: increment this if you change the format of metadata such that @@ -48,68 +55,151 @@ pub fn rustc_version() -> String { ) } +#[derive(RustcEncodable, RustcDecodable)] +pub struct CrateInfo { + pub name: String, + pub triple: String, + pub hash: hir::svh::Svh, + pub disambiguator: String, + pub panic_strategy: PanicStrategy, + pub plugin_registrar_fn: Option, + pub macro_derive_registrar: Option +} + pub mod root_tag { pub const rustc_version: usize = 0x10f; - pub const crate_deps: usize = 0x102; - pub const crate_hash: usize = 0x103; - pub const crate_crate_name: usize = 0x104; - pub const crate_disambiguator: usize = 0x113; - pub const items: usize = 0x100; + + pub const crate_info: usize = 0x104; + pub const index: usize = 0x110; pub const xref_index: usize = 0x111; pub const xref_data: usize = 0x112; - pub const crate_triple: usize = 0x105; + pub const crate_deps: usize = 0x102; pub const dylib_dependency_formats: usize = 0x106; + pub const native_libraries: usize = 0x10a; pub const lang_items: usize = 0x107; pub const lang_items_missing: usize = 0x76; pub const impls: usize = 0x109; - pub const native_libraries: usize = 0x10a; - pub const plugin_registrar_fn: usize = 0x10b; - pub const panic_strategy: usize = 0x114; - pub const macro_derive_registrar: usize = 0x115; pub const reachable_ids: usize = 0x10c; pub const macro_defs: usize = 0x10e; pub const codemap: usize = 0xa1; } +#[derive(RustcEncodable, RustcDecodable)] +pub struct ModData { + pub reexports: Vec +} + +#[derive(RustcEncodable, RustcDecodable)] +pub struct VariantData { + pub kind: ty::VariantKind, + pub disr: u64, + + /// If this is a struct's only variant, this + /// is the index of the "struct ctor" item. + pub struct_ctor: Option +} + +#[derive(RustcEncodable, RustcDecodable)] +pub struct TraitData { + pub unsafety: hir::Unsafety, + pub paren_sugar: bool, + pub has_default_impl: bool +} + +#[derive(RustcEncodable, RustcDecodable)] +pub struct ImplData { + pub polarity: hir::ImplPolarity, + pub parent_impl: Option, + pub coerce_unsized_kind: Option, +} + +#[derive(RustcEncodable, RustcDecodable)] +pub struct TraitAssociatedData { + pub has_default: bool +} + +#[derive(RustcEncodable, RustcDecodable)] +pub struct ImplAssociatedData { + pub defaultness: hir::Defaultness, + pub constness: hir::Constness +} + +#[derive(RustcEncodable, RustcDecodable)] +pub struct FnData { + pub constness: hir::Constness +} + +#[derive(RustcEncodable, RustcDecodable)] +pub struct ClosureData { + pub kind: ty::ClosureKind +} + +#[derive(RustcEncodable, RustcDecodable)] +pub enum EntryData { + Other, + Mod(ModData), + Variant(VariantData), + Trait(TraitData), + Impl(ImplData), + TraitAssociated(TraitAssociatedData), + ImplAssociated(ImplAssociatedData), + Fn(FnData), + Closure(ClosureData) +} + +#[derive(RustcEncodable, RustcDecodable)] +pub struct TraitTypedData<'tcx> { + pub trait_ref: ty::TraitRef<'tcx> +} + +#[derive(RustcEncodable, RustcDecodable)] +pub struct ImplTypedData<'tcx> { + pub trait_ref: Option> +} + +#[derive(RustcEncodable, RustcDecodable)] +pub struct MethodTypedData<'tcx> { + pub explicit_self: ty::ExplicitSelfCategory<'tcx> +} + +#[derive(RustcEncodable, RustcDecodable)] +pub struct ClosureTypedData<'tcx> { + pub ty: ty::ClosureTy<'tcx> +} + +#[derive(RustcEncodable, RustcDecodable)] +pub enum EntryTypedData<'tcx> { + Other, + Trait(TraitTypedData<'tcx>), + Impl(ImplTypedData<'tcx>), + Method(MethodTypedData<'tcx>), + Closure(ClosureTypedData<'tcx>) +} + pub mod item_tag { - pub const name: usize = 0x20; - pub const def_index: usize = 0x21; - pub const family: usize = 0x24; - pub const ty: usize = 0x25; - pub const parent_item: usize = 0x28; - pub const is_tuple_struct_ctor: usize = 0x29; - pub const closure_kind: usize = 0x2a; - pub const closure_ty: usize = 0x2b; pub const def_key: usize = 0x2c; + pub const family: usize = 0x24; pub const attributes: usize = 0x101; - pub const trait_ref: usize = 0x3b; - pub const disr_val: usize = 0x3c; - pub const fields: usize = 0x41; - pub const variances: usize = 0x43; - pub const trait_method_explicit_self: usize = 0x45; - pub const ast: usize = 0x50; - pub const mir: usize = 0x52; - pub const trait_item_has_body: usize = 0x70; pub const visibility: usize = 0x78; - pub const inherent_impls: usize = 0x79; pub const children: usize = 0x7b; - pub const method_argument_names: usize = 0x85; pub const stability: usize = 0x88; - pub const repr: usize = 0x89; - pub const struct_ctor: usize = 0x8b; + pub const deprecation: usize = 0xa7; + + pub const ty: usize = 0x25; + pub const inherent_impls: usize = 0x79; + pub const variances: usize = 0x43; pub const generics: usize = 0x8f; pub const predicates: usize = 0x95; - pub const unsafety: usize = 0x9a; - pub const polarity: usize = 0x9d; - pub const paren_sugar: usize = 0xa0; pub const super_predicates: usize = 0xa3; - pub const defaulted_trait: usize = 0xa4; - pub const impl_coerce_unsized_kind: usize = 0xa5; - pub const constness: usize = 0xa6; - pub const deprecation: usize = 0xa7; - pub const defaultness: usize = 0xa8; - pub const parent_impl: usize = 0xa9; + + pub const ast: usize = 0x50; + pub const mir: usize = 0x52; + + pub const data: usize = 0x3c; + pub const typed_data: usize = 0x3d; + + pub const fn_arg_names: usize = 0x85; } /// The shorthand encoding of `Ty` uses `TypeVariants`' variant `usize` diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 7b6ed4e6b764..dd6ef73ccdbd 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -12,6 +12,7 @@ //! Validates all used crates and extern libraries and loads their metadata +use common::CrateInfo; use cstore::{self, CStore, CrateSource, MetadataBlob}; use decoder; use loader::{self, CratePaths}; @@ -85,7 +86,7 @@ fn should_link(i: &ast::Item) -> bool { } #[derive(Debug)] -struct CrateInfo { +struct ExternCrateInfo { ident: String, name: String, id: ast::NodeId, @@ -183,7 +184,7 @@ impl<'a> CrateReader<'a> { } } - fn extract_crate_info(&self, i: &ast::Item) -> Option { + fn extract_crate_info(&self, i: &ast::Item) -> Option { match i.node { ast::ItemKind::ExternCrate(ref path_opt) => { debug!("resolving extern crate stmt. ident: {} path_opt: {:?}", @@ -196,7 +197,7 @@ impl<'a> CrateReader<'a> { } None => i.ident.to_string(), }; - Some(CrateInfo { + Some(ExternCrateInfo { ident: i.ident.to_string(), name: name, id: i.id, @@ -258,32 +259,28 @@ impl<'a> CrateReader<'a> { fn verify_no_symbol_conflicts(&self, span: Span, - metadata: &MetadataBlob) { - let disambiguator = decoder::get_crate_disambiguator(metadata.as_slice()); - let crate_name = decoder::get_crate_name(metadata.as_slice()); - + info: &CrateInfo) { // Check for (potential) conflicts with the local crate - if self.local_crate_name == crate_name && - self.sess.local_crate_disambiguator() == &disambiguator[..] { + if self.local_crate_name == info.name && + self.sess.local_crate_disambiguator() == &info.disambiguator[..] { span_fatal!(self.sess, span, E0519, "the current crate is indistinguishable from one of its \ dependencies: it has the same crate-name `{}` and was \ compiled with the same `-C metadata` arguments. This \ will result in symbol conflicts between the two.", - crate_name) + info.name) } - let svh = decoder::get_crate_hash(metadata.as_slice()); // Check for conflicts with any crate loaded so far self.cstore.iter_crate_data(|_, other| { - if other.name() == crate_name && // same crate-name - other.disambiguator() == disambiguator && // same crate-disambiguator - other.hash() != svh { // but different SVH + if other.name() == info.name && // same crate-name + other.disambiguator() == info.disambiguator && // same crate-disambiguator + other.hash() != info.hash { // but different SVH span_fatal!(self.sess, span, E0523, "found two different crates with name `{}` that are \ not distinguished by differing `-C metadata`. This \ will result in symbol conflicts between the two.", - crate_name) + info.name) } }); } @@ -298,7 +295,8 @@ impl<'a> CrateReader<'a> { -> (CrateNum, Rc, cstore::CrateSource) { info!("register crate `extern crate {} as {}`", name, ident); - self.verify_no_symbol_conflicts(span, &lib.metadata); + let crate_info = decoder::get_crate_info(lib.metadata.as_slice()); + self.verify_no_symbol_conflicts(span, &crate_info); // Claim this crate number and cache it let cnum = self.next_crate_num; @@ -321,9 +319,15 @@ impl<'a> CrateReader<'a> { let cnum_map = self.resolve_crate_deps(root, metadata.as_slice(), cnum, span); + if crate_info.macro_derive_registrar.is_some() { + self.sess.span_err(span, "crates of the `rustc-macro` crate type \ + cannot be linked at runtime"); + } + let cmeta = Rc::new(cstore::CrateMetadata { name: name.to_string(), extern_crate: Cell::new(None), + info: crate_info, index: decoder::load_index(metadata.as_slice()), xref_index: decoder::load_xrefs(metadata.as_slice()), key_map: decoder::load_key_map(metadata.as_slice()), @@ -334,11 +338,6 @@ impl<'a> CrateReader<'a> { explicitly_linked: Cell::new(explicitly_linked), }); - if decoder::get_derive_registrar_fn(cmeta.data.as_slice()).is_some() { - self.sess.span_err(span, "crates of the `rustc-macro` crate type \ - cannot be linked at runtime"); - } - let source = cstore::CrateSource { dylib: dylib, rlib: rlib, @@ -416,13 +415,11 @@ impl<'a> CrateReader<'a> { // Note that we only do this for target triple crates, though, as we // don't want to match a host crate against an equivalent target one // already loaded. + let crate_info = decoder::get_crate_info(library.metadata.as_slice()); if loader.triple == self.sess.opts.target_triple { - let meta_hash = decoder::get_crate_hash(library.metadata.as_slice()); - let meta_name = decoder::get_crate_name(library.metadata.as_slice()) - .to_string(); let mut result = LoadResult::Loaded(library); self.cstore.iter_crate_data(|cnum, data| { - if data.name() == meta_name && meta_hash == data.hash() { + if data.name() == crate_info.name && crate_info.hash == data.hash() { assert!(loader.hash.is_none()); info!("load success, going to previous cnum: {}", cnum); result = LoadResult::Previous(cnum); @@ -497,7 +494,7 @@ impl<'a> CrateReader<'a> { }).collect() } - fn read_extension_crate(&mut self, span: Span, info: &CrateInfo) -> ExtensionCrate { + fn read_extension_crate(&mut self, span: Span, info: &ExternCrateInfo) -> ExtensionCrate { info!("read extension crate {} `extern crate {} as {}` linked={}", info.id, info.name, info.ident, info.should_link); let target_triple = &self.sess.opts.target_triple[..]; @@ -570,11 +567,12 @@ impl<'a> CrateReader<'a> { let ci = self.extract_crate_info(item).unwrap(); let ekrate = self.read_extension_crate(item.span, &ci); + let crate_info = decoder::get_crate_info(ekrate.metadata.as_slice()); let source_name = format!("<{} macros>", item.ident); let mut ret = Macros { macro_rules: Vec::new(), custom_derive_registrar: None, - svh: decoder::get_crate_hash(ekrate.metadata.as_slice()), + svh: crate_info.hash, dylib: None, }; decoder::each_exported_macro(ekrate.metadata.as_slice(), @@ -619,7 +617,7 @@ impl<'a> CrateReader<'a> { true }); - match decoder::get_derive_registrar_fn(ekrate.metadata.as_slice()) { + match crate_info.macro_derive_registrar { Some(id) => ret.custom_derive_registrar = Some(id), // If this crate is not a rustc-macro crate then we might be able to @@ -656,7 +654,7 @@ impl<'a> CrateReader<'a> { /// SVH and DefIndex of the registrar function. pub fn find_plugin_registrar(&mut self, span: Span, name: &str) -> Option<(PathBuf, Svh, DefIndex)> { - let ekrate = self.read_extension_crate(span, &CrateInfo { + let ekrate = self.read_extension_crate(span, &ExternCrateInfo { name: name.to_string(), ident: name.to_string(), id: ast::DUMMY_NODE_ID, @@ -673,13 +671,10 @@ impl<'a> CrateReader<'a> { span_fatal!(self.sess, span, E0456, "{}", &message[..]); } - let svh = decoder::get_crate_hash(ekrate.metadata.as_slice()); - let registrar = - decoder::get_plugin_registrar_fn(ekrate.metadata.as_slice()); - - match (ekrate.dylib.as_ref(), registrar) { + let crate_info = decoder::get_crate_info(ekrate.metadata.as_slice()); + match (ekrate.dylib.as_ref(), crate_info.plugin_registrar_fn) { (Some(dylib), Some(reg)) => { - Some((dylib.to_path_buf(), svh, reg)) + Some((dylib.to_path_buf(), crate_info.hash, reg)) } (None, Some(_)) => { span_err!(self.sess, span, E0457, diff --git a/src/librustc_metadata/csearch.rs b/src/librustc_metadata/csearch.rs index c4ce7af269da..f650155c0354 100644 --- a/src/librustc_metadata/csearch.rs +++ b/src/librustc_metadata/csearch.rs @@ -14,10 +14,10 @@ use decoder; use encoder; use loader; -use middle::cstore::{InlinedItem, CrateStore, CrateSource, ChildItem, ExternCrate}; -use middle::cstore::{NativeLibraryKind, LinkMeta, LinkagePreference}; +use rustc::middle::cstore::{InlinedItem, CrateStore, CrateSource, ChildItem, ExternCrate}; +use rustc::middle::cstore::{NativeLibraryKind, LinkMeta, LinkagePreference}; use rustc::hir::def; -use middle::lang_items; +use rustc::middle::lang_items; use rustc::ty::{self, Ty, TyCtxt}; use rustc::hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX}; @@ -77,12 +77,6 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { decoder::get_item_variances(&cdata, def.index) } - fn repr_attrs(&self, def: DefId) -> Vec { - self.dep_graph.read(DepNode::MetaData(def)); - let cdata = self.get_crate_data(def.krate); - decoder::get_repr_attrs(&cdata, def.index) - } - fn item_type<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> Ty<'tcx> { @@ -136,23 +130,21 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { decoder::get_adt_def(&cdata, def.index, tcx) } - fn method_arg_names(&self, did: DefId) -> Vec + fn fn_arg_names(&self, did: DefId) -> Vec { self.dep_graph.read(DepNode::MetaData(did)); let cdata = self.get_crate_data(did.krate); - decoder::get_method_arg_names(&cdata, did.index) - } - - fn item_name(&self, def: DefId) -> ast::Name { - self.dep_graph.read(DepNode::MetaData(def)); - let cdata = self.get_crate_data(def.krate); - decoder::get_item_name(&cdata, def.index) + decoder::get_fn_arg_names(&cdata, did.index) } fn opt_item_name(&self, def: DefId) -> Option { self.dep_graph.read(DepNode::MetaData(def)); let cdata = self.get_crate_data(def.krate); - decoder::maybe_get_item_name(&cdata, def.index) + if def.index == CRATE_DEF_INDEX { + Some(token::intern(&cdata.name())) + } else { + decoder::maybe_get_item_name(&cdata, def.index) + } } fn inherent_implementations_for_type(&self, def_id: DefId) -> Vec @@ -183,10 +175,9 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { self.dep_graph.read(DepNode::MetaData(def_id)); let mut result = vec![]; let crate_data = self.get_crate_data(def_id.krate); - let get_crate_data = |cnum| self.get_crate_data(cnum); - decoder::each_child_of_item(&crate_data, def_id.index, get_crate_data, |def, _, _| { - result.push(def.def_id()); - }); + let get_crate_data = &mut |cnum| self.get_crate_data(cnum); + decoder::each_child_of_item(&crate_data, def_id.index, get_crate_data, + &mut |def, _, _| result.push(def.def_id())); result } @@ -339,20 +330,17 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { fn crate_hash(&self, cnum: CrateNum) -> Svh { - let cdata = self.get_crate_data(cnum); - decoder::get_crate_hash(cdata.data()) + self.get_crate_hash(cnum) } fn crate_disambiguator(&self, cnum: CrateNum) -> token::InternedString { - let cdata = self.get_crate_data(cnum); - token::intern_and_get_ident(&decoder::get_crate_disambiguator(cdata.data())) + token::intern_and_get_ident(&self.get_crate_data(cnum).disambiguator()) } fn plugin_registrar_fn(&self, cnum: CrateNum) -> Option { - let cdata = self.get_crate_data(cnum); - decoder::get_plugin_registrar_fn(cdata.data()).map(|index| DefId { + self.get_crate_data(cnum).info.plugin_registrar_fn.map(|index| DefId { krate: cnum, index: index }) @@ -412,13 +400,6 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { decoder::get_struct_ctor_def_id(&cdata, struct_def_id.index) } - fn tuple_struct_definition_if_ctor(&self, did: DefId) -> Option - { - self.dep_graph.read(DepNode::MetaData(did)); - let cdata = self.get_crate_data(did.krate); - decoder::get_tuple_struct_definition_if_ctor(&cdata, did.index) - } - fn struct_field_names(&self, def: DefId) -> Vec { self.dep_graph.read(DepNode::MetaData(def)); @@ -431,8 +412,9 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { self.dep_graph.read(DepNode::MetaData(def_id)); let mut result = vec![]; let crate_data = self.get_crate_data(def_id.krate); - let get_crate_data = |cnum| self.get_crate_data(cnum); - decoder::each_child_of_item(&crate_data, def_id.index, get_crate_data, |def, name, vis| { + let get_crate_data = &mut |cnum| self.get_crate_data(cnum); + decoder::each_child_of_item(&crate_data, def_id.index, get_crate_data, + &mut |def, name, vis| { result.push(ChildItem { def: def, name: name, vis: vis }); }); result @@ -497,45 +479,17 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { }; match inlined { - decoder::FoundAst::NotFound => { + None => { self.inlined_item_cache .borrow_mut() .insert(def_id, None); } - decoder::FoundAst::Found(&InlinedItem::Item(d, ref item)) => { + Some(&InlinedItem::Item(d, ref item)) => { assert_eq!(d, def_id); let inlined_root_node_id = find_inlined_item_root(item.id); cache_inlined_item(def_id, item.id, inlined_root_node_id); } - decoder::FoundAst::FoundParent(parent_did, item) => { - let inlined_root_node_id = find_inlined_item_root(item.id); - cache_inlined_item(parent_did, item.id, inlined_root_node_id); - - match item.node { - hir::ItemEnum(ref ast_def, _) => { - let ast_vs = &ast_def.variants; - let ty_vs = &tcx.lookup_adt_def(parent_did).variants; - assert_eq!(ast_vs.len(), ty_vs.len()); - for (ast_v, ty_v) in ast_vs.iter().zip(ty_vs.iter()) { - cache_inlined_item(ty_v.did, - ast_v.node.data.id(), - inlined_root_node_id); - } - } - hir::ItemStruct(ref struct_def, _) => { - if struct_def.is_struct() { - bug!("instantiate_inline: called on a non-tuple struct") - } else { - cache_inlined_item(def_id, - struct_def.id(), - inlined_root_node_id); - } - } - _ => bug!("instantiate_inline: item has a \ - non-enum, non-struct parent") - } - } - decoder::FoundAst::Found(&InlinedItem::TraitItem(_, ref trait_item)) => { + Some(&InlinedItem::TraitItem(_, ref trait_item)) => { let inlined_root_node_id = find_inlined_item_root(trait_item.id); cache_inlined_item(def_id, trait_item.id, inlined_root_node_id); @@ -548,7 +502,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { tcx.impl_or_trait_items.borrow_mut() .insert(trait_item_def_id, ty_trait_item); } - decoder::FoundAst::Found(&InlinedItem::ImplItem(_, ref impl_item)) => { + Some(&InlinedItem::ImplItem(_, ref impl_item)) => { let inlined_root_node_id = find_inlined_item_root(impl_item.id); cache_inlined_item(def_id, impl_item.id, inlined_root_node_id); } diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs index 7aa4677353bb..c6cbe6db9098 100644 --- a/src/librustc_metadata/cstore.rs +++ b/src/librustc_metadata/cstore.rs @@ -39,9 +39,9 @@ use syntax::attr; use syntax::codemap; use syntax_pos; -pub use middle::cstore::{NativeLibraryKind, LinkagePreference}; -pub use middle::cstore::{NativeStatic, NativeFramework, NativeUnknown}; -pub use middle::cstore::{CrateSource, LinkMeta}; +pub use rustc::middle::cstore::{NativeLibraryKind, LinkagePreference}; +pub use rustc::middle::cstore::{NativeStatic, NativeFramework, NativeUnknown}; +pub use rustc::middle::cstore::{CrateSource, LinkMeta}; // A map from external crate numbers (as decoded from some crate file) to // local crate numbers (as generated during this session). Each external @@ -78,6 +78,7 @@ pub struct CrateMetadata { pub cnum: CrateNum, pub codemap_import_info: RefCell>, + pub info: common::CrateInfo, pub index: index::Index, pub xref_index: index::DenseIndex, @@ -143,8 +144,7 @@ impl CStore { } pub fn get_crate_hash(&self, cnum: CrateNum) -> Svh { - let cdata = self.get_crate_data(cnum); - decoder::get_crate_hash(cdata.data()) + self.get_crate_data(cnum).hash() } pub fn set_crate_data(&self, cnum: CrateNum, data: Rc) { @@ -299,11 +299,9 @@ impl CStore { impl CrateMetadata { pub fn data<'a>(&'a self) -> &'a [u8] { self.data.as_slice() } - pub fn name(&self) -> String { decoder::get_crate_name(self.data()) } - pub fn hash(&self) -> Svh { decoder::get_crate_hash(self.data()) } - pub fn disambiguator(&self) -> String { - decoder::get_crate_disambiguator(self.data()) - } + pub fn name(&self) -> &str { &self.info.name } + pub fn hash(&self) -> Svh { self.info.hash } + pub fn disambiguator(&self) -> &str { &self.info.disambiguator } pub fn imported_filemaps<'a>(&'a self, codemap: &codemap::CodeMap) -> Ref<'a, Vec> { let filemaps = self.codemap_import_info.borrow(); @@ -352,7 +350,7 @@ impl CrateMetadata { } pub fn panic_strategy(&self) -> PanicStrategy { - decoder::get_panic_strategy(self.data()) + self.info.panic_strategy.clone() } } diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 662236be0f0d..f3283451b93b 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -15,25 +15,22 @@ use astencode::decode_inlined_item; use cstore::{self, CrateMetadata}; use common::*; -use common::Family::*; -use def_key; use index; use rustc::hir::def_id::CRATE_DEF_INDEX; use rustc::hir::svh::Svh; use rustc::hir::map as hir_map; -use rustc::hir::map::DefKey; +use rustc::hir::map::{DefKey, DefPathData}; use rustc::util::nodemap::FnvHashMap; use rustc::hir; use rustc::hir::intravisit::IdRange; -use rustc::session::config::PanicStrategy; -use middle::cstore::{InlinedItem, LinkagePreference}; -use rustc::hir::def::{self, Def}; +use rustc::middle::cstore::{InlinedItem, LinkagePreference}; +use rustc::hir::def::Def; use rustc::hir::def_id::{CrateNum, DefId, DefIndex, LOCAL_CRATE}; -use middle::lang_items; +use rustc::middle::lang_items; use rustc::ty::{ImplContainer, TraitContainer}; -use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; +use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::subst::Substs; use rustc_const_math::ConstInt; @@ -51,6 +48,7 @@ use rbml; use rustc_serialize::{Decodable, Decoder, SpecializedDecoder, opaque}; use syntax::attr; use syntax::ast::{self, NodeId}; +use syntax::parse::token; use syntax_pos::{self, Span, BytePos}; pub struct DecodeContext<'a, 'tcx: 'a> { @@ -101,12 +99,6 @@ impl<'a, 'tcx> DecodeContext<'a, 'tcx> { self.decode() }) } - - pub fn seq_mut<'b, T: Decodable>(&'b mut self) -> impl Iterator + 'b { - (0..self.read_usize().unwrap()).map(move |_| { - self.decode() - }) - } } macro_rules! decoder_methods { @@ -321,6 +313,13 @@ impl CrateMetadata { Some(d) => d } } + + fn local_def_id(&self, index: DefIndex) -> DefId { + DefId { + krate: self.cnum, + index: index + } + } } pub fn load_index(data: &[u8]) -> index::Index { @@ -342,12 +341,10 @@ pub fn load_xrefs(data: &[u8]) -> index::DenseIndex { // Go through each item in the metadata and create a map from that // item's def-key to the item's DefIndex. pub fn load_key_map(data: &[u8]) -> FnvHashMap { - rbml::Doc::new(data).get(root_tag::items).children().map(|item_doc| { + load_index(data).iter_enumerated(data).map(|(index, pos)| { // load def-key from item - let key = item_def_key(item_doc); - - // load def-index from item - (key, item_doc.get(item_tag::def_index).decoder().decode()) + let key = item_def_key(rbml::Doc::at(data, pos as usize)); + (key, index) }).collect() } @@ -356,38 +353,27 @@ fn item_family(item: rbml::Doc) -> Family { } fn item_visibility(item: rbml::Doc) -> ty::Visibility { - match reader::maybe_get_doc(item, item_tag::visibility) { - None => ty::Visibility::Public, - Some(visibility_doc) => visibility_doc.decoder().decode() - } + item.get(item_tag::visibility).decoder().decode() } -fn item_defaultness(item: rbml::Doc) -> hir::Defaultness { - match reader::maybe_get_doc(item, item_tag::defaultness) { - None => hir::Defaultness::Default, // should occur only for default impls on traits - Some(defaultness_doc) => defaultness_doc.decoder().decode() - } -} - -fn item_parent_item(cdata: Cmd, d: rbml::Doc) -> Option { - reader::maybe_get_doc(d, item_tag::parent_item).map(|did| { - let mut dcx = did.decoder(); - dcx.cdata = Some(cdata); - dcx.decode() - }) -} - -fn item_require_parent_item(cdata: Cmd, d: rbml::Doc) -> DefId { - let mut dcx = d.get(item_tag::parent_item).decoder(); +fn entry_data(doc: rbml::Doc, cdata: Cmd) -> EntryData { + let mut dcx = doc.get(item_tag::data).decoder(); dcx.cdata = Some(cdata); + dcx.decode() } -fn item_def_id(d: rbml::Doc, cdata: Cmd) -> DefId { - DefId { - krate: cdata.cnum, - index: d.get(item_tag::def_index).decoder().decode() - } +fn entry_typed_data<'a, 'tcx>(doc: rbml::Doc, tcx: TyCtxt<'a, 'tcx, 'tcx>, cdata: Cmd) + -> EntryTypedData<'tcx> { + let mut dcx = doc.get(item_tag::typed_data).decoder(); + dcx.cdata = Some(cdata); + dcx.tcx = Some(tcx); + + dcx.decode() +} + +fn item_parent_item(cdata: Cmd, d: rbml::Doc) -> Option { + item_def_key(d).parent.map(|index| cdata.local_def_id(index)) } fn doc_type<'a, 'tcx>(doc: rbml::Doc, tcx: TyCtxt<'a, 'tcx, 'tcx>, cdata: Cmd) -> Ty<'tcx> { @@ -404,53 +390,63 @@ fn maybe_doc_type<'a, 'tcx>(doc: rbml::Doc, tcx: TyCtxt<'a, 'tcx, 'tcx>, cdata: }) } -fn doc_trait_ref<'a, 'tcx>(doc: rbml::Doc, tcx: TyCtxt<'a, 'tcx, 'tcx>, cdata: Cmd) - -> ty::TraitRef<'tcx> { - let mut dcx = doc.decoder(); - dcx.tcx = Some(tcx); - dcx.cdata = Some(cdata); - dcx.decode() -} - fn item_name(item: rbml::Doc) -> ast::Name { maybe_item_name(item).expect("no item in item_name") } fn maybe_item_name(item: rbml::Doc) -> Option { - reader::maybe_get_doc(item, item_tag::name).map(|name| { - name.decoder().decode() - }) + let name = match item_def_key(item).disambiguated_data.data { + DefPathData::TypeNs(name) | + DefPathData::ValueNs(name) | + DefPathData::Module(name) | + DefPathData::MacroDef(name) | + DefPathData::TypeParam(name) | + DefPathData::LifetimeDef(name) | + DefPathData::EnumVariant(name) | + DefPathData::Field(name) | + DefPathData::Binding(name) => Some(name), + + DefPathData::InlinedRoot(_) => bug!("unexpected DefPathData"), + + DefPathData::CrateRoot | + DefPathData::Misc | + DefPathData::Impl | + DefPathData::ClosureExpr | + DefPathData::StructCtor | + DefPathData::Initializer | + DefPathData::ImplTrait => None + }; + + name.map(|s| token::intern(&s)) } -fn item_to_def(cdata: Cmd, item: rbml::Doc, did: DefId) -> Option { - Some(match item_family(item) { - Family::Const => Def::Const(did), - Family::AssociatedConst => Def::AssociatedConst(did), - Family::ImmStatic => Def::Static(did, false), - Family::MutStatic => Def::Static(did, true), - Family::Struct(..) => Def::Struct(did), - Family::Union => Def::Union(did), - Family::Fn => Def::Fn(did), - Family::Method => Def::Method(did), - Family::Type => Def::TyAlias(did), - Family::AssociatedType => { - Def::AssociatedTy(item_require_parent_item(cdata, item), did) - } - Family::Mod => Def::Mod(did), - Family::ForeignMod => Def::ForeignMod(did), - Family::Variant(..) => { - Def::Variant(item_require_parent_item(cdata, item), did) - } - Family::Trait => Def::Trait(did), - Family::Enum => Def::Enum(did), +impl Family { + fn to_def(&self, did: DefId) -> Option { + Some(match *self { + Family::Const => Def::Const(did), + Family::AssociatedConst => Def::AssociatedConst(did), + Family::ImmStatic | Family::ForeignImmStatic => Def::Static(did, false), + Family::MutStatic | Family::ForeignMutStatic => Def::Static(did, true), + Family::Struct => Def::Struct(did), + Family::Union => Def::Union(did), + Family::Fn | Family::ForeignFn => Def::Fn(did), + Family::Method => Def::Method(did), + Family::Type => Def::TyAlias(did), + Family::AssociatedType => Def::AssociatedTy(did), + Family::Mod => Def::Mod(did), + Family::Variant => Def::Variant(did), + Family::Trait => Def::Trait(did), + Family::Enum => Def::Enum(did), - Family::Impl | - Family::DefaultImpl | - Family::PublicField | - Family::InheritedField => { - return None - } - }) + Family::ForeignMod | + Family::Impl | + Family::DefaultImpl | + Family::Field | + Family::Closure => { + return None + } + }) + } } pub fn get_trait_def<'a, 'tcx>(cdata: Cmd, @@ -459,13 +455,46 @@ pub fn get_trait_def<'a, 'tcx>(cdata: Cmd, { let item_doc = cdata.lookup_item(item_id); let generics = doc_generics(item_doc, tcx, cdata); - let unsafety = item_doc.get(item_tag::unsafety).decoder().decode(); - let paren_sugar = item_doc.get(item_tag::paren_sugar).decoder().decode(); - let trait_ref = doc_trait_ref(item_doc.get(item_tag::trait_ref), tcx, cdata); - let def_path = def_path(cdata, item_id).unwrap(); - ty::TraitDef::new(unsafety, paren_sugar, generics, trait_ref, - def_path.deterministic_hash(tcx)) + let data = match entry_data(item_doc, cdata) { + EntryData::Trait(data) => data, + _ => bug!() + }; + let typed_data = match entry_typed_data(item_doc, tcx, cdata) { + EntryTypedData::Trait(data) => data, + _ => bug!() + }; + + ty::TraitDef::new(data.unsafety, data.paren_sugar, generics, typed_data.trait_ref, + def_path(cdata, item_id).unwrap().deterministic_hash(tcx))) +} + +fn get_variant<'tcx>(cdata: Cmd, + item: rbml::Doc, + index: DefIndex) + -> (ty::VariantDefData<'tcx, 'tcx>, Option) { + let data = match entry_data(item, cdata) { + EntryData::Variant(data) => data, + _ => bug!() + }; + + let mut dcx = item.get(item_tag::children).decoder(); + dcx.cdata = Some(cdata); + + let fields = dcx.seq().map(|index| { + let f = cdata.lookup_item(index); + ty::FieldDefData::new(cdata.local_def_id(index), + item_name(f), + item_visibility(f)) + }).collect(); + + (ty::VariantDefData { + did: cdata.local_def_id(data.struct_ctor.unwrap_or(index)), + name: item_name(item), + fields: fields, + disr_val: ConstInt::Infer(data.disr), + kind: data.kind, + }, data.struct_ctor) } pub fn get_adt_def<'a, 'tcx>(cdata: Cmd, @@ -473,116 +502,47 @@ pub fn get_adt_def<'a, 'tcx>(cdata: Cmd, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> ty::AdtDefMaster<'tcx> { - fn expect_variant_kind(family: Family) -> ty::VariantKind { - match family { - Struct(kind) | Variant(kind) => kind, - Union => ty::VariantKind::Struct, - _ => bug!("unexpected family: {:?}", family), - } - } - fn get_enum_variants<'tcx>(cdata: Cmd, doc: rbml::Doc) -> Vec> { + let doc = cdata.lookup_item(item_id); + let did = cdata.local_def_id(item_id); + let mut ctor_index = None; + let family = item_family(doc); + let variants = if family == Family::Enum { let mut dcx = doc.get(item_tag::children).decoder(); dcx.cdata = Some(cdata); - dcx.seq().map(|did: DefId| { - let item = cdata.lookup_item(did.index); - let disr = item.get(item_tag::disr_val).decoder().decode(); - ty::VariantDefData { - did: did, - name: item_name(item), - fields: get_variant_fields(cdata, item), - disr_val: ConstInt::Infer(disr), - kind: expect_variant_kind(item_family(item)), - } + dcx.seq().map(|index| { + let (variant, struct_ctor) = get_variant(cdata, cdata.lookup_item(index), index); + assert_eq!(struct_ctor, None); + variant }).collect() - } - fn get_variant_fields<'tcx>(cdata: Cmd, doc: rbml::Doc) -> Vec> { - let mut dcx = doc.get(item_tag::fields).decoder(); - dcx.cdata = Some(cdata); - - dcx.seq().map(|did: DefId| { - let f = cdata.lookup_item(did.index); - let vis = match item_family(f) { - PublicField => ty::Visibility::Public, - InheritedField => ty::Visibility::PrivateExternal, - _ => bug!() - }; - ty::FieldDefData::new(did, item_name(f), vis) - }).collect() - } - fn get_struct_variant<'tcx>(cdata: Cmd, - doc: rbml::Doc, - did: DefId) -> ty::VariantDefData<'tcx, 'tcx> { - ty::VariantDefData { - did: did, - name: item_name(doc), - fields: get_variant_fields(cdata, doc), - disr_val: ConstInt::Infer(0), - kind: expect_variant_kind(item_family(doc)), - } - } - - let doc = cdata.lookup_item(item_id); - let did = DefId { krate: cdata.cnum, index: item_id }; - let mut ctor_did = None; - let (kind, variants) = match item_family(doc) { - Enum => { - (AdtKind::Enum, get_enum_variants(cdata, doc)) - } - Struct(..) => { - // Use separate constructor id for unit/tuple structs and reuse did for braced structs. - ctor_did = reader::maybe_get_doc(doc, item_tag::struct_ctor).map(|ctor_doc| { - let mut dcx = ctor_doc.decoder(); - dcx.cdata = Some(cdata); - dcx.decode() - }); - (AdtKind::Struct, vec![get_struct_variant(cdata, doc, ctor_did.unwrap_or(did))]) - } - Union => { - (AdtKind::Union, vec![get_struct_variant(cdata, doc, did)]) - } - _ => bug!("get_adt_def called on a non-ADT {:?} - {:?}", item_family(doc), did) + } else{ + let (variant, struct_ctor) = get_variant(cdata, doc, item_id); + ctor_index = struct_ctor; + vec![variant] + }; + let kind = match family { + Family::Enum => ty::AdtKind::Enum, + Family::Struct => ty::AdtKind::Struct, + Family::Union => ty::AdtKind::Union, + _ => bug!("get_adt_def called on a non-ADT {:?} - {:?}", + family, did) }; let adt = tcx.intern_adt_def(did, kind, variants); - if let Some(ctor_did) = ctor_did { + if let Some(ctor_index) = ctor_index { // Make adt definition available through constructor id as well. - tcx.insert_adt_def(ctor_did, adt); + tcx.insert_adt_def(cdata.local_def_id(ctor_index), adt); } // this needs to be done *after* the variant is interned, // to support recursive structures for variant in &adt.variants { - if variant.kind == ty::VariantKind::Tuple && adt.is_enum() { - // tuple-like enum variant fields aren't real items - get the types - // from the ctor. - debug!("evaluating the ctor-type of {:?}", - variant.name); - let ctor_ty = get_type(cdata, variant.did.index, tcx); - debug!("evaluating the ctor-type of {:?}.. {:?}", - variant.name, - ctor_ty); - let field_tys = match ctor_ty.sty { - ty::TyFnDef(.., &ty::BareFnTy { sig: ty::Binder(ty::FnSig { - ref inputs, .. - }), ..}) => { - // tuple-struct constructors don't have escaping regions - assert!(!inputs.has_escaping_regions()); - inputs - }, - _ => bug!("tuple-variant ctor is not an ADT") - }; - for (field, &ty) in variant.fields.iter().zip(field_tys.iter()) { - field.fulfill_ty(ty); - } - } else { - for field in &variant.fields { - debug!("evaluating the type of {:?}::{:?}", variant.name, field.name); - let ty = get_type(cdata, field.did.index, tcx); - field.fulfill_ty(ty); - debug!("evaluating the type of {:?}::{:?}: {:?}", - variant.name, field.name, ty); - } + for field in &variant.fields { + debug!("evaluating the type of {:?}::{:?}", variant.name, field.name); + let ty = get_type(cdata, field.did.index, tcx); + field.fulfill_ty(ty); + debug!("evaluating the type of {:?}::{:?}: {:?}", + variant.name, field.name, ty); } } @@ -641,24 +601,19 @@ pub fn get_visibility(cdata: Cmd, id: DefIndex) -> ty::Visibility { item_visibility(cdata.lookup_item(id)) } -pub fn get_parent_impl(cdata: Cmd, id: DefIndex) -> Option { - let item = cdata.lookup_item(id); - reader::maybe_get_doc(item, item_tag::parent_impl).map(|doc| { - let mut dcx = doc.decoder(); - dcx.cdata = Some(cdata); - dcx.decode() - }) +fn get_impl_data(cdata: Cmd, id: DefIndex) -> ImplData { + match entry_data(cdata.lookup_item(id), cdata) { + EntryData::Impl(data) => data, + _ => bug!() + } } -pub fn get_repr_attrs(cdata: Cmd, id: DefIndex) -> Vec { - let item = cdata.lookup_item(id); - reader::maybe_get_doc(item, item_tag::repr).map_or(vec![], |doc| { - doc.decoder().decode() - }) +pub fn get_parent_impl(cdata: Cmd, id: DefIndex) -> Option { + get_impl_data(cdata, id).parent_impl } pub fn get_impl_polarity(cdata: Cmd, id: DefIndex) -> hir::ImplPolarity { - cdata.lookup_item(id).get(item_tag::polarity).decoder().decode() + get_impl_data(cdata, id).polarity } pub fn get_custom_coerce_unsized_kind( @@ -666,10 +621,7 @@ pub fn get_custom_coerce_unsized_kind( id: DefIndex) -> Option { - let item_doc = cdata.lookup_item(id); - reader::maybe_get_doc(item_doc, item_tag::impl_coerce_unsized_kind).map(|kind_doc| { - kind_doc.decoder().decode() - }) + get_impl_data(cdata, id).coerce_unsized_kind } pub fn get_impl_trait<'a, 'tcx>(cdata: Cmd, @@ -677,10 +629,10 @@ pub fn get_impl_trait<'a, 'tcx>(cdata: Cmd, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Option> { - let item_doc = cdata.lookup_item(id); - reader::maybe_get_doc(item_doc, item_tag::trait_ref).map(|tp| { - doc_trait_ref(tp, tcx, cdata) - }) + match entry_typed_data(cdata.lookup_item(id), tcx, cdata) { + EntryTypedData::Impl(data) => data.trait_ref, + _ => bug!() + } } /// Iterates over the language items in the given crate. @@ -691,8 +643,8 @@ pub fn get_lang_items(cdata: Cmd) -> Vec<(DefIndex, usize)> { /// Iterates over each child of the given item. pub fn each_child_of_item(cdata: Cmd, id: DefIndex, - mut get_crate_data: G, - mut callback: F) + mut get_crate_data: &mut G, + mut callback: &mut F) where F: FnMut(Def, ast::Name, ty::Visibility), G: FnMut(CrateNum) -> Rc, { @@ -709,31 +661,24 @@ pub fn each_child_of_item(cdata: Cmd, id: DefIndex, dcx.cdata = Some(cdata); // Iterate over all children. - for child_def_id in dcx.seq_mut::() { - // This item may be in yet another crate if it was the child of a - // reexport. - let crate_data = if child_def_id.krate == cdata.cnum { - None - } else { - Some(get_crate_data(child_def_id.krate)) - }; - let crate_data = match crate_data { - Some(ref cdata) => &**cdata, - None => cdata - }; - + for child_index in dcx.seq::() { // Get the item. - if let Some(child_item_doc) = crate_data.get_item(child_def_id.index) { + if let Some(child) = cdata.get_item(child_index) { // Hand off the item to the callback. - if let Some(def) = item_to_def(crate_data, child_item_doc, child_def_id) { - let child_name = item_name(child_item_doc); - let visibility = item_visibility(child_item_doc); - callback(def, child_name, visibility); + let family = item_family(child); + if let Family::ForeignMod = family { + each_child_of_item(cdata, child_index, get_crate_data, callback); + } else if let Some(def) = family.to_def(cdata.local_def_id(child_index)) { + callback(def, item_name(child), item_visibility(child)); } } } - for exp in dcx.seq_mut::() { + let reexports = match entry_data(item_doc, cdata) { + EntryData::Mod(data) => data.reexports, + _ => return + }; + for exp in reexports { // This reexport may be in yet another crate. let crate_data = if exp.def_id.krate == cdata.cnum { None @@ -746,9 +691,9 @@ pub fn each_child_of_item(cdata: Cmd, id: DefIndex, }; // Get the item. - if let Some(child_item_doc) = crate_data.get_item(exp.def_id.index) { + if let Some(child) = crate_data.get_item(exp.def_id.index) { // Hand off the item to the callback. - if let Some(def) = item_to_def(crate_data, child_item_doc, exp.def_id) { + if let Some(def) = item_family(child).to_def(exp.def_id) { // These items have a public visibility because they're part of // a public re-export. callback(def, exp.name, ty::Visibility::Public); @@ -757,62 +702,21 @@ pub fn each_child_of_item(cdata: Cmd, id: DefIndex, } } -pub fn get_item_name(cdata: Cmd, id: DefIndex) -> ast::Name { - item_name(cdata.lookup_item(id)) -} - pub fn maybe_get_item_name(cdata: Cmd, id: DefIndex) -> Option { maybe_item_name(cdata.lookup_item(id)) } -pub enum FoundAst<'ast> { - Found(&'ast InlinedItem), - FoundParent(DefId, &'ast hir::Item), - NotFound, -} - pub fn maybe_get_item_ast<'a, 'tcx>(cdata: Cmd, tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefIndex) - -> FoundAst<'tcx> { + -> Option<&'tcx InlinedItem> { debug!("Looking up item: {:?}", id); let item_doc = cdata.lookup_item(id); - let item_did = item_def_id(item_doc, cdata); - let parent_def_id = DefId { - krate: cdata.cnum, - index: def_key(cdata, id).parent.unwrap() - }; + let item_did = cdata.local_def_id(id); + let parent_def_id = cdata.local_def_id(def_key(cdata, id).parent.unwrap()); let mut parent_def_path = def_path(cdata, id).unwrap(); parent_def_path.data.pop(); - if let Some(ast_doc) = reader::maybe_get_doc(item_doc, item_tag::ast as usize) { - let ii = decode_inlined_item(cdata, - tcx, - parent_def_path, - parent_def_id, - ast_doc, - item_did); - return FoundAst::Found(ii); - } else if let Some(parent_did) = item_parent_item(cdata, item_doc) { - // Remove the last element from the paths, since we are now - // trying to inline the parent. - let grandparent_def_id = DefId { - krate: cdata.cnum, - index: def_key(cdata, parent_def_id.index).parent.unwrap() - }; - let mut grandparent_def_path = parent_def_path; - grandparent_def_path.data.pop(); - let parent_doc = cdata.lookup_item(parent_did.index); - if let Some(ast_doc) = reader::maybe_get_doc(parent_doc, item_tag::ast as usize) { - let ii = decode_inlined_item(cdata, - tcx, - grandparent_def_path, - grandparent_def_id, - ast_doc, - parent_did); - if let &InlinedItem::Item(_, ref i) = ii { - return FoundAst::FoundParent(parent_did, i); - } - } - } - FoundAst::NotFound + reader::maybe_get_doc(item_doc, item_tag::ast).map(|ast_doc| { + decode_inlined_item(cdata, tcx, parent_def_path, parent_def_id, ast_doc, item_did) + }) } pub fn is_item_mir_available<'tcx>(cdata: Cmd, id: DefIndex) -> bool { @@ -837,41 +741,41 @@ pub fn maybe_get_item_mir<'a, 'tcx>(cdata: Cmd, }) } -fn get_explicit_self<'a, 'tcx>(cdata: Cmd, item: rbml::Doc, tcx: TyCtxt<'a, 'tcx, 'tcx>) - -> ty::ExplicitSelfCategory<'tcx> { - let mut dcx = item.get(item_tag::trait_method_explicit_self).decoder(); - dcx.cdata = Some(cdata); - dcx.tcx = Some(tcx); - - dcx.decode() -} - -pub fn get_trait_name(cdata: Cmd, id: DefIndex) -> ast::Name { - let doc = cdata.lookup_item(id); - item_name(doc) -} - pub fn get_impl_or_trait_item<'a, 'tcx>(cdata: Cmd, id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Option> { let item_doc = cdata.lookup_item(id); + let family = item_family(item_doc); - let def_id = item_def_id(item_doc, cdata); + match family { + Family::AssociatedConst | + Family::Method | + Family::AssociatedType => {} - let container_id = if let Some(id) = item_parent_item(cdata, item_doc) { - id - } else { - return None; - }; + _ => return None + } + + let def_id = cdata.local_def_id(id); + + let container_id = item_parent_item(cdata, item_doc).unwrap(); let container = match item_family(cdata.lookup_item(container_id.index)) { - Trait => TraitContainer(container_id), + Family::Trait => TraitContainer(container_id), _ => ImplContainer(container_id), }; let name = item_name(item_doc); let vis = item_visibility(item_doc); - let defaultness = item_defaultness(item_doc); - Some(match item_family(item_doc) { + let (defaultness, has_body) = match entry_data(item_doc, cdata) { + EntryData::TraitAssociated(data) => { + (hir::Defaultness::Default, data.has_default) + } + EntryData::ImplAssociated(data) => { + (data.defaultness, true) + } + _ => bug!() + }; + + Some(match family { Family::AssociatedConst => { let ty = doc_type(item_doc, tcx, cdata); ty::ConstTraitItem(Rc::new(ty::AssociatedConst { @@ -881,7 +785,7 @@ pub fn get_impl_or_trait_item<'a, 'tcx>(cdata: Cmd, id: DefIndex, tcx: TyCtxt<'a defaultness: defaultness, def_id: def_id, container: container, - has_value: item_doc.get(item_tag::trait_item_has_body).decoder().decode(), + has_value: has_body, })) } Family::Method => { @@ -894,8 +798,11 @@ pub fn get_impl_or_trait_item<'a, 'tcx>(cdata: Cmd, id: DefIndex, tcx: TyCtxt<'a "the type {:?} of the method {:?} is not a function?", ity, name) }; - let explicit_self = get_explicit_self(cdata, item_doc, tcx); + let explicit_self = match entry_typed_data(item_doc, tcx, cdata) { + EntryTypedData::Method(data) => data.explicit_self, + _ => bug!() + }; ty::MethodTraitItem(Rc::new(ty::Method { name: name, generics: generics, @@ -904,7 +811,7 @@ pub fn get_impl_or_trait_item<'a, 'tcx>(cdata: Cmd, id: DefIndex, tcx: TyCtxt<'a explicit_self: explicit_self, vis: vis, defaultness: defaultness, - has_body: item_doc.get(item_tag::trait_item_has_body).decoder().decode(), + has_body: has_body, def_id: def_id, container: container, })) @@ -920,7 +827,7 @@ pub fn get_impl_or_trait_item<'a, 'tcx>(cdata: Cmd, id: DefIndex, tcx: TyCtxt<'a container: container, })) } - _ => return None + _ => bug!() }) } @@ -931,49 +838,33 @@ pub fn get_item_variances(cdata: Cmd, id: DefIndex) -> Vec { pub fn get_struct_ctor_def_id(cdata: Cmd, node_id: DefIndex) -> Option { - let item = cdata.lookup_item(node_id); - reader::maybe_get_doc(item, item_tag::struct_ctor).map(|ctor_doc| { - let mut dcx = ctor_doc.decoder(); - dcx.cdata = Some(cdata); - dcx.decode() - }) -} + let data = match entry_data(cdata.lookup_item(node_id), cdata) { + EntryData::Variant(data) => data, + _ => bug!() + }; -/// If node_id is the constructor of a tuple struct, retrieve the NodeId of -/// the actual type definition, otherwise, return None -pub fn get_tuple_struct_definition_if_ctor(cdata: Cmd, - node_id: DefIndex) - -> Option -{ - let item = cdata.lookup_item(node_id); - reader::maybe_get_doc(item, item_tag::is_tuple_struct_ctor).and_then(|doc| { - if doc.decoder().decode() { - Some(item_require_parent_item(cdata, item)) - } else { - None - } - }) + data.struct_ctor.map(|index| cdata.local_def_id(index)) } pub fn get_item_attrs(cdata: Cmd, - orig_node_id: DefIndex) + node_id: DefIndex) -> Vec { // The attributes for a tuple struct are attached to the definition, not the ctor; // we assume that someone passing in a tuple struct ctor is actually wanting to // look at the definition - let node_id = get_tuple_struct_definition_if_ctor(cdata, orig_node_id); - let node_id = node_id.map(|x| x.index).unwrap_or(orig_node_id); - let item = cdata.lookup_item(node_id); + let mut item = cdata.lookup_item(node_id); + let def_key = item_def_key(item); + if def_key.disambiguated_data.data == DefPathData::StructCtor { + item = cdata.lookup_item(def_key.parent.unwrap()); + } get_attributes(item) } pub fn get_struct_field_names(cdata: Cmd, id: DefIndex) -> Vec { - let mut dcx = cdata.lookup_item(id).get(item_tag::fields).decoder(); + let mut dcx = cdata.lookup_item(id).get(item_tag::children).decoder(); dcx.cdata = Some(cdata); - dcx.seq().map(|did: DefId| { - item_name(cdata.lookup_item(did.index)) - }).collect() + dcx.seq().map(|index| item_name(cdata.lookup_item(index))).collect() } fn get_attributes(md: rbml::Doc) -> Vec { @@ -1019,36 +910,8 @@ fn list_crate_deps(data: &[u8], out: &mut io::Write) -> io::Result<()> { Ok(()) } -pub fn maybe_get_crate_hash(data: &[u8]) -> Option { - let cratedoc = rbml::Doc::new(data); - reader::maybe_get_doc(cratedoc, root_tag::crate_hash).map(|doc| { - doc.decoder().decode() - }) -} - -pub fn get_crate_hash(data: &[u8]) -> Svh { - rbml::Doc::new(data).get(root_tag::crate_hash).decoder().decode() -} - -pub fn maybe_get_crate_name(data: &[u8]) -> Option { - let cratedoc = rbml::Doc::new(data); - reader::maybe_get_doc(cratedoc, root_tag::crate_crate_name).map(|doc| { - doc.decoder().decode() - }) -} - -pub fn get_crate_disambiguator(data: &[u8]) -> String { - rbml::Doc::new(data).get(root_tag::crate_disambiguator).decoder().decode() -} - -pub fn get_crate_triple(data: &[u8]) -> Option { - let cratedoc = rbml::Doc::new(data); - let triple_doc = reader::maybe_get_doc(cratedoc, root_tag::crate_triple); - triple_doc.map(|s| s.decoder().decode()) -} - -pub fn get_crate_name(data: &[u8]) -> String { - maybe_get_crate_name(data).expect("no crate name in crate") +pub fn get_crate_info(data: &[u8]) -> CrateInfo { + rbml::Doc::new(data).get(root_tag::crate_info).decoder().decode() } pub fn list_crate_metadata(bytes: &[u8], out: &mut io::Write) -> io::Result<()> { @@ -1118,9 +981,8 @@ pub fn get_trait_of_item(cdata: Cmd, id: DefIndex) -> Option { None => return None, Some(item_id) => item_id, }; - let parent_item_doc = cdata.lookup_item(parent_item_id.index); - match item_family(parent_item_doc) { - Trait => Some(item_def_id(parent_item_doc, cdata)), + match item_family(cdata.lookup_item(parent_item_id.index)) { + Family::Trait => Some(parent_item_id), _ => None } } @@ -1131,11 +993,6 @@ pub fn get_native_libraries(cdata: Cmd) rbml::Doc::new(cdata.data()).get(root_tag::native_libraries).decoder().decode() } -pub fn get_plugin_registrar_fn(data: &[u8]) -> Option { - reader::maybe_get_doc(rbml::Doc::new(data), root_tag::plugin_registrar_fn) - .map(|doc| doc.decoder().decode()) -} - pub fn each_exported_macro(data: &[u8], mut f: F) where F: FnMut(ast::Name, Vec, Span, String) -> bool, { @@ -1147,11 +1004,6 @@ pub fn each_exported_macro(data: &[u8], mut f: F) where } } -pub fn get_derive_registrar_fn(data: &[u8]) -> Option { - reader::maybe_get_doc(rbml::Doc::new(data), root_tag::macro_derive_registrar) - .map(|doc| doc.decoder().decode()) -} - pub fn get_dylib_dependency_formats(cdata: Cmd) -> Vec<(CrateNum, LinkagePreference)> { @@ -1167,9 +1019,9 @@ pub fn get_missing_lang_items(cdata: Cmd) -> Vec { rbml::Doc::new(cdata.data()).get(root_tag::lang_items_missing).decoder().decode() } -pub fn get_method_arg_names(cdata: Cmd, id: DefIndex) -> Vec { +pub fn get_fn_arg_names(cdata: Cmd, id: DefIndex) -> Vec { let method_doc = cdata.lookup_item(id); - match reader::maybe_get_doc(method_doc, item_tag::method_argument_names) { + match reader::maybe_get_doc(method_doc, item_tag::fn_arg_names) { Some(args_doc) => args_doc.decoder().decode(), None => vec![], } @@ -1178,24 +1030,16 @@ pub fn get_method_arg_names(cdata: Cmd, id: DefIndex) -> Vec { pub fn get_reachable_ids(cdata: Cmd) -> Vec { let dcx = rbml::Doc::new(cdata.data()).get(root_tag::reachable_ids).decoder(); - dcx.seq().map(|index| { - DefId { - krate: cdata.cnum, - index: index, - } - }).collect() + dcx.seq().map(|index| cdata.local_def_id(index)).collect() } pub fn is_const_fn(cdata: Cmd, id: DefIndex) -> bool { - match reader::maybe_get_doc(cdata.lookup_item(id), item_tag::constness) { - None => false, - Some(doc) => { - match doc.decoder().decode() { - hir::Constness::Const => true, - hir::Constness::NotConst => false, - } - } - } + let constness = match entry_data(cdata.lookup_item(id), cdata) { + EntryData::ImplAssociated(data) => data.constness, + EntryData::Fn(data) => data.constness, + _ => hir::Constness::NotConst + }; + constness == hir::Constness::Const } pub fn is_extern_item<'a, 'tcx>(cdata: Cmd, @@ -1207,8 +1051,15 @@ pub fn is_extern_item<'a, 'tcx>(cdata: Cmd, None => return false, }; let applicable = match item_family(item_doc) { - ImmStatic | MutStatic => true, - Fn => get_generics(cdata, id, tcx).types.is_empty(), + Family::ImmStatic | + Family::MutStatic | + Family::ForeignImmStatic | + Family::ForeignMutStatic => true, + + Family::Fn | Family::ForeignFn => { + get_generics(cdata, id, tcx).types.is_empty() + } + _ => false, }; @@ -1221,13 +1072,12 @@ pub fn is_extern_item<'a, 'tcx>(cdata: Cmd, } pub fn is_foreign_item(cdata: Cmd, id: DefIndex) -> bool { - let item_doc = cdata.lookup_item(id); - let parent_item_id = match item_parent_item(cdata, item_doc) { - None => return false, - Some(item_id) => item_id, - }; - let parent_item_doc = cdata.lookup_item(parent_item_id.index); - item_family(parent_item_doc) == ForeignMod + match item_family(cdata.lookup_item(id)) { + Family::ForeignImmStatic | + Family::ForeignMutStatic | + Family::ForeignFn => true, + _ => false + } } fn doc_generics<'a, 'tcx>(base_doc: rbml::Doc, @@ -1268,7 +1118,10 @@ fn doc_predicates<'a, 'tcx>(base_doc: rbml::Doc, } pub fn is_defaulted_trait(cdata: Cmd, trait_id: DefIndex) -> bool { - cdata.lookup_item(trait_id).get(item_tag::defaulted_trait).decoder().decode() + match entry_data(cdata.lookup_item(trait_id), cdata) { + EntryData::Trait(data) => data.has_default_impl, + _ => bug!() + } } pub fn is_default_impl(cdata: Cmd, impl_id: DefIndex) -> bool { @@ -1280,29 +1133,27 @@ pub fn get_imported_filemaps(metadata: &[u8]) -> Vec { } pub fn closure_kind(cdata: Cmd, closure_id: DefIndex) -> ty::ClosureKind { - cdata.lookup_item(closure_id).get(item_tag::closure_kind).decoder().decode() + match entry_data(cdata.lookup_item(closure_id), cdata) { + EntryData::Closure(data) => data.kind, + _ => bug!() + } } pub fn closure_ty<'a, 'tcx>(cdata: Cmd, closure_id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> ty::ClosureTy<'tcx> { - let closure_doc = cdata.lookup_item(closure_id); - let closure_ty_doc = closure_doc.get(item_tag::closure_ty); - let mut dcx = closure_ty_doc.decoder(); - dcx.tcx = Some(tcx); - dcx.cdata = Some(cdata); - dcx.decode() + match entry_typed_data(cdata.lookup_item(closure_id), tcx, cdata) { + EntryTypedData::Closure(data) => data.ty, + _ => bug!() + } } pub fn def_key(cdata: Cmd, id: DefIndex) -> hir_map::DefKey { debug!("def_key: id={:?}", id); - let item_doc = cdata.lookup_item(id); - item_def_key(item_doc) + item_def_key(cdata.lookup_item(id)) } fn item_def_key(item_doc: rbml::Doc) -> hir_map::DefKey { - let simple_key = item_doc.get(item_tag::def_key).decoder().decode(); - let name = maybe_item_name(item_doc).map(|name| name.as_str()); - def_key::recover_def_key(simple_key, name) + item_doc.get(item_tag::def_key).decoder().decode() } // Returns the path leading to the thing with this `id`. Note that @@ -1316,7 +1167,3 @@ pub fn def_path(cdata: Cmd, id: DefIndex) -> Option { None } } - -pub fn get_panic_strategy(data: &[u8]) -> PanicStrategy { - rbml::Doc::new(data).get(root_tag::panic_strategy).decoder().decode() -} diff --git a/src/librustc_metadata/def_key.rs b/src/librustc_metadata/def_key.rs deleted file mode 100644 index 285ca2e4d4d4..000000000000 --- a/src/librustc_metadata/def_key.rs +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use rustc::hir::def_id::DefIndex; -use rustc::hir::map as hir_map; -use syntax::parse::token::InternedString; - -#[derive(RustcEncodable, RustcDecodable)] -pub struct DefKey { - pub parent: Option, - pub disambiguated_data: DisambiguatedDefPathData, -} - -#[derive(RustcEncodable, RustcDecodable)] -pub struct DisambiguatedDefPathData { - pub data: DefPathData, - pub disambiguator: u32, -} - -#[derive(RustcEncodable, RustcDecodable)] -pub enum DefPathData { - CrateRoot, - Misc, - Impl, - TypeNs, - ValueNs, - Module, - MacroDef, - ClosureExpr, - TypeParam, - LifetimeDef, - EnumVariant, - Field, - StructCtor, - Initializer, - Binding, - ImplTrait, -} - -pub fn simplify_def_key(key: hir_map::DefKey) -> DefKey { - let data = DisambiguatedDefPathData { - data: simplify_def_path_data(key.disambiguated_data.data), - disambiguator: key.disambiguated_data.disambiguator, - }; - DefKey { - parent: key.parent, - disambiguated_data: data, - } -} - -fn simplify_def_path_data(data: hir_map::DefPathData) -> DefPathData { - match data { - hir_map::DefPathData::CrateRoot => DefPathData::CrateRoot, - hir_map::DefPathData::InlinedRoot(_) => bug!("unexpected DefPathData"), - hir_map::DefPathData::Misc => DefPathData::Misc, - hir_map::DefPathData::Impl => DefPathData::Impl, - hir_map::DefPathData::TypeNs(_) => DefPathData::TypeNs, - hir_map::DefPathData::ValueNs(_) => DefPathData::ValueNs, - hir_map::DefPathData::Module(_) => DefPathData::Module, - hir_map::DefPathData::MacroDef(_) => DefPathData::MacroDef, - hir_map::DefPathData::ClosureExpr => DefPathData::ClosureExpr, - hir_map::DefPathData::TypeParam(_) => DefPathData::TypeParam, - hir_map::DefPathData::LifetimeDef(_) => DefPathData::LifetimeDef, - hir_map::DefPathData::EnumVariant(_) => DefPathData::EnumVariant, - hir_map::DefPathData::Field(_) => DefPathData::Field, - hir_map::DefPathData::StructCtor => DefPathData::StructCtor, - hir_map::DefPathData::Initializer => DefPathData::Initializer, - hir_map::DefPathData::Binding(_) => DefPathData::Binding, - hir_map::DefPathData::ImplTrait => DefPathData::ImplTrait, - } -} - -pub fn recover_def_key(key: DefKey, name: Option) -> hir_map::DefKey { - let data = hir_map::DisambiguatedDefPathData { - data: recover_def_path_data(key.disambiguated_data.data, name), - disambiguator: key.disambiguated_data.disambiguator, - }; - hir_map::DefKey { - parent: key.parent, - disambiguated_data: data, - } -} - -fn recover_def_path_data(data: DefPathData, name: Option) -> hir_map::DefPathData { - match data { - DefPathData::CrateRoot => hir_map::DefPathData::CrateRoot, - DefPathData::Misc => hir_map::DefPathData::Misc, - DefPathData::Impl => hir_map::DefPathData::Impl, - DefPathData::TypeNs => hir_map::DefPathData::TypeNs(name.unwrap()), - DefPathData::ValueNs => hir_map::DefPathData::ValueNs(name.unwrap()), - DefPathData::Module => hir_map::DefPathData::Module(name.unwrap()), - DefPathData::MacroDef => hir_map::DefPathData::MacroDef(name.unwrap()), - DefPathData::ClosureExpr => hir_map::DefPathData::ClosureExpr, - DefPathData::TypeParam => hir_map::DefPathData::TypeParam(name.unwrap()), - DefPathData::LifetimeDef => hir_map::DefPathData::LifetimeDef(name.unwrap()), - DefPathData::EnumVariant => hir_map::DefPathData::EnumVariant(name.unwrap()), - DefPathData::Field => hir_map::DefPathData::Field(name.unwrap()), - DefPathData::StructCtor => hir_map::DefPathData::StructCtor, - DefPathData::Initializer => hir_map::DefPathData::Initializer, - DefPathData::Binding => hir_map::DefPathData::Binding(name.unwrap()), - DefPathData::ImplTrait => hir_map::DefPathData::ImplTrait, - } -} diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 1e4c61e0b2e1..3ad9251b0721 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -16,15 +16,12 @@ use astencode::encode_inlined_item; use common::*; use cstore; -use decoder; -use def_key; use index::{self, IndexData}; -use middle::cstore::{InlinedItemRef, LinkMeta, LinkagePreference}; +use rustc::middle::cstore::{InlinedItemRef, LinkMeta, LinkagePreference}; use rustc::hir::def; -use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId}; -use middle::dependency_format::Linkage; -use rustc::dep_graph::DepNode; +use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefIndex, DefId}; +use rustc::middle::dependency_format::Linkage; use rustc::traits::specialization_graph; use rustc::ty::{self, Ty, TyCtxt}; @@ -41,7 +38,7 @@ use std::mem; use std::ops::{Deref, DerefMut}; use std::rc::Rc; use std::u32; -use syntax::ast::{self, NodeId, Name, CRATE_NODE_ID}; +use syntax::ast::{self, CRATE_NODE_ID}; use syntax::attr; use syntax; use rbml; @@ -49,7 +46,6 @@ use rbml; use rustc::hir::{self, PatKind}; use rustc::hir::intravisit::Visitor; use rustc::hir::intravisit; -use rustc::hir::map::DefKey; use super::index_builder::{FromId, IndexBuilder, Untracked}; @@ -166,59 +162,29 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { Ok(()) }).unwrap(); } -} -fn encode_name(ecx: &mut EncodeContext, name: Name) { - ecx.start_tag(item_tag::name); - name.encode(ecx).unwrap(); - ecx.end_tag(); -} + /// For every DefId that we create a metadata item for, we include a + /// serialized copy of its DefKey, which allows us to recreate a path. + fn encode_def_key(&mut self, def_id: DefId) { + self.start_tag(item_tag::def_key); + self.tcx.map.def_key(def_id).encode(self); + self.end_tag(); + } -fn encode_def_id(ecx: &mut EncodeContext, def_id: DefId) { - assert!(def_id.is_local()); - ecx.start_tag(item_tag::def_index); - def_id.index.encode(ecx).unwrap(); - ecx.end_tag(); -} + // Item info table encoding + fn encode_family(&mut self, f: Family) { + self.start_tag(item_tag::family); + f.encode(self).unwrap(); + self.end_tag(); + } -fn encode_def_key(ecx: &mut EncodeContext, key: DefKey) { - let simple_key = def_key::simplify_def_key(key); - ecx.start_tag(item_tag::def_key); - simple_key.encode(ecx); - ecx.end_tag(); -} + fn encode_item_variances(&mut self, def_id: DefId) { + let v = self.tcx.item_variances(def_id); + self.start_tag(item_tag::variances); + v.encode(self); + self.end_tag(); + } -/// For every DefId that we create a metadata item for, we include a -/// serialized copy of its DefKey, which allows us to recreate a path. -fn encode_def_id_and_key(ecx: &mut EncodeContext, def_id: DefId) { - encode_def_id(ecx, def_id); - let def_key = ecx.tcx.map.def_key(def_id); - encode_def_key(ecx, def_key); -} - -fn encode_trait_ref<'a, 'tcx>(ecx: &mut EncodeContext<'a, 'tcx>, - trait_ref: ty::TraitRef<'tcx>, - tag: usize) { - ecx.start_tag(tag); - trait_ref.encode(ecx).unwrap(); - ecx.end_tag(); -} - -// Item info table encoding -fn encode_family(ecx: &mut EncodeContext, f: Family) { - ecx.start_tag(item_tag::family); - f.encode(ecx).unwrap(); - ecx.end_tag(); -} - -fn encode_item_variances(ecx: &mut EncodeContext, id: NodeId) { - let v = ecx.tcx.item_variances(ecx.tcx.map.local_def_id(id)); - ecx.start_tag(item_tag::variances); - v.encode(ecx); - ecx.end_tag(); -} - -impl<'a, 'tcx> EncodeContext<'a, 'tcx> { fn encode_bounds_and_type_for_item(&mut self, def_id: DefId) { let tcx = self.tcx; self.encode_bounds_and_type(&tcx.lookup_item_type(def_id), @@ -238,37 +204,21 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.end_tag(); } - fn encode_disr_val(&mut self, - disr_val: ty::Disr) { - self.start_tag(item_tag::disr_val); - disr_val.to_u64_unchecked().encode(self).unwrap(); + fn encode_variant(&mut self, variant: ty::VariantDef, + struct_ctor: Option) + -> EntryData { + self.start_tag(item_tag::children); + self.seq(&variant.fields, |_, f| { + assert!(f.did.is_local()); + f.did.index + }); self.end_tag(); - } - fn encode_parent_item(&mut self, id: DefId) { - self.start_tag(item_tag::parent_item); - id.encode(self).unwrap(); - self.end_tag(); - } - - fn encode_variant_fields(&mut self, - variant: ty::VariantDef) { - self.start_tag(item_tag::fields); - self.seq(&variant.fields, |_, f| f.did); - self.end_tag(); - } -} - -impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { - fn encode_enum_variant_infos(&mut self, enum_did: DefId) { - debug!("encode_enum_variant_info(enum_did={:?})", enum_did); - let def = self.tcx.lookup_adt_def(enum_did); - self.encode_fields(enum_did); - for (i, variant) in def.variants.iter().enumerate() { - self.record(variant.did, - EncodeContext::encode_enum_variant_info, - (enum_did, Untracked(i))); - } + EntryData::Variant(VariantData { + kind: variant.kind, + disr: variant.disr_val.to_u64_unchecked(), + struct_ctor: struct_ctor + }) } } @@ -285,10 +235,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let def = tcx.lookup_adt_def(enum_did); let variant = &def.variants[index]; let vid = variant.did; - encode_def_id_and_key(self, vid); - encode_family(self, Family::Variant(variant.kind)); - encode_name(self, variant.name); - self.encode_parent_item(enum_did); + self.encode_def_key(vid); + self.encode_family(Family::Variant); let enum_id = tcx.map.as_local_node_id(enum_did).unwrap(); let enum_vis = &tcx.map.expect_item(enum_id).vis; @@ -296,60 +244,58 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let attrs = tcx.get_attrs(vid); encode_attributes(self, &attrs); - self.encode_repr_attrs(&attrs); + encode_stability(self, vid); - let stab = tcx.lookup_stability(vid); - let depr = tcx.lookup_deprecation(vid); - encode_stability(self, stab); - encode_deprecation(self, depr); + let data = self.encode_variant(variant, None); + + self.start_tag(item_tag::data); + data.encode(self).unwrap(); + self.end_tag(); + + self.start_tag(item_tag::typed_data); + EntryTypedData::Other.encode(self).unwrap(); + self.end_tag(); - self.encode_variant_fields(variant); - self.encode_disr_val(variant.disr_val); self.encode_bounds_and_type_for_item(vid); } } impl<'a, 'tcx> EncodeContext<'a, 'tcx> { fn encode_info_for_mod(&mut self, - FromId(id, (md, attrs, name, vis)): - FromId<(&hir::Mod, &[ast::Attribute], Name, &hir::Visibility)>) { + FromId(id, (md, attrs, vis)): + FromId<(&hir::Mod, &[ast::Attribute], &hir::Visibility)>) { let tcx = self.tcx; - encode_def_id_and_key(self, tcx.map.local_def_id(id)); - encode_family(self, Family::Mod); - encode_name(self, name); + let def_id = tcx.map.local_def_id(id); + self.encode_def_key(def_id); + self.encode_family(Family::Mod); + self.encode_visibility(vis); + encode_stability(self, def_id); + encode_attributes(self, attrs); debug!("(encoding info for module) encoding info for module ID {}", id); // Encode info about all the module children. self.start_tag(item_tag::children); self.seq(&md.item_ids, |_, item_id| { - tcx.map.local_def_id(item_id.id) + tcx.map.local_def_id(item_id.id).index }); - - // Encode the reexports of this module, if this module is public. - match self.reexports.get(&id) { - Some(exports) if *vis == hir::Public => exports.encode(self).unwrap(), - _ => <[def::Export]>::encode(&[], self).unwrap() - } self.end_tag(); - self.encode_visibility(vis); + // Encode the reexports of this module, if this module is public. + let reexports = match self.reexports.get(&id) { + Some(exports) if *vis == hir::Public => exports.clone(), + _ => vec![] + }; - let stab = tcx.lookup_stability(tcx.map.local_def_id(id)); - let depr = tcx.lookup_deprecation(tcx.map.local_def_id(id)); - encode_stability(self, stab); - encode_deprecation(self, depr); + self.start_tag(item_tag::data); + EntryData::Mod(ModData { + reexports: reexports + }).encode(self).unwrap(); + self.end_tag(); - encode_attributes(self, attrs); - } - - fn encode_struct_field_family(&mut self, - visibility: ty::Visibility) { - encode_family(self, if visibility.is_public() { - Family::PublicField - } else { - Family::InheritedField - }); + self.start_tag(item_tag::typed_data); + EntryTypedData::Other.encode(self).unwrap(); + self.end_tag(); } fn encode_visibility(&mut self, visibility: T) { @@ -380,18 +326,6 @@ impl HasVisibility for ty::Visibility { } } -fn encode_constness(ecx: &mut EncodeContext, constness: hir::Constness) { - ecx.start_tag(item_tag::constness); - constness.encode(ecx).unwrap(); - ecx.end_tag(); -} - -fn encode_defaultness(ecx: &mut EncodeContext, defaultness: hir::Defaultness) { - ecx.start_tag(item_tag::defaultness); - defaultness.encode(ecx).unwrap(); - ecx.end_tag(); -} - impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { fn encode_fields(&mut self, adt_def_id: DefId) { @@ -424,48 +358,23 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let nm = field.name; debug!("encode_field: encoding {} {:?}", nm, field.did); - self.encode_struct_field_family(field.vis); - encode_name(self, nm); + self.encode_family(Family::Field); + self.encode_visibility(field.vis); self.encode_bounds_and_type_for_item(field.did); - encode_def_id_and_key(self, field.did); + self.encode_def_key(field.did); let variant_id = tcx.map.as_local_node_id(variant.did).unwrap(); let variant_data = tcx.map.expect_variant_data(variant_id); encode_attributes(self, &variant_data.fields()[field_index].attrs); - - let stab = tcx.lookup_stability(field.did); - let depr = tcx.lookup_deprecation(field.did); - encode_stability(self, stab); - encode_deprecation(self, depr); + encode_stability(self, field.did); } - fn encode_struct_ctor(&mut self, - (struct_def_id, struct_node_id, ctor_node_id): - (DefId, ast::NodeId, ast::NodeId)) { - let tcx = self.tcx; - let def = tcx.lookup_adt_def(struct_def_id); - let variant = def.struct_variant(); - let item = tcx.map.expect_item(struct_node_id); - let ctor_def_id = tcx.map.local_def_id(ctor_node_id); - encode_def_id_and_key(self, ctor_def_id); - encode_family(self, Family::Struct(variant.kind)); + fn encode_struct_ctor(&mut self, ctor_def_id: DefId) { + self.encode_def_key(ctor_def_id); + self.encode_family(Family::Struct); self.encode_bounds_and_type_for_item(ctor_def_id); - encode_name(self, item.name); - self.encode_parent_item(struct_def_id); - let stab = tcx.lookup_stability(ctor_def_id); - let depr = tcx.lookup_deprecation(ctor_def_id); - encode_stability(self, stab); - encode_deprecation(self, depr); - - // indicate that this is a tuple struct ctor, because - // downstream users will normally want the tuple struct - // definition, but without this there is no way for them - // to tell that they actually have a ctor rather than a - // normal function - self.start_tag(item_tag::is_tuple_struct_ctor); - true.encode(self).unwrap(); - self.end_tag(); + encode_stability(self, ctor_def_id); } fn encode_generics(&mut self, @@ -489,215 +398,137 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.end_tag(); } - fn encode_method_ty_fields(&mut self, method_ty: &ty::Method<'tcx>) { - encode_def_id_and_key(self, method_ty.def_id); - encode_name(self, method_ty.name); - self.encode_generics(&method_ty.generics, &method_ty.predicates); - self.encode_visibility(method_ty.vis); - - self.start_tag(item_tag::trait_method_explicit_self); - method_ty.explicit_self.encode(self).unwrap(); - self.end_tag(); - - encode_family(self, Family::Method); - } - - fn encode_info_for_trait_item(&mut self, - (trait_def_id, item_def_id, trait_item): - (DefId, DefId, &hir::TraitItem)) { + fn encode_info_for_trait_item(&mut self, def_id: DefId) { let tcx = self.tcx; - self.encode_parent_item(trait_def_id); + let node_id = tcx.map.as_local_node_id(def_id).unwrap(); + let ast_item = tcx.map.expect_trait_item(node_id); + let trait_item = tcx.impl_or_trait_item(def_id); + let (family, has_default, typed_data) = match trait_item { + ty::ConstTraitItem(ref associated_const) => { + self.encode_bounds_and_type_for_item(def_id); - let stab = tcx.lookup_stability(item_def_id); - let depr = tcx.lookup_deprecation(item_def_id); - encode_stability(self, stab); - encode_deprecation(self, depr); + let trait_def_id = trait_item.container().id(); + encode_inlined_item(self, + InlinedItemRef::TraitItem(trait_def_id, ast_item)); - match tcx.impl_or_trait_item(item_def_id) { - ty::ConstTraitItem(associated_const) => { - encode_name(self, associated_const.name); - encode_def_id_and_key(self, item_def_id); - self.encode_visibility(associated_const.vis); - - encode_family(self, Family::AssociatedConst); - self.encode_bounds_and_type_for_item(item_def_id); + (Family::AssociatedConst, + associated_const.has_value, + EntryTypedData::Other) } - ty::MethodTraitItem(method_ty) => { - self.encode_method_ty_fields(&method_ty); - self.encode_bounds_and_type_for_item(item_def_id); - } - ty::TypeTraitItem(associated_type) => { - encode_name(self, associated_type.name); - encode_def_id_and_key(self, item_def_id); - encode_family(self, Family::AssociatedType); + ty::MethodTraitItem(ref method_ty) => { + self.encode_bounds_and_type_for_item(def_id); + (Family::Method, + method_ty.has_body, + EntryTypedData::Method(MethodTypedData { + explicit_self: method_ty.explicit_self + })) + } + ty::TypeTraitItem(ref associated_type) => { if let Some(ty) = associated_type.ty { self.encode_type(ty); } - } - } - encode_attributes(self, &trait_item.attrs); - match trait_item.node { - hir::ConstTraitItem(_, ref default) => { - self.start_tag(item_tag::trait_item_has_body); - default.is_some().encode(self).unwrap(); - self.end_tag(); + (Family::AssociatedType, false, EntryTypedData::Other) + } + }; + + self.encode_def_key(def_id); + self.encode_family(family); + self.encode_visibility(trait_item.vis()); + + encode_stability(self, def_id); + encode_attributes(self, &ast_item.attrs); + if let hir::MethodTraitItem(ref sig, _) = ast_item.node { + self.encode_fn_arg_names(&sig.decl); + }; + + self.start_tag(item_tag::data); + EntryData::TraitAssociated(TraitAssociatedData { + has_default: has_default + }).encode(self).unwrap(); + self.end_tag(); + + self.start_tag(item_tag::typed_data); + typed_data.encode(self).unwrap(); + self.end_tag(); + + self.encode_mir(def_id); + } + + fn encode_info_for_impl_item(&mut self, def_id: DefId) { + let node_id = self.tcx.map.as_local_node_id(def_id).unwrap(); + let ast_item = self.tcx.map.expect_impl_item(node_id); + let impl_item = self.tcx.impl_or_trait_item(def_id); + let impl_def_id = impl_item.container().id(); + let (family, typed_data) = match impl_item { + ty::ConstTraitItem(_) => { + self.encode_bounds_and_type_for_item(def_id); encode_inlined_item(self, - InlinedItemRef::TraitItem(trait_def_id, trait_item)); - self.encode_mir(item_def_id); - } - hir::MethodTraitItem(ref sig, ref body) => { - self.start_tag(item_tag::trait_item_has_body); - body.is_some().encode(self).unwrap(); - self.end_tag(); + InlinedItemRef::ImplItem(impl_def_id, ast_item)); + self.encode_mir(def_id); - self.encode_mir(item_def_id); - self.encode_method_argument_names(&sig.decl); - } - - hir::TypeTraitItem(..) => {} - } - } - - fn encode_info_for_impl_item(&mut self, - (impl_id, impl_item_def_id, ast_item): - (NodeId, DefId, Option<&hir::ImplItem>)) { - match self.tcx.impl_or_trait_item(impl_item_def_id) { - ty::ConstTraitItem(ref associated_const) => { - self.encode_info_for_associated_const(&associated_const, - impl_id, - ast_item) + (Family::AssociatedConst, EntryTypedData::Other) } ty::MethodTraitItem(ref method_type) => { - self.encode_info_for_method(&method_type, - impl_id, - ast_item) + self.encode_bounds_and_type_for_item(def_id); + + (Family::Method, + EntryTypedData::Method(MethodTypedData { + explicit_self: method_type.explicit_self + })) } ty::TypeTraitItem(ref associated_type) => { - self.encode_info_for_associated_type(&associated_type, - impl_id, - ast_item) + if let Some(ty) = associated_type.ty { + self.encode_type(ty); + } + + (Family::AssociatedType, EntryTypedData::Other) } - } - } + }; - fn encode_info_for_associated_const(&mut self, - associated_const: &ty::AssociatedConst, - parent_id: NodeId, - impl_item_opt: Option<&hir::ImplItem>) { - let tcx = self.tcx; - debug!("encode_info_for_associated_const({:?},{:?})", - associated_const.def_id, - associated_const.name); + self.encode_def_key(def_id); + self.encode_family(family); + self.encode_visibility(impl_item.vis()); + encode_attributes(self, &ast_item.attrs); + encode_stability(self, def_id); - encode_def_id_and_key(self, associated_const.def_id); - encode_name(self, associated_const.name); - self.encode_visibility(associated_const.vis); - encode_family(self, Family::AssociatedConst); + let constness = if let hir::ImplItemKind::Method(ref sig, _) = ast_item.node { + if sig.constness == hir::Constness::Const { + encode_inlined_item( + self, + InlinedItemRef::ImplItem(impl_def_id, ast_item)); + } - self.encode_parent_item(tcx.map.local_def_id(parent_id)); + let generics = self.tcx.lookup_generics(def_id); + let types = generics.parent_types as usize + generics.types.len(); + let needs_inline = types > 0 || attr::requests_inline(&ast_item.attrs); + if needs_inline || sig.constness == hir::Constness::Const { + self.encode_mir(def_id); + } + self.encode_fn_arg_names(&sig.decl); + sig.constness + } else { + hir::Constness::NotConst + }; - self.start_tag(item_tag::trait_item_has_body); - true.encode(self).unwrap(); + self.start_tag(item_tag::data); + EntryData::ImplAssociated(ImplAssociatedData { + defaultness: ast_item.defaultness, + constness:constness + }).encode(self).unwrap(); self.end_tag(); - self.encode_bounds_and_type_for_item(associated_const.def_id); - - let stab = tcx.lookup_stability(associated_const.def_id); - let depr = tcx.lookup_deprecation(associated_const.def_id); - encode_stability(self, stab); - encode_deprecation(self, depr); - - if let Some(ii) = impl_item_opt { - encode_attributes(self, &ii.attrs); - encode_defaultness(self, ii.defaultness); - encode_inlined_item(self, - InlinedItemRef::ImplItem(tcx.map.local_def_id(parent_id), - ii)); - self.encode_mir(associated_const.def_id); - } - } - - fn encode_info_for_method(&mut self, - m: &ty::Method<'tcx>, - parent_id: NodeId, - impl_item_opt: Option<&hir::ImplItem>) { - let tcx = self.tcx; - - debug!("encode_info_for_method: {:?} {:?}", m.def_id, - m.name); - self.encode_method_ty_fields(m); - self.encode_parent_item(tcx.map.local_def_id(parent_id)); - - self.start_tag(item_tag::trait_item_has_body); - true.encode(self).unwrap(); + self.start_tag(item_tag::typed_data); + typed_data.encode(self).unwrap(); self.end_tag(); - - let stab = tcx.lookup_stability(m.def_id); - let depr = tcx.lookup_deprecation(m.def_id); - encode_stability(self, stab); - encode_deprecation(self, depr); - - self.encode_bounds_and_type_for_item(m.def_id); - - if let Some(impl_item) = impl_item_opt { - if let hir::ImplItemKind::Method(ref sig, _) = impl_item.node { - encode_attributes(self, &impl_item.attrs); - let generics = tcx.lookup_generics(m.def_id); - let types = generics.parent_types as usize + generics.types.len(); - let needs_inline = types > 0 || attr::requests_inline(&impl_item.attrs); - if sig.constness == hir::Constness::Const { - encode_inlined_item( - self, - InlinedItemRef::ImplItem(tcx.map.local_def_id(parent_id), - impl_item)); - } - if needs_inline || sig.constness == hir::Constness::Const { - self.encode_mir(m.def_id); - } - encode_constness(self, sig.constness); - encode_defaultness(self, impl_item.defaultness); - self.encode_method_argument_names(&sig.decl); - } - } } - fn encode_info_for_associated_type(&mut self, - associated_type: &ty::AssociatedType<'tcx>, - parent_id: NodeId, - impl_item_opt: Option<&hir::ImplItem>) { - let tcx = self.tcx; - debug!("encode_info_for_associated_type({:?},{:?})", - associated_type.def_id, - associated_type.name); - - encode_def_id_and_key(self, associated_type.def_id); - encode_name(self, associated_type.name); - self.encode_visibility(associated_type.vis); - encode_family(self, Family::AssociatedType); - self.encode_parent_item(tcx.map.local_def_id(parent_id)); - - let stab = tcx.lookup_stability(associated_type.def_id); - let depr = tcx.lookup_deprecation(associated_type.def_id); - encode_stability(self, stab); - encode_deprecation(self, depr); - - if let Some(ii) = impl_item_opt { - encode_attributes(self, &ii.attrs); - encode_defaultness(self, ii.defaultness); - } - - if let Some(ty) = associated_type.ty { - self.encode_type(ty); - } - } - - fn encode_method_argument_names(&mut self, + fn encode_fn_arg_names(&mut self, decl: &hir::FnDecl) { - self.start_tag(item_tag::method_argument_names); + self.start_tag(item_tag::fn_arg_names); self.seq(&decl.inputs, |_, arg| { if let PatKind::Binding(_, ref path1, _) = arg.pat.node { @@ -710,18 +541,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.end_tag(); } - fn encode_repr_attrs(&mut self, - attrs: &[ast::Attribute]) { - let mut repr_attrs = Vec::new(); - for attr in attrs { - repr_attrs.extend(attr::find_repr_attrs(self.tcx.sess.diagnostic(), - attr)); - } - self.start_tag(item_tag::repr); - repr_attrs.encode(self); - self.end_tag(); - } - fn encode_mir(&mut self, def_id: DefId) { if let Some(mir) = self.mir_map.map.get(&def_id) { self.start_tag(item_tag::mir as usize); @@ -742,16 +561,13 @@ fn encode_inherent_implementations(ecx: &mut EncodeContext, ecx.end_tag(); } -fn encode_stability(ecx: &mut EncodeContext, stab_opt: Option<&attr::Stability>) { - stab_opt.map(|stab| { +fn encode_stability(ecx: &mut EncodeContext, def_id: DefId) { + ecx.tcx.lookup_stability(def_id).map(|stab| { ecx.start_tag(item_tag::stability); stab.encode(ecx).unwrap(); ecx.end_tag(); }); -} - -fn encode_deprecation(ecx: &mut EncodeContext, depr_opt: Option) { - depr_opt.map(|depr| { + ecx.tcx.lookup_deprecation(def_id).map(|depr| { ecx.start_tag(item_tag::deprecation); depr.encode(ecx).unwrap(); ecx.end_tag(); @@ -794,47 +610,26 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { debug!("encoding info for item at {}", tcx.sess.codemap().span_to_string(item.span)); - let vis = &item.vis; - - let (stab, depr) = tcx.dep_graph.with_task(DepNode::MetaData(def_id), || { - (tcx.lookup_stability(tcx.map.local_def_id(item.id)), - tcx.lookup_deprecation(tcx.map.local_def_id(item.id))) - }); - - match item.node { + let (family, data, typed_data) = match item.node { hir::ItemStatic(_, m, _) => { - encode_def_id_and_key(self, def_id); - encode_family(self, if m == hir::MutMutable { - Family::MutStatic - } else { - Family::ImmStatic - }); self.encode_bounds_and_type_for_item(def_id); - encode_name(self, item.name); - self.encode_visibility(vis); - encode_stability(self, stab); - encode_deprecation(self, depr); - encode_attributes(self, &item.attrs); + + if m == hir::MutMutable { + (Family::MutStatic, EntryData::Other, EntryTypedData::Other) + } else { + (Family::ImmStatic, EntryData::Other, EntryTypedData::Other) + } } hir::ItemConst(..) => { - encode_def_id_and_key(self, def_id); - encode_family(self, Family::Const); self.encode_bounds_and_type_for_item(def_id); - encode_name(self, item.name); - encode_attributes(self, &item.attrs); encode_inlined_item(self, InlinedItemRef::Item(def_id, item)); self.encode_mir(def_id); - self.encode_visibility(vis); - encode_stability(self, stab); - encode_deprecation(self, depr); + + (Family::Const, EntryData::Other, EntryTypedData::Other) } hir::ItemFn(ref decl, _, constness, _, ref generics, _) => { - encode_def_id_and_key(self, def_id); - encode_family(self, Family::Fn); let tps_len = generics.ty_params.len(); self.encode_bounds_and_type_for_item(def_id); - encode_name(self, item.name); - encode_attributes(self, &item.attrs); let needs_inline = tps_len > 0 || attr::requests_inline(&item.attrs); if constness == hir::Constness::Const { encode_inlined_item(self, InlinedItemRef::Item(def_id, item)); @@ -842,224 +637,172 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { if needs_inline || constness == hir::Constness::Const { self.encode_mir(def_id); } - encode_constness(self, constness); - self.encode_visibility(vis); - encode_stability(self, stab); - encode_deprecation(self, depr); - self.encode_method_argument_names(&decl); + self.encode_fn_arg_names(&decl); + + (Family::Fn, EntryData::Fn(FnData { + constness: constness + }), EntryTypedData::Other) } hir::ItemMod(ref m) => { - self.encode_info_for_mod(FromId(item.id, (m, &item.attrs, item.name, &item.vis))); + self.encode_info_for_mod(FromId(item.id, (m, &item.attrs, &item.vis))); + return; } hir::ItemForeignMod(ref fm) => { - encode_def_id_and_key(self, def_id); - encode_family(self, Family::ForeignMod); - encode_name(self, item.name); - // Encode all the items in self module. self.start_tag(item_tag::children); self.seq(&fm.items, |_, foreign_item| { - tcx.map.local_def_id(foreign_item.id) + tcx.map.local_def_id(foreign_item.id).index }); - <[def::Export]>::encode(&[], self).unwrap(); self.end_tag(); - self.encode_visibility(vis); - encode_stability(self, stab); - encode_deprecation(self, depr); + (Family::ForeignMod, EntryData::Other, EntryTypedData::Other) } hir::ItemTy(..) => { - encode_def_id_and_key(self, def_id); - encode_family(self, Family::Type); self.encode_bounds_and_type_for_item(def_id); - encode_name(self, item.name); - self.encode_visibility(vis); - encode_stability(self, stab); - encode_deprecation(self, depr); + + (Family::Type, EntryData::Other, EntryTypedData::Other) } hir::ItemEnum(ref enum_definition, _) => { - encode_def_id_and_key(self, def_id); - encode_family(self, Family::Enum); - encode_item_variances(self, item.id); + self.encode_item_variances(def_id); self.encode_bounds_and_type_for_item(def_id); - encode_name(self, item.name); - encode_attributes(self, &item.attrs); - self.encode_repr_attrs(&item.attrs); self.start_tag(item_tag::children); self.seq(&enum_definition.variants, |_, v| { - tcx.map.local_def_id(v.node.data.id()) + tcx.map.local_def_id(v.node.data.id()).index }); - <[def::Export]>::encode(&[], self).unwrap(); self.end_tag(); // Encode inherent implementations for self enumeration. encode_inherent_implementations(self, def_id); - self.encode_visibility(vis); - encode_stability(self, stab); - encode_deprecation(self, depr); + (Family::Enum, EntryData::Other, EntryTypedData::Other) } hir::ItemStruct(ref struct_def, _) => { - /* Index the class*/ let def = tcx.lookup_adt_def(def_id); let variant = def.struct_variant(); - /* Now, make an item for the class itself */ - encode_def_id_and_key(self, def_id); - encode_family(self, Family::Struct(variant.kind)); self.encode_bounds_and_type_for_item(def_id); - encode_item_variances(self, item.id); - encode_name(self, item.name); - encode_attributes(self, &item.attrs); - encode_stability(self, stab); - encode_deprecation(self, depr); - self.encode_visibility(vis); - self.encode_repr_attrs(&item.attrs); + self.encode_item_variances(def_id); /* Encode def_ids for each field and method for methods, write all the stuff get_trait_method needs to know*/ - self.encode_variant_fields(variant); + let struct_ctor = if !struct_def.is_struct() { + Some(tcx.map.local_def_id(struct_def.id()).index) + } else { + None + }; + let data = self.encode_variant(variant, struct_ctor); // Encode inherent implementations for self structure. encode_inherent_implementations(self, def_id); - if !struct_def.is_struct() { - let ctor_did = tcx.map.local_def_id(struct_def.id()); - self.start_tag(item_tag::struct_ctor); - ctor_did.encode(self).unwrap(); - self.end_tag(); - } + (Family::Struct, data, EntryTypedData::Other) } hir::ItemUnion(..) => { - let def = self.tcx.lookup_adt_def(def_id); - let variant = def.struct_variant(); - - encode_def_id_and_key(self, def_id); - encode_family(self, Family::Union); self.encode_bounds_and_type_for_item(def_id); - encode_item_variances(self, item.id); - encode_name(self, item.name); - encode_attributes(self, &item.attrs); - encode_stability(self, stab); - encode_deprecation(self, depr); - self.encode_visibility(vis); - self.encode_repr_attrs(&item.attrs); + self.encode_item_variances(def_id); /* Encode def_ids for each field and method for methods, write all the stuff get_trait_method needs to know*/ - self.encode_variant_fields(variant); - - encode_inlined_item(self, InlinedItemRef::Item(def_id, item)); - self.encode_mir(def_id); + let def = self.tcx.lookup_adt_def(def_id); + let data = self.encode_variant(def.struct_variant(), None); // Encode inherent implementations for self union. encode_inherent_implementations(self, def_id); + + (Family::Union, data, EntryTypedData::Other) } hir::ItemDefaultImpl(..) => { - encode_def_id_and_key(self, def_id); - encode_family(self, Family::DefaultImpl); - encode_name(self, item.name); - - let trait_ref = tcx.impl_trait_ref(tcx.map.local_def_id(item.id)).unwrap(); - encode_trait_ref(self, trait_ref, item_tag::trait_ref); + (Family::DefaultImpl, EntryData::Other, + EntryTypedData::Impl(ImplTypedData { + trait_ref: tcx.impl_trait_ref(def_id) + })) } hir::ItemImpl(_, polarity, ..) => { - encode_def_id_and_key(self, def_id); - encode_family(self, Family::Impl); self.encode_bounds_and_type_for_item(def_id); - encode_name(self, item.name); - encode_attributes(self, &item.attrs); - self.start_tag(item_tag::polarity); - polarity.encode(self).unwrap(); - self.end_tag(); - - match - tcx.custom_coerce_unsized_kinds - .borrow() - .get(&tcx.map.local_def_id(item.id)) - { - Some(&kind) => { - self.start_tag(item_tag::impl_coerce_unsized_kind); - kind.encode(self); - self.end_tag(); - } - None => {} - } + let trait_ref = tcx.impl_trait_ref(def_id); + let parent = if let Some(trait_ref) = trait_ref { + let trait_def = tcx.lookup_trait_def(trait_ref.def_id); + trait_def.ancestors(def_id).skip(1).next().and_then(|node| { + match node { + specialization_graph::Node::Impl(parent) => Some(parent), + _ => None, + } + }) + } else { + None + }; self.start_tag(item_tag::children); - tcx.impl_or_trait_items(def_id).encode(self).unwrap(); - <[def::Export]>::encode(&[], self).unwrap(); + self.seq(&tcx.impl_or_trait_items(def_id)[..], |_, &def_id| { + assert!(def_id.is_local()); + def_id.index + }); self.end_tag(); - let did = tcx.map.local_def_id(item.id); - if let Some(trait_ref) = tcx.impl_trait_ref(did) { - encode_trait_ref(self, trait_ref, item_tag::trait_ref); - - let trait_def = tcx.lookup_trait_def(trait_ref.def_id); - let parent = trait_def.ancestors(did) - .skip(1) - .next() - .and_then(|node| match node { - specialization_graph::Node::Impl(parent) => - Some(parent), - _ => None, - }); - parent.map(|parent| { - self.start_tag(item_tag::parent_impl); - parent.encode(self).unwrap(); - self.end_tag(); - }); - } - encode_stability(self, stab); - encode_deprecation(self, depr); + (Family::Impl, + EntryData::Impl(ImplData { + polarity: polarity, + parent_impl: parent, + coerce_unsized_kind: tcx.custom_coerce_unsized_kinds.borrow() + .get(&def_id).cloned() + }), + EntryTypedData::Impl(ImplTypedData { + trait_ref: trait_ref + })) } hir::ItemTrait(..) => { - encode_def_id_and_key(self, def_id); - encode_family(self, Family::Trait); - encode_item_variances(self, item.id); + self.encode_item_variances(def_id); let trait_def = tcx.lookup_trait_def(def_id); let trait_predicates = tcx.lookup_predicates(def_id); - self.start_tag(item_tag::unsafety); - trait_def.unsafety.encode(self).unwrap(); - self.end_tag(); - - self.start_tag(item_tag::paren_sugar); - trait_def.paren_sugar.encode(self).unwrap(); - self.end_tag(); - - self.start_tag(item_tag::defaulted_trait); - tcx.trait_has_default_impl(def_id).encode(self).unwrap(); - self.end_tag(); - self.encode_generics(&trait_def.generics, &trait_predicates); self.encode_predicates(&tcx.lookup_super_predicates(def_id), item_tag::super_predicates); - encode_trait_ref(self, trait_def.trait_ref, item_tag::trait_ref); - encode_name(self, item.name); - encode_attributes(self, &item.attrs); - self.encode_visibility(vis); - encode_stability(self, stab); - encode_deprecation(self, depr); self.start_tag(item_tag::children); - tcx.impl_or_trait_items(def_id).encode(self).unwrap(); - <[def::Export]>::encode(&[], self).unwrap(); + self.seq(&tcx.impl_or_trait_items(def_id)[..], |_, &def_id| { + assert!(def_id.is_local()); + def_id.index + }); self.end_tag(); // Encode inherent implementations for self trait. encode_inherent_implementations(self, def_id); + + (Family::Trait, + EntryData::Trait(TraitData { + unsafety: trait_def.unsafety, + paren_sugar: trait_def.paren_sugar, + has_default_impl: tcx.trait_has_default_impl(def_id) + }), + EntryTypedData::Trait(TraitTypedData { + trait_ref: trait_def.trait_ref + })) } hir::ItemExternCrate(_) | hir::ItemUse(_) => { bug!("cannot encode info for item {:?}", item) } - } + }; + + self.encode_family(family); + self.encode_def_key(def_id); + self.encode_visibility(&item.vis); + encode_attributes(self, &item.attrs); + encode_stability(self, def_id); + + self.start_tag(item_tag::data); + data.encode(self).unwrap(); + self.end_tag(); + + self.start_tag(item_tag::typed_data); + typed_data.encode(self).unwrap(); + self.end_tag(); } } @@ -1084,88 +827,52 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { // no sub-item recording needed in these cases } hir::ItemEnum(..) => { - self.encode_enum_variant_infos(def_id); + self.encode_fields(def_id); + + let def = self.tcx.lookup_adt_def(def_id); + for (i, variant) in def.variants.iter().enumerate() { + self.record(variant.did, + EncodeContext::encode_enum_variant_info, + (def_id, Untracked(i))); + } } hir::ItemStruct(ref struct_def, _) => { - self.encode_addl_struct_info(def_id, struct_def.id(), item); + self.encode_fields(def_id); + + // If this is a tuple-like struct, encode the type of the constructor. + match self.tcx.lookup_adt_def(def_id).struct_variant().kind { + ty::VariantKind::Struct => { + // no value for structs like struct Foo { ... } + } + ty::VariantKind::Tuple | ty::VariantKind::Unit => { + // there is a value for structs like `struct + // Foo()` and `struct Foo` + let ctor_def_id = self.tcx.map.local_def_id(struct_def.id()); + self.record(ctor_def_id, + EncodeContext::encode_struct_ctor, + ctor_def_id); + } + } } hir::ItemUnion(..) => { - self.encode_addl_union_info(def_id); + self.encode_fields(def_id); } - hir::ItemImpl(.., ref ast_items) => { - self.encode_addl_impl_info(def_id, item.id, ast_items); + hir::ItemImpl(..) => { + for &trait_item_def_id in &self.tcx.impl_or_trait_items(def_id)[..] { + self.record(trait_item_def_id, + EncodeContext::encode_info_for_impl_item, + trait_item_def_id); + } } - hir::ItemTrait(.., ref trait_items) => { - self.encode_addl_trait_info(def_id, trait_items); + hir::ItemTrait(..) => { + for &item_def_id in &self.tcx.impl_or_trait_items(def_id)[..] { + self.record(item_def_id, + EncodeContext::encode_info_for_trait_item, + item_def_id); + } } } } - - fn encode_addl_struct_info(&mut self, - def_id: DefId, - struct_node_id: ast::NodeId, - item: &hir::Item) { - let def = self.tcx.lookup_adt_def(def_id); - let variant = def.struct_variant(); - - self.encode_fields(def_id); - - // If this is a tuple-like struct, encode the type of the constructor. - match variant.kind { - ty::VariantKind::Struct => { - // no value for structs like struct Foo { ... } - } - ty::VariantKind::Tuple | ty::VariantKind::Unit => { - // there is a value for structs like `struct - // Foo()` and `struct Foo` - let ctor_def_id = self.tcx.map.local_def_id(struct_node_id); - self.record(ctor_def_id, - EncodeContext::encode_struct_ctor, - (def_id, item.id, struct_node_id)); - } - } - } - - fn encode_addl_union_info(&mut self, def_id: DefId) { - self.encode_fields(def_id); - } - - fn encode_addl_impl_info(&mut self, - def_id: DefId, - impl_id: ast::NodeId, - ast_items: &[hir::ImplItem]) { - let items = self.tcx.impl_or_trait_items(def_id); - - // Iterate down the trait items, emitting them. We rely on the - // assumption that all of the actually implemented trait items - // appear first in the impl structure, in the same order they do - // in the ast. This is a little sketchy. - let num_implemented_methods = ast_items.len(); - for (i, &trait_item_def_id) in items.iter().enumerate() { - let ast_item = if i < num_implemented_methods { - Some(&ast_items[i]) - } else { - None - }; - - self.record(trait_item_def_id, - EncodeContext::encode_info_for_impl_item, - (impl_id, trait_item_def_id, ast_item)); - } - } - - fn encode_addl_trait_info(&mut self, - def_id: DefId, - trait_items: &[hir::TraitItem]) { - // Now output the trait item info for each trait item. - let r = self.tcx.impl_or_trait_items(def_id); - for (&item_def_id, trait_item) in r.iter().zip(trait_items) { - assert!(item_def_id.is_local()); - self.record(item_def_id, - EncodeContext::encode_info_for_trait_item, - (def_id, item_def_id, trait_item)); - } - } } impl<'a, 'tcx> EncodeContext<'a, 'tcx> { @@ -1175,37 +882,30 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { debug!("writing foreign item {}", tcx.node_path_str(nitem.id)); - encode_def_id_and_key(self, def_id); - let parent_id = tcx.map.get_parent(nitem.id); - self.encode_parent_item(tcx.map.local_def_id(parent_id)); + self.encode_def_key(def_id); self.encode_visibility(&nitem.vis); - match nitem.node { + self.encode_bounds_and_type_for_item(def_id); + let family = match nitem.node { hir::ForeignItemFn(ref fndecl, _) => { - encode_family(self, Family::Fn); - self.encode_bounds_and_type_for_item(def_id); - encode_name(self, nitem.name); - encode_attributes(self, &nitem.attrs); - let stab = tcx.lookup_stability(tcx.map.local_def_id(nitem.id)); - let depr = tcx.lookup_deprecation(tcx.map.local_def_id(nitem.id)); - encode_stability(self, stab); - encode_deprecation(self, depr); - self.encode_method_argument_names(&fndecl); + self.encode_fn_arg_names(&fndecl); + + Family::ForeignFn } - hir::ForeignItemStatic(_, mutbl) => { - encode_family(self, if mutbl { - Family::MutStatic - } else { - Family::ImmStatic - }); - self.encode_bounds_and_type_for_item(def_id); - encode_attributes(self, &nitem.attrs); - let stab = tcx.lookup_stability(tcx.map.local_def_id(nitem.id)); - let depr = tcx.lookup_deprecation(tcx.map.local_def_id(nitem.id)); - encode_stability(self, stab); - encode_deprecation(self, depr); - encode_name(self, nitem.name); - } - } + hir::ForeignItemStatic(_, true) => Family::ForeignMutStatic, + hir::ForeignItemStatic(_, false) => Family::ForeignImmStatic + }; + self.encode_family(family); + + self.start_tag(item_tag::data); + EntryData::Other.encode(self).unwrap(); + self.end_tag(); + + self.start_tag(item_tag::typed_data); + EntryTypedData::Other.encode(self).unwrap(); + self.end_tag(); + + encode_attributes(self, &nitem.attrs); + encode_stability(self, def_id); } } @@ -1267,21 +967,25 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { impl<'a, 'tcx> EncodeContext<'a, 'tcx> { fn encode_info_for_anon_ty(&mut self, def_id: DefId) { - encode_def_id_and_key(self, def_id); + self.encode_def_key(def_id); self.encode_bounds_and_type_for_item(def_id); } fn encode_info_for_closure(&mut self, def_id: DefId) { let tcx = self.tcx; - encode_def_id_and_key(self, def_id); - encode_name(self, syntax::parse::token::intern("")); + self.encode_def_key(def_id); + self.encode_family(Family::Closure); - self.start_tag(item_tag::closure_ty); - tcx.tables.borrow().closure_tys[&def_id].encode(self).unwrap(); + self.start_tag(item_tag::data); + EntryData::Closure(ClosureData { + kind: tcx.closure_kind(def_id) + }).encode(self).unwrap(); self.end_tag(); - self.start_tag(item_tag::closure_kind); - tcx.closure_kind(def_id).encode(self).unwrap(); + self.start_tag(item_tag::typed_data); + EntryTypedData::Closure(ClosureTypedData { + ty: tcx.tables.borrow().closure_tys[&def_id].clone() + }).encode(self).unwrap(); self.end_tag(); assert!(self.mir_map.map.contains_key(&def_id)); @@ -1292,16 +996,14 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { fn encode_info_for_items(ecx: &mut EncodeContext) -> IndexData { let krate = ecx.tcx.map.krate(); - ecx.start_tag(root_tag::items); + // FIXME(eddyb) Avoid wrapping the items in a doc. + ecx.start_tag(0).unwrap(); let items = { let mut index = IndexBuilder::new(ecx); index.record(DefId::local(CRATE_DEF_INDEX), EncodeContext::encode_info_for_mod, - FromId(CRATE_NODE_ID, (&krate.module, - &krate.attrs, - syntax::parse::token::intern(&ecx.link_meta.crate_name), - &hir::Public))); + FromId(CRATE_NODE_ID, (&krate.module, &krate.attrs, &hir::Public))); let mut visitor = EncodeVisitor { index: index, }; @@ -1354,8 +1056,7 @@ fn encode_crate_deps(ecx: &mut EncodeContext, cstore: &cstore::CStore) { // but is enough to get transitive crate dependencies working. ecx.start_tag(root_tag::crate_deps); ecx.seq(&get_ordered_deps(cstore), |_, &(_, ref dep)| { - (dep.name(), decoder::get_crate_hash(dep.data()), - dep.explicitly_linked.get()) + (dep.name(), dep.hash(), dep.explicitly_linked.get()) }); ecx.end_tag(); } @@ -1406,18 +1107,6 @@ fn encode_native_libraries(ecx: &mut EncodeContext) { ecx.end_tag(); } -fn encode_plugin_registrar_fn(ecx: &mut EncodeContext) { - match ecx.tcx.sess.plugin_registrar_fn.get() { - Some(id) => { - let def_id = ecx.tcx.map.local_def_id(id); - ecx.start_tag(root_tag::plugin_registrar_fn); - def_id.index.encode(ecx).unwrap(); - ecx.end_tag(); - } - None => {} - } -} - fn encode_codemap(ecx: &mut EncodeContext) { let codemap = ecx.tcx.sess.codemap(); let all_filemaps = codemap.files.borrow(); @@ -1448,15 +1137,6 @@ fn encode_macro_defs(ecx: &mut EncodeContext) { (def.name, &def.attrs, def.span, body) }); ecx.end_tag(); - - if ecx.tcx.sess.crate_types.borrow().contains(&CrateTypeRustcMacro) { - let id = ecx.tcx.sess.derive_registrar_fn.get().unwrap(); - let did = ecx.tcx.map.local_def_id(id); - - ecx.start_tag(root_tag::macro_derive_registrar); - did.index.encode(ecx).unwrap(); - ecx.end_tag(); - } } struct ImplVisitor<'a, 'tcx:'a> { @@ -1601,30 +1281,29 @@ fn encode_metadata_inner(ecx: &mut EncodeContext) { let tcx = ecx.tcx; let link_meta = ecx.link_meta; - ecx.start_tag(root_tag::crate_crate_name); - link_meta.crate_name.encode(ecx).unwrap(); - ecx.end_tag(); - - ecx.start_tag(root_tag::crate_triple); - tcx.sess.opts.target_triple.encode(ecx).unwrap(); - ecx.end_tag(); - - ecx.start_tag(root_tag::crate_hash); - link_meta.crate_hash.encode(ecx).unwrap(); - ecx.end_tag(); - - ecx.start_tag(root_tag::crate_disambiguator); - tcx.sess.local_crate_disambiguator().encode(ecx).unwrap(); - ecx.end_tag(); - - encode_dylib_dependency_formats(ecx); - - ecx.start_tag(root_tag::panic_strategy); - ecx.tcx.sess.opts.cg.panic.encode(ecx); + ecx.start_tag(root_tag::crate_info); + let is_rustc_macro = tcx.sess.crate_types.borrow().contains(&CrateTypeRustcMacro); + CrateInfo { + name: link_meta.crate_name.clone(), + triple: tcx.sess.opts.target_triple.clone(), + hash: link_meta.crate_hash, + disambiguator: tcx.sess.local_crate_disambiguator().to_string(), + panic_strategy: tcx.sess.opts.cg.panic.clone(), + plugin_registrar_fn: tcx.sess.plugin_registrar_fn.get().map(|id| { + tcx.map.local_def_id(id).index + }), + macro_derive_registrar: if is_rustc_macro { + let id = tcx.sess.derive_registrar_fn.get().unwrap(); + Some(tcx.map.local_def_id(id).index) + } else { + None + } + }.encode(ecx).unwrap(); ecx.end_tag(); let mut i = ecx.position(); encode_crate_deps(ecx, ecx.cstore); + encode_dylib_dependency_formats(ecx); let dep_bytes = ecx.position() - i; // Encode the language items. @@ -1637,11 +1316,6 @@ fn encode_metadata_inner(ecx: &mut EncodeContext) { encode_native_libraries(ecx); let native_lib_bytes = ecx.position() - i; - // Encode the plugin registrar function - i = ecx.position(); - encode_plugin_registrar_fn(ecx); - let plugin_registrar_fn_bytes = ecx.position() - i; - // Encode codemap i = ecx.position(); encode_codemap(ecx); @@ -1689,7 +1363,6 @@ fn encode_metadata_inner(ecx: &mut EncodeContext) { println!(" dep bytes: {}", dep_bytes); println!(" lang item bytes: {}", lang_item_bytes); println!(" native bytes: {}", native_lib_bytes); - println!("plugin registrar bytes: {}", plugin_registrar_fn_bytes); println!(" codemap bytes: {}", codemap_bytes); println!(" macro def bytes: {}", macro_defs_bytes); println!(" impl bytes: {}", impl_bytes); diff --git a/src/librustc_metadata/index.rs b/src/librustc_metadata/index.rs index 63d7f1b58bb0..98a43c7639c3 100644 --- a/src/librustc_metadata/index.rs +++ b/src/librustc_metadata/index.rs @@ -53,6 +53,18 @@ impl Index { Some(position) } } + + pub fn iter_enumerated<'a>(&self, bytes: &'a [u8]) + -> impl Iterator + 'a { + let words = bytes_to_words(&bytes[self.data_start..self.data_end]); + words.iter().enumerate().filter_map(|(index, &position)| { + if position == u32::MAX { + None + } else { + Some((DefIndex::new(index), u32::from_be(position))) + } + }) + } } /// While we are generating the metadata, we also track the position diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs index b7125daa4ad5..b46c5be9f8a8 100644 --- a/src/librustc_metadata/lib.rs +++ b/src/librustc_metadata/lib.rs @@ -51,26 +51,24 @@ extern crate rustc_const_math; #[cfg(test)] extern crate test; -pub mod rbml { +mod rbml { pub mod writer; pub mod reader; pub use self::reader::Doc; } -pub use rustc::middle; +mod diagnostics; -pub mod diagnostics; - -pub mod astencode; -pub mod common; -pub mod def_key; -pub mod encoder; +mod astencode; +mod common; mod index_builder; -pub mod decoder; +mod index; +mod encoder; +mod decoder; +mod csearch; + pub mod creader; -pub mod csearch; pub mod cstore; -pub mod index; pub mod loader; pub mod macro_import; diff --git a/src/librustc_metadata/loader.rs b/src/librustc_metadata/loader.rs index a4f8ee477990..47bf65bead9a 100644 --- a/src/librustc_metadata/loader.rs +++ b/src/librustc_metadata/loader.rs @@ -511,9 +511,8 @@ impl<'a> Context<'a> { if let Some((ref p, _)) = lib.rlib { err.note(&format!("path: {}", p.display())); } - let data = lib.metadata.as_slice(); - let name = decoder::get_crate_name(data); - note_crate_name(&mut err, &name); + let crate_info = decoder::get_crate_info(lib.metadata.as_slice()); + note_crate_name(&mut err, &crate_info.name); } err.emit(); None @@ -610,33 +609,27 @@ impl<'a> Context<'a> { return None; } + let crate_info = decoder::get_crate_info(crate_data); if self.should_match_name { - match decoder::maybe_get_crate_name(crate_data) { - Some(ref name) if self.crate_name == *name => {} - _ => { info!("Rejecting via crate name"); return None } + if self.crate_name != crate_info.name { + info!("Rejecting via crate name"); return None; } } - let hash = match decoder::maybe_get_crate_hash(crate_data) { - None => { info!("Rejecting via lack of crate hash"); return None; } - Some(h) => h, - }; - let triple = match decoder::get_crate_triple(crate_data) { - None => { debug!("triple not present"); return None } - Some(t) => t, - }; - if triple != self.triple { - info!("Rejecting via crate triple: expected {} got {}", self.triple, triple); + if crate_info.triple != self.triple { + info!("Rejecting via crate triple: expected {} got {}", + self.triple, crate_info.triple); self.rejected_via_triple.push(CrateMismatch { path: libpath.to_path_buf(), - got: triple.to_string() + got: crate_info.triple }); return None; } if let Some(myhash) = self.hash { - if *myhash != hash { - info!("Rejecting via hash: expected {} got {}", *myhash, hash); + if *myhash != crate_info.hash { + info!("Rejecting via hash: expected {} got {}", + *myhash, crate_info.hash); self.rejected_via_hash.push(CrateMismatch { path: libpath.to_path_buf(), got: myhash.to_string() @@ -645,7 +638,7 @@ impl<'a> Context<'a> { } } - Some(hash) + Some(crate_info.hash) } diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 248690befac0..6283ff2187ab 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -271,7 +271,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, // Tuple-like ADTs are represented as ExprCall. We convert them here. expr_ty.ty_adt_def().and_then(|adt_def|{ match cx.tcx.expect_def(fun.id) { - Def::Variant(_, variant_id) => { + Def::Variant(variant_id) => { Some((adt_def, adt_def.variant_index_with_id(variant_id))) }, Def::Struct(..) => { @@ -480,8 +480,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } AdtKind::Enum => { match cx.tcx.expect_def(expr.id) { - Def::Variant(enum_id, variant_id) => { - debug_assert!(adt.did == enum_id); + Def::Variant(variant_id) => { assert!(base.is_none()); let index = adt.variant_index_with_id(variant_id); @@ -688,13 +687,12 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, }, ref sty => bug!("unexpected sty: {:?}", sty) }, - Def::Variant(enum_id, variant_id) => match cx.tcx.node_id_to_type(expr.id).sty { + Def::Variant(variant_id) => match cx.tcx.node_id_to_type(expr.id).sty { // A variant constructor. Should only be reached if not called in the same // expression. ty::TyFnDef(..) => variant_id, // A unit variant, similar special case to the struct case above. ty::TyAdt(adt_def, substs) => { - debug_assert!(adt_def.did == enum_id); let index = adt_def.variant_index_with_id(variant_id); return ExprKind::Adt { adt_def: adt_def, diff --git a/src/librustc_mir/hair/cx/pattern.rs b/src/librustc_mir/hair/cx/pattern.rs index 2c946b078a2f..7b8446b184fb 100644 --- a/src/librustc_mir/hair/cx/pattern.rs +++ b/src/librustc_mir/hair/cx/pattern.rs @@ -301,7 +301,8 @@ impl<'patcx, 'cx, 'gcx, 'tcx> PatCx<'patcx, 'cx, 'gcx, 'tcx> { subpatterns: Vec>) -> PatternKind<'tcx> { match self.cx.tcx.expect_def(pat.id) { - Def::Variant(enum_id, variant_id) => { + Def::Variant(variant_id) => { + let enum_id = self.cx.tcx.parent_def_id(variant_id).unwrap(); let adt_def = self.cx.tcx.lookup_adt_def(enum_id); if adt_def.variants.len() > 1 { PatternKind::Variant { diff --git a/src/librustc_passes/static_recursion.rs b/src/librustc_passes/static_recursion.rs index d23f77af3215..0ab8e2d7fcd2 100644 --- a/src/librustc_passes/static_recursion.rs +++ b/src/librustc_passes/static_recursion.rs @@ -272,15 +272,13 @@ impl<'a, 'ast: 'a> Visitor<'ast> for CheckItemRecursionVisitor<'a, 'ast> { // affect the specific variant used, but we need to check // the whole enum definition to see what expression that // might be (if any). - Some(Def::Variant(enum_id, variant_id)) => { - if let Some(enum_node_id) = self.ast_map.as_local_node_id(enum_id) { - if let hir::ItemEnum(ref enum_def, ref generics) = self.ast_map - .expect_item(enum_node_id) - .node { + Some(Def::Variant(variant_id)) => { + if let Some(variant_id) = self.ast_map.as_local_node_id(variant_id) { + let variant = self.ast_map.expect_variant(variant_id); + let enum_id = self.ast_map.get_parent(variant_id); + let enum_item = self.ast_map.expect_item(enum_id); + if let hir::ItemEnum(ref enum_def, ref generics) = enum_item.node { self.populate_enum_discriminants(enum_def); - let enum_id = self.ast_map.as_local_node_id(enum_id).unwrap(); - let variant_id = self.ast_map.as_local_node_id(variant_id).unwrap(); - let variant = self.ast_map.expect_variant(variant_id); self.visit_variant(variant, generics, enum_id); } else { span_bug!(e.span, diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 4012c1cb3488..1b119fd00850 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -323,8 +323,13 @@ impl<'b, 'a, 'tcx: 'a, 'v> Visitor<'v> for ReachEverythingInTheInterfaceVisitor< let def = self.ev.tcx.expect_def(ty.id); match def { Def::Struct(def_id) | Def::Union(def_id) | Def::Enum(def_id) | - Def::TyAlias(def_id) | Def::Trait(def_id) | Def::AssociatedTy(def_id, _) => { - if let Some(node_id) = self.ev.tcx.map.as_local_node_id(def_id) { + Def::TyAlias(def_id) | Def::Trait(def_id) | Def::AssociatedTy(def_id) => { + if let Some(mut node_id) = self.ev.tcx.map.as_local_node_id(def_id) { + // Check the trait for associated types. + if let hir::map::NodeTraitItem(_) = self.ev.tcx.map.get(node_id) { + node_id = self.ev.tcx.map.get_parent(node_id); + } + let item = self.ev.tcx.map.expect_item(node_id); if let Def::TyAlias(..) = def { // Type aliases are substituted. Associated type aliases are not @@ -947,9 +952,14 @@ impl<'a, 'tcx: 'a, 'v> Visitor<'v> for SearchInterfaceForPrivateItemsVisitor<'a, return } Def::Struct(def_id) | Def::Union(def_id) | Def::Enum(def_id) | - Def::TyAlias(def_id) | Def::Trait(def_id) | Def::AssociatedTy(def_id, _) => { + Def::TyAlias(def_id) | Def::Trait(def_id) | Def::AssociatedTy(def_id) => { // Non-local means public (private items can't leave their crate, modulo bugs) - if let Some(node_id) = self.tcx.map.as_local_node_id(def_id) { + if let Some(mut node_id) = self.tcx.map.as_local_node_id(def_id) { + // Check the trait for associated types. + if let hir::map::NodeTraitItem(_) = self.tcx.map.get(node_id) { + node_id = self.tcx.map.get_parent(node_id); + } + let item = self.tcx.map.expect_item(node_id); let vis = match self.substituted_alias_visibility(item, path) { Some(vis) => vis, diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 7264dcea9553..77a01aac7395 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -24,6 +24,7 @@ use {resolve_error, resolve_struct_error, ResolutionError}; use rustc::middle::cstore::ChildItem; use rustc::hir::def::*; use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId}; +use rustc::hir::map::DefPathData; use rustc::ty; use std::cell::Cell; @@ -250,8 +251,7 @@ impl<'b> Resolver<'b> { self.define(parent, name, TypeNS, (module, sp, vis)); for variant in &(*enum_definition).variants { - let item_def_id = self.definitions.local_def_id(item.id); - self.build_reduced_graph_for_variant(variant, item_def_id, module, vis); + self.build_reduced_graph_for_variant(variant, module, vis); } } @@ -314,7 +314,7 @@ impl<'b> Resolver<'b> { is_static_method = !sig.decl.has_self(); (Def::Method(item_def_id), ValueNS) } - TraitItemKind::Type(..) => (Def::AssociatedTy(def_id, item_def_id), TypeNS), + TraitItemKind::Type(..) => (Def::AssociatedTy(item_def_id), TypeNS), TraitItemKind::Macro(_) => panic!("unexpanded macro in resolve!"), }; @@ -334,7 +334,6 @@ impl<'b> Resolver<'b> { // type and value namespaces. fn build_reduced_graph_for_variant(&mut self, variant: &Variant, - item_id: DefId, parent: Module<'b>, vis: ty::Visibility) { let name = variant.node.name.name; @@ -346,7 +345,7 @@ impl<'b> Resolver<'b> { // Variants are always treated as importable to allow them to be glob used. // All variants are defined in both type and value namespaces as future-proofing. - let def = Def::Variant(item_id, self.definitions.local_def_id(variant.node.data.id())); + let def = Def::Variant(self.definitions.local_def_id(variant.node.data.id())); self.define(parent, name, ValueNS, (def, variant.span, vis)); self.define(parent, name, TypeNS, (def, variant.span, vis)); } @@ -389,20 +388,12 @@ impl<'b> Resolver<'b> { /// Builds the reduced graph for a single item in an external crate. fn build_reduced_graph_for_external_crate_def(&mut self, parent: Module<'b>, child: ChildItem) { - if let Def::ForeignMod(def_id) = child.def { - // Foreign modules have no names. Recur and populate eagerly. - for child in self.session.cstore.item_children(def_id) { - self.build_reduced_graph_for_external_crate_def(parent, child); - } - return; - } - let def = child.def; let name = child.name; let vis = if parent.is_trait() { ty::Visibility::Public } else { child.vis }; match def { - Def::Mod(_) | Def::ForeignMod(_) | Def::Enum(..) => { + Def::Mod(_) | Def::Enum(..) => { debug!("(building reduced graph for external crate) building module {} {:?}", name, vis); let parent_link = ModuleParentLink(parent, name); @@ -434,7 +425,8 @@ impl<'b> Resolver<'b> { let trait_item_def_ids = self.session.cstore.impl_or_trait_items(def_id); for &trait_item_def in &trait_item_def_ids { let trait_item_name = - self.session.cstore.item_name(trait_item_def); + self.session.cstore.opt_item_name(trait_item_def) + .expect("opt_item_name returned None for trait"); debug!("(building reduced graph for external crate) ... adding trait item \ '{}'", @@ -452,7 +444,9 @@ impl<'b> Resolver<'b> { let _ = self.try_define(parent, name, TypeNS, (def, DUMMY_SP, vis)); } Def::Struct(def_id) - if self.session.cstore.tuple_struct_definition_if_ctor(def_id).is_none() => { + if self.session.cstore.def_key(def_id).disambiguated_data.data != + DefPathData::StructCtor + => { debug!("(building reduced graph for external crate) building type and value for {}", name); let _ = self.try_define(parent, name, TypeNS, (def, DUMMY_SP, vis)); diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index b03e76c829a3..016b621eabd4 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -2757,7 +2757,7 @@ impl<'a> Resolver<'a> { if let Some(resolution) = self.def_map.get(&node_id) { match resolution.base_def { Def::Enum(did) | Def::TyAlias(did) | Def::Union(did) | - Def::Struct(did) | Def::Variant(_, did) if resolution.depth == 0 => { + Def::Struct(did) | Def::Variant(did) if resolution.depth == 0 => { if let Some(fields) = self.structs.get(&did) { if fields.iter().any(|&field_name| name == field_name) { return Field; @@ -2826,7 +2826,7 @@ impl<'a> Resolver<'a> { if let Some(path_res) = self.resolve_possibly_assoc_item(expr.id, maybe_qself.as_ref(), path, ValueNS) { // Check if struct variant - let is_struct_variant = if let Def::Variant(_, variant_id) = path_res.base_def { + let is_struct_variant = if let Def::Variant(variant_id) = path_res.base_def { self.structs.contains_key(&variant_id) } else { false diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index 2cbc110c56af..79fcff7d8a16 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -293,8 +293,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { let def = self.tcx.expect_def(ref_id); match def { - Def::Mod(_) | - Def::ForeignMod(_) => { + Def::Mod(_) => { self.dumper.mod_ref(ModRefData { span: sub_span.expect("No span found for mod ref"), ref_id: Some(def_id), diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 00c9ea3af182..cbdce3229c7c 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1373,7 +1373,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { item.expect("missing associated type").def_id() }; - (ty, Def::AssociatedTy(trait_did, item_did)) + (ty, Def::AssociatedTy(item_did)) } fn qpath_to_ty(&self, @@ -1522,8 +1522,9 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { tcx.prohibit_type_params(base_segments); tcx.mk_self_type() } - Def::AssociatedTy(trait_did, _) => { + Def::AssociatedTy(def_id) => { tcx.prohibit_type_params(&base_segments[..base_segments.len()-2]); + let trait_did = tcx.parent_def_id(def_id).unwrap(); self.qpath_to_ty(rscope, span, param_mode, diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 3a854da1d480..e38b865842e8 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3224,7 +3224,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.set_tainted_by_errors(); return None; } - Def::Variant(type_did, _) | Def::Struct(type_did) | Def::Union(type_did) => { + Def::Variant(did) => { + let type_did = self.tcx.parent_def_id(did).unwrap(); + Some((type_did, self.tcx.expect_variant_def(def))) + } + Def::Struct(type_did) | Def::Union(type_did) => { Some((type_did, self.tcx.expect_variant_def(def))) } Def::TyAlias(did) => { @@ -4115,10 +4119,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // Case 1 and 1b. Reference to a *type* or *enum variant*. Def::Struct(def_id) | Def::Union(def_id) | - Def::Variant(_, def_id) | + Def::Variant(def_id) | Def::Enum(def_id) | Def::TyAlias(def_id) | - Def::AssociatedTy(_, def_id) | + Def::AssociatedTy(def_id) | Def::Trait(def_id) => { // Everything but the final segment should have no // parameters at all. @@ -4166,7 +4170,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // here. If they do, an error will have been reported // elsewhere. (I hope) Def::Mod(..) | - Def::ForeignMod(..) | Def::PrimTy(..) | Def::SelfTy(..) | Def::TyParam(..) | diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index e72ea60072e0..855b135b8636 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -17,6 +17,7 @@ use rustc::hir; use rustc::hir::def::Def; use rustc::hir::def_id::DefId; +use rustc::hir::map::DefPathData; use rustc::hir::print as pprust; use rustc::ty::{self, TyCtxt, VariantKind}; use rustc::util::nodemap::FnvHashSet; @@ -82,7 +83,7 @@ fn try_inline_def<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>, } Def::Struct(did) // If this is a struct constructor, we skip it - if tcx.sess.cstore.tuple_struct_definition_if_ctor(did).is_none() => { + if tcx.def_key(did).disambiguated_data.data != DefPathData::StructCtor => { record_extern_fqn(cx, did, clean::TypeStruct); ret.extend(build_impls(cx, tcx, did)); clean::StructItem(build_struct(cx, tcx, did)) @@ -497,17 +498,10 @@ fn build_module<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>, // visit each node at most once. let mut visited = FnvHashSet(); for item in tcx.sess.cstore.item_children(did) { - match item.def { - Def::ForeignMod(did) => { - fill_in(cx, tcx, did, items); - } - def => { - if item.vis == ty::Visibility::Public { - if !visited.insert(def) { continue } - if let Some(i) = try_inline_def(cx, tcx, def) { - items.extend(i) - } - } + if item.vis == ty::Visibility::Public { + if !visited.insert(item.def) { continue } + if let Some(i) = try_inline_def(cx, tcx, item.def) { + items.extend(i) } } } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index f9d7eb50edae..43a9b4e49e39 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1161,7 +1161,7 @@ impl<'a, 'tcx> Clean for (DefId, &'a ty::PolyFnSig<'tcx>) { let mut names = if cx.map.as_local_node_id(did).is_some() { vec![].into_iter() } else { - cx.tcx().sess.cstore.method_arg_names(did).into_iter() + cx.tcx().sess.cstore.fn_arg_names(did).into_iter() }.peekable(); FnDecl { output: Return(sig.0.output.clean(cx)), @@ -2757,6 +2757,8 @@ fn resolve_type(cx: &DocContext, fn register_def(cx: &DocContext, def: Def) -> DefId { debug!("register_def({:?})", def); + let tcx = cx.tcx(); + let (did, kind) = match def { Def::Fn(i) => (i, TypeFunction), Def::TyAlias(i) => (i, TypeTypedef), @@ -2766,7 +2768,7 @@ fn register_def(cx: &DocContext, def: Def) -> DefId { Def::Union(i) => (i, TypeUnion), Def::Mod(i) => (i, TypeModule), Def::Static(i, _) => (i, TypeStatic), - Def::Variant(i, _) => (i, TypeEnum), + Def::Variant(i) => (tcx.parent_def_id(i).unwrap(), TypeEnum), Def::SelfTy(Some(def_id), _) => (def_id, TypeTrait), Def::SelfTy(_, Some(impl_def_id)) => { return impl_def_id @@ -2774,10 +2776,6 @@ fn register_def(cx: &DocContext, def: Def) -> DefId { _ => return def.def_id() }; if did.is_local() { return did } - let tcx = match cx.tcx_opt() { - Some(tcx) => tcx, - None => return did - }; inline::record_extern_fqn(cx, did, kind); if let TypeTrait = kind { let t = inline::build_external_trait(cx, tcx, did); diff --git a/src/librustdoc/visit_lib.rs b/src/librustdoc/visit_lib.rs index da11f652b4b3..d93ca75a8da0 100644 --- a/src/librustdoc/visit_lib.rs +++ b/src/librustdoc/visit_lib.rs @@ -68,7 +68,6 @@ impl<'a, 'b, 'tcx> LibEmbargoVisitor<'a, 'b, 'tcx> { for item in self.cstore.item_children(did) { match item.def { Def::Mod(did) | - Def::ForeignMod(did) | Def::Trait(did) | Def::Struct(did) | Def::Union(did) | @@ -84,9 +83,10 @@ impl<'a, 'b, 'tcx> LibEmbargoVisitor<'a, 'b, 'tcx> { } fn visit_item(&mut self, did: DefId, item: ChildItem) { - let inherited_item_level = match item.def { - Def::ForeignMod(..) => self.prev_level, - _ => if item.vis == Visibility::Public { self.prev_level } else { None } + let inherited_item_level = if item.vis == Visibility::Public { + self.prev_level + } else { + None }; let item_level = self.update(did, inherited_item_level); From cc47dc5c6e2502f554c465bef5a8f883139c0c4e Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Thu, 8 Sep 2016 19:54:29 +0300 Subject: [PATCH 424/443] rustc_metadata: store dense indexes in little-endian instead of big. --- src/librustc_metadata/index.rs | 29 ++++++++++------------------- 1 file changed, 10 insertions(+), 19 deletions(-) diff --git a/src/librustc_metadata/index.rs b/src/librustc_metadata/index.rs index 98a43c7639c3..80d5141c99ca 100644 --- a/src/librustc_metadata/index.rs +++ b/src/librustc_metadata/index.rs @@ -44,7 +44,7 @@ impl Index { debug!("lookup_item: index={:?} words.len={:?}", index, words.len()); - let position = u32::from_be(words[index]); + let position = u32::from_le(words[index]); if position == u32::MAX { debug!("lookup_item: position=u32::MAX"); None @@ -61,7 +61,7 @@ impl Index { if position == u32::MAX { None } else { - Some((DefIndex::new(index), u32::from_be(position))) + Some((DefIndex::new(index), u32::from_le(position))) } }) } @@ -100,13 +100,11 @@ impl IndexData { "recorded position for item {:?} twice, first at {:?} and now at {:?}", item, self.positions[item], position); - self.positions[item] = position; + self.positions[item] = position.to_le(); } pub fn write_index(&self, buf: &mut Cursor>) { - for &position in &self.positions { - write_be_u32(buf, position); - } + buf.write_all(words_to_bytes(&self.positions)).unwrap(); } } @@ -120,7 +118,7 @@ pub struct DenseIndex { impl DenseIndex { pub fn lookup(&self, buf: &[u8], ix: u32) -> Option { let data = bytes_to_words(&buf[self.start..self.end]); - data.get(ix as usize).map(|d| u32::from_be(*d)) + data.get(ix as usize).map(|d| u32::from_le(*d)) } pub fn from_buf(buf: &[u8], start: usize, end: usize) -> Self { assert!((end-start)%4 == 0 && start <= end && end <= buf.len()); @@ -135,23 +133,16 @@ pub fn write_dense_index(entries: Vec, buf: &mut Cursor>) { let elen = entries.len(); assert!(elen < u32::MAX as usize); - for entry in entries { - write_be_u32(buf, entry); - } + buf.write_all(words_to_bytes(&entries)).unwrap(); info!("write_dense_index: {} entries", elen); } -fn write_be_u32(w: &mut W, u: u32) { - let _ = w.write_all(&[ - (u >> 24) as u8, - (u >> 16) as u8, - (u >> 8) as u8, - (u >> 0) as u8, - ]); -} - fn bytes_to_words(b: &[u8]) -> &[u32] { assert!(b.len() % 4 == 0); unsafe { slice::from_raw_parts(b.as_ptr() as *const u32, b.len()/4) } } + +fn words_to_bytes(w: &[u32]) -> &[u8] { + unsafe { slice::from_raw_parts(w.as_ptr() as *const u8, w.len()*4) } +} From 6890354f3b43c98ff0e329fe7cf952eb1176ce61 Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Thu, 8 Sep 2016 21:36:22 +0300 Subject: [PATCH 425/443] rustc_metadata: use the shorthand encoding for predicates also. --- src/librustc_metadata/common.rs | 6 +- src/librustc_metadata/creader.rs | 1 - src/librustc_metadata/cstore.rs | 1 - src/librustc_metadata/decoder.rs | 39 ++++++----- src/librustc_metadata/encoder.rs | 114 ++++++++++++------------------- src/librustc_metadata/index.rs | 30 -------- 6 files changed, 67 insertions(+), 124 deletions(-) diff --git a/src/librustc_metadata/common.rs b/src/librustc_metadata/common.rs index e068395f729a..f30551cadd97 100644 --- a/src/librustc_metadata/common.rs +++ b/src/librustc_metadata/common.rs @@ -72,8 +72,6 @@ pub mod root_tag { pub const crate_info: usize = 0x104; pub const index: usize = 0x110; - pub const xref_index: usize = 0x111; - pub const xref_data: usize = 0x112; pub const crate_deps: usize = 0x102; pub const dylib_dependency_formats: usize = 0x106; pub const native_libraries: usize = 0x10a; @@ -202,7 +200,7 @@ pub mod item_tag { pub const fn_arg_names: usize = 0x85; } -/// The shorthand encoding of `Ty` uses `TypeVariants`' variant `usize` +/// The shorthand encoding uses an enum's variant index `usize` /// and is offset by this value so it never matches a real variant. /// This offset is also chosen so that the first byte is never < 0x80. -pub const TYPE_SHORTHAND_OFFSET: usize = 0x80; +pub const SHORTHAND_OFFSET: usize = 0x80; diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index dd6ef73ccdbd..73dcf9470183 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -329,7 +329,6 @@ impl<'a> CrateReader<'a> { extern_crate: Cell::new(None), info: crate_info, index: decoder::load_index(metadata.as_slice()), - xref_index: decoder::load_xrefs(metadata.as_slice()), key_map: decoder::load_key_map(metadata.as_slice()), data: metadata, cnum_map: RefCell::new(cnum_map), diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs index c6cbe6db9098..44fdf29aa73c 100644 --- a/src/librustc_metadata/cstore.rs +++ b/src/librustc_metadata/cstore.rs @@ -80,7 +80,6 @@ pub struct CrateMetadata { pub info: common::CrateInfo, pub index: index::Index, - pub xref_index: index::DenseIndex, /// For each public item in this crate, we encode a key. When the /// crate is loaded, we read all the keys and put them in this diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index f3283451b93b..c665a7be955d 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -243,10 +243,10 @@ impl<'a, 'tcx> SpecializedDecoder> for DecodeContext<'a, 'tcx> { // Handle shorthands first, if we have an usize > 0x80. if self.opaque.data[self.opaque.position()] & 0x80 != 0 { let pos = self.read_usize()?; - assert!(pos >= TYPE_SHORTHAND_OFFSET); + assert!(pos >= SHORTHAND_OFFSET); let key = ty::CReaderCacheKey { cnum: self.cdata().cnum, - pos: pos - TYPE_SHORTHAND_OFFSET + pos: pos - SHORTHAND_OFFSET }; if let Some(ty) = tcx.rcache.borrow().get(&key).cloned() { return Ok(ty); @@ -333,11 +333,6 @@ pub fn crate_rustc_version(data: &[u8]) -> Option { }) } -pub fn load_xrefs(data: &[u8]) -> index::DenseIndex { - let index = rbml::Doc::new(data).get(root_tag::xref_index); - index::DenseIndex::from_buf(index.data, index.start, index.end) -} - // Go through each item in the metadata and create a map from that // item's def-key to the item's DefIndex. pub fn load_key_map(data: &[u8]) -> FnvHashMap { @@ -1099,20 +1094,28 @@ fn doc_predicates<'a, 'tcx>(base_doc: rbml::Doc, { let mut dcx = base_doc.get(tag).decoder(); dcx.cdata = Some(cdata); + dcx.tcx = Some(tcx); ty::GenericPredicates { parent: dcx.decode(), - predicates: dcx.seq().map(|offset| { - let predicate_pos = cdata.xref_index.lookup( - cdata.data(), offset).unwrap() as usize; - let mut dcx = rbml::Doc { - data: cdata.data(), - start: predicate_pos, - end: cdata.data().len(), - }.decoder(); - dcx.tcx = Some(tcx); - dcx.cdata = Some(cdata); - dcx.decode() + predicates: (0..dcx.decode::()).map(|_| { + // Handle shorthands first, if we have an usize > 0x80. + if dcx.opaque.data[dcx.opaque.position()] & 0x80 != 0 { + let pos = dcx.decode::(); + assert!(pos >= SHORTHAND_OFFSET); + let pos = pos - SHORTHAND_OFFSET; + + let mut dcx = rbml::Doc { + data: cdata.data(), + start: pos, + end: cdata.data().len(), + }.decoder(); + dcx.tcx = Some(tcx); + dcx.cdata = Some(cdata); + dcx.decode() + } else { + dcx.decode() + } }).collect() } } diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 3ad9251b0721..637228725e0b 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -16,7 +16,7 @@ use astencode::encode_inlined_item; use common::*; use cstore; -use index::{self, IndexData}; +use index::IndexData; use rustc::middle::cstore::{InlinedItemRef, LinkMeta, LinkagePreference}; use rustc::hir::def; @@ -30,11 +30,10 @@ use rustc::session::config::{self, CrateTypeRustcMacro}; use rustc::util::nodemap::{FnvHashMap, NodeSet}; use rustc_serialize::{Encodable, Encoder, SpecializedEncoder, opaque}; -use std::cell::RefCell; +use std::hash::Hash; use std::intrinsics; use std::io::prelude::*; use std::io::Cursor; -use std::mem; use std::ops::{Deref, DerefMut}; use std::rc::Rc; use std::u32; @@ -58,14 +57,10 @@ pub struct EncodeContext<'a, 'tcx: 'a> { reachable: &'a NodeSet, mir_map: &'a MirMap<'tcx>, - type_shorthands: RefCell, usize>>, - xrefs: FnvHashMap, u32>, // sequentially-assigned + type_shorthands: FnvHashMap, usize>, + predicate_shorthands: FnvHashMap, usize>, } -/// "interned" entries referenced by id -#[derive(PartialEq, Eq, Hash)] -enum XRef<'tcx> { Predicate(ty::Predicate<'tcx>) } - impl<'a, 'tcx> Deref for EncodeContext<'a, 'tcx> { type Target = rbml::writer::Encoder<'a>; fn deref(&self) -> &Self::Target { @@ -117,32 +112,7 @@ impl<'a, 'tcx> Encoder for EncodeContext<'a, 'tcx> { impl<'a, 'tcx> SpecializedEncoder> for EncodeContext<'a, 'tcx> { fn specialized_encode(&mut self, ty: &Ty<'tcx>) -> Result<(), Self::Error> { - let existing_shorthand = self.type_shorthands.borrow().get(ty).cloned(); - if let Some(shorthand) = existing_shorthand { - return self.emit_usize(shorthand); - } - - let start = self.mark_stable_position(); - ty.sty.encode(self)?; - let len = self.mark_stable_position() - start; - - // The shorthand encoding uses the same usize as the - // discriminant, with an offset so they can't conflict. - let discriminant = unsafe { intrinsics::discriminant_value(&ty.sty) }; - assert!(discriminant < TYPE_SHORTHAND_OFFSET as u64); - let shorthand = start + TYPE_SHORTHAND_OFFSET; - - // Get the number of bits that leb128 could fit - // in the same space as the fully encoded type. - let leb128_bits = len * 7; - - // Check that the shorthand is a not longer than the - // full encoding itself, i.e. it's an obvious win. - if leb128_bits >= 64 || (shorthand as u64) < (1 << leb128_bits) { - self.type_shorthands.borrow_mut().insert(*ty, shorthand); - } - - Ok(()) + self.encode_with_shorthand(ty, &ty.sty, |ecx| &mut ecx.type_shorthands) } } @@ -163,6 +133,42 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { }).unwrap(); } + /// Encode the given value or a previously cached shorthand. + fn encode_with_shorthand(&mut self, value: &T, variant: &U, map: M) + -> Result<(), ::Error> + where M: for<'b> Fn(&'b mut Self) -> &'b mut FnvHashMap, + T: Clone + Eq + Hash, + U: Encodable { + let existing_shorthand = map(self).get(value).cloned(); + if let Some(shorthand) = existing_shorthand { + return self.emit_usize(shorthand); + } + + let start = self.mark_stable_position(); + variant.encode(self)?; + let len = self.mark_stable_position() - start; + + // The shorthand encoding uses the same usize as the + // discriminant, with an offset so they can't conflict. + let discriminant = unsafe { + intrinsics::discriminant_value(variant) + }; + assert!(discriminant < SHORTHAND_OFFSET as u64); + let shorthand = start + SHORTHAND_OFFSET; + + // Get the number of bits that leb128 could fit + // in the same space as the fully encoded type. + let leb128_bits = len * 7; + + // Check that the shorthand is a not longer than the + // full encoding itself, i.e. it's an obvious win. + if leb128_bits >= 64 || (shorthand as u64) < (1 << leb128_bits) { + map(self).insert(value.clone(), shorthand); + } + + Ok(()) + } + /// For every DefId that we create a metadata item for, we include a /// serialized copy of its DefKey, which allows us to recreate a path. fn encode_def_key(&mut self, def_id: DefId) { @@ -393,7 +399,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.start_tag(tag); predicates.parent.encode(self).unwrap(); self.seq(&predicates.predicates, |ecx, predicate| { - ecx.add_xref(XRef::Predicate(predicate.clone())) + ecx.encode_with_shorthand(predicate, predicate, + |ecx| &mut ecx.predicate_shorthands).unwrap() }); self.end_tag(); } @@ -575,34 +582,6 @@ fn encode_stability(ecx: &mut EncodeContext, def_id: DefId) { } impl<'a, 'tcx> EncodeContext<'a, 'tcx> { - fn add_xref(&mut self, xref: XRef<'tcx>) -> u32 { - let old_len = self.xrefs.len() as u32; - *self.xrefs.entry(xref).or_insert(old_len) - } - - fn encode_xrefs(&mut self) { - let xrefs = mem::replace(&mut self.xrefs, Default::default()); - let mut xref_positions = vec![0; xrefs.len()]; - - // Encode XRefs sorted by their ID - let mut sorted_xrefs: Vec<_> = xrefs.into_iter().collect(); - sorted_xrefs.sort_by_key(|&(_, id)| id); - - self.start_tag(root_tag::xref_data); - for (xref, id) in sorted_xrefs.into_iter() { - xref_positions[id as usize] = self.mark_stable_position() as u32; - match xref { - XRef::Predicate(p) => p.encode(self).unwrap() - } - } - self.mark_stable_position(); - self.end_tag(); - - self.start_tag(root_tag::xref_index); - index::write_dense_index(xref_positions, &mut self.opaque.cursor); - self.end_tag(); - } - fn encode_info_for_item(&mut self, (def_id, item): (DefId, &hir::Item)) { let tcx = self.tcx; @@ -1233,7 +1212,7 @@ pub fn encode_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, reachable: reachable, mir_map: mir_map, type_shorthands: Default::default(), - xrefs: Default::default() + predicate_shorthands: Default::default() }); // RBML compacts the encoded bytes whenever appropriate, @@ -1345,10 +1324,6 @@ fn encode_metadata_inner(ecx: &mut EncodeContext) { encode_item_index(ecx, items); let index_bytes = ecx.position() - i; - i = ecx.position(); - ecx.encode_xrefs(); - let xref_bytes = ecx.position() - i; - let total_bytes = ecx.position(); if ecx.tcx.sess.meta_stats() { @@ -1369,7 +1344,6 @@ fn encode_metadata_inner(ecx: &mut EncodeContext) { println!(" reachable bytes: {}", reachable_bytes); println!(" item bytes: {}", item_bytes); println!(" index bytes: {}", index_bytes); - println!(" xref bytes: {}", xref_bytes); println!(" zero bytes: {}", zero_bytes); println!(" total bytes: {}", total_bytes); } diff --git a/src/librustc_metadata/index.rs b/src/librustc_metadata/index.rs index 80d5141c99ca..2c16411c37bd 100644 --- a/src/librustc_metadata/index.rs +++ b/src/librustc_metadata/index.rs @@ -108,36 +108,6 @@ impl IndexData { } } -/// A dense index with integer keys. Different API from IndexData (should -/// these be merged?) -pub struct DenseIndex { - start: usize, - end: usize -} - -impl DenseIndex { - pub fn lookup(&self, buf: &[u8], ix: u32) -> Option { - let data = bytes_to_words(&buf[self.start..self.end]); - data.get(ix as usize).map(|d| u32::from_le(*d)) - } - pub fn from_buf(buf: &[u8], start: usize, end: usize) -> Self { - assert!((end-start)%4 == 0 && start <= end && end <= buf.len()); - DenseIndex { - start: start, - end: end - } - } -} - -pub fn write_dense_index(entries: Vec, buf: &mut Cursor>) { - let elen = entries.len(); - assert!(elen < u32::MAX as usize); - - buf.write_all(words_to_bytes(&entries)).unwrap(); - - info!("write_dense_index: {} entries", elen); -} - fn bytes_to_words(b: &[u8]) -> &[u32] { assert!(b.len() % 4 == 0); unsafe { slice::from_raw_parts(b.as_ptr() as *const u32, b.len()/4) } From adddfccf2b63f7969d80d459788e973b56168ec4 Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Thu, 15 Sep 2016 11:04:00 +0300 Subject: [PATCH 426/443] rustc_metadata: move all encoding/decoding helpers to methods. --- src/librustc/middle/cstore.rs | 3 - src/librustc_metadata/astencode.rs | 6 +- src/librustc_metadata/creader.rs | 35 +- src/librustc_metadata/csearch.rs | 148 +-- src/librustc_metadata/cstore.rs | 22 +- src/librustc_metadata/decoder.rs | 1569 ++++++++++++-------------- src/librustc_metadata/encoder.rs | 461 ++++---- src/librustc_metadata/loader.rs | 13 +- src/librustc_metadata/rbml/reader.rs | 73 +- src/librustdoc/clean/mod.rs | 4 +- 10 files changed, 1103 insertions(+), 1231 deletions(-) diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 87fdc858cf0f..6324995f328b 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -188,7 +188,6 @@ pub trait CrateStore<'tcx> { fn is_compiler_builtins(&self, cnum: CrateNum) -> bool; fn panic_strategy(&self, cnum: CrateNum) -> PanicStrategy; fn extern_crate(&self, cnum: CrateNum) -> Option; - fn crate_attrs(&self, cnum: CrateNum) -> Vec; /// The name of the crate as it is referred to in source code of the current /// crate. fn crate_name(&self, cnum: CrateNum) -> InternedString; @@ -365,8 +364,6 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { bug!("panic_strategy") } fn extern_crate(&self, cnum: CrateNum) -> Option { bug!("extern_crate") } - fn crate_attrs(&self, cnum: CrateNum) -> Vec - { bug!("crate_attrs") } fn crate_name(&self, cnum: CrateNum) -> InternedString { bug!("crate_name") } fn original_crate_name(&self, cnum: CrateNum) -> InternedString { bug!("original_crate_name") diff --git a/src/librustc_metadata/astencode.rs b/src/librustc_metadata/astencode.rs index 518e66244121..f48c31fc2f9d 100644 --- a/src/librustc_metadata/astencode.rs +++ b/src/librustc_metadata/astencode.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![allow(non_camel_case_types)] - use rustc::hir::map as ast_map; use rustc::hir::intravisit::{Visitor, IdRangeComputingVisitor, IdRange}; @@ -64,9 +62,7 @@ pub fn decode_inlined_item<'a, 'tcx>(cdata: &CrateMetadata, orig_did: DefId) -> &'tcx InlinedItem { debug!("> Decoding inlined fn: {:?}", tcx.item_path_str(orig_did)); - let dcx = &mut ast_doc.decoder(); - dcx.tcx = Some(tcx); - dcx.cdata = Some(cdata); + let dcx = &mut DecodeContext::new(ast_doc, Some(cdata)).typed(tcx); dcx.from_id_range = IdRange::decode(dcx).unwrap(); let cnt = dcx.from_id_range.max.as_usize() - dcx.from_id_range.min.as_usize(); dcx.to_id_range.min = tcx.sess.reserve_node_ids(cnt); diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 73dcf9470183..77a583f7379c 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -14,7 +14,6 @@ use common::CrateInfo; use cstore::{self, CStore, CrateSource, MetadataBlob}; -use decoder; use loader::{self, CratePaths}; use rustc::hir::def_id::{CrateNum, DefIndex}; @@ -28,6 +27,7 @@ use rustc::util::nodemap::{FnvHashMap, FnvHashSet}; use rustc::hir::map as hir_map; use std::cell::{RefCell, Cell}; +use std::ops::Deref; use std::path::PathBuf; use std::rc::Rc; use std::fs; @@ -143,11 +143,13 @@ enum PMDSource { Owned(loader::Library), } -impl PMDSource { - pub fn as_slice<'a>(&'a self) -> &'a [u8] { +impl Deref for PMDSource { + type Target = MetadataBlob; + + fn deref(&self) -> &MetadataBlob { match *self { - PMDSource::Registered(ref cmd) => cmd.data(), - PMDSource::Owned(ref lib) => lib.metadata.as_slice(), + PMDSource::Registered(ref cmd) => &cmd.data, + PMDSource::Owned(ref lib) => &lib.metadata } } } @@ -295,7 +297,7 @@ impl<'a> CrateReader<'a> { -> (CrateNum, Rc, cstore::CrateSource) { info!("register crate `extern crate {} as {}`", name, ident); - let crate_info = decoder::get_crate_info(lib.metadata.as_slice()); + let crate_info = lib.metadata.get_crate_info(); self.verify_no_symbol_conflicts(span, &crate_info); // Claim this crate number and cache it @@ -317,7 +319,7 @@ impl<'a> CrateReader<'a> { let loader::Library { dylib, rlib, metadata } = lib; - let cnum_map = self.resolve_crate_deps(root, metadata.as_slice(), cnum, span); + let cnum_map = self.resolve_crate_deps(root, &metadata, cnum, span); if crate_info.macro_derive_registrar.is_some() { self.sess.span_err(span, "crates of the `rustc-macro` crate type \ @@ -328,8 +330,8 @@ impl<'a> CrateReader<'a> { name: name.to_string(), extern_crate: Cell::new(None), info: crate_info, - index: decoder::load_index(metadata.as_slice()), - key_map: decoder::load_key_map(metadata.as_slice()), + index: metadata.load_index(), + key_map: metadata.load_key_map(), data: metadata, cnum_map: RefCell::new(cnum_map), cnum: cnum, @@ -414,7 +416,7 @@ impl<'a> CrateReader<'a> { // Note that we only do this for target triple crates, though, as we // don't want to match a host crate against an equivalent target one // already loaded. - let crate_info = decoder::get_crate_info(library.metadata.as_slice()); + let crate_info = library.metadata.get_crate_info(); if loader.triple == self.sess.opts.target_triple { let mut result = LoadResult::Loaded(library); self.cstore.iter_crate_data(|cnum, data| { @@ -465,14 +467,14 @@ impl<'a> CrateReader<'a> { // Go through the crate metadata and load any crates that it references fn resolve_crate_deps(&mut self, root: &Option, - cdata: &[u8], + metadata: &MetadataBlob, krate: CrateNum, span: Span) -> cstore::CrateNumMap { debug!("resolving deps of external crate"); // The map from crate numbers in the crate we're resolving to local crate // numbers - let map: FnvHashMap<_, _> = decoder::get_crate_deps(cdata).iter().map(|dep| { + let map: FnvHashMap<_, _> = metadata.get_crate_deps().iter().map(|dep| { debug!("resolving dep crate {} hash: `{}`", dep.name, dep.hash); let (local_cnum, ..) = self.resolve_crate(root, &dep.name, @@ -566,7 +568,7 @@ impl<'a> CrateReader<'a> { let ci = self.extract_crate_info(item).unwrap(); let ekrate = self.read_extension_crate(item.span, &ci); - let crate_info = decoder::get_crate_info(ekrate.metadata.as_slice()); + let crate_info = ekrate.metadata.get_crate_info(); let source_name = format!("<{} macros>", item.ident); let mut ret = Macros { macro_rules: Vec::new(), @@ -574,8 +576,7 @@ impl<'a> CrateReader<'a> { svh: crate_info.hash, dylib: None, }; - decoder::each_exported_macro(ekrate.metadata.as_slice(), - |name, attrs, span, body| { + ekrate.metadata.each_exported_macro(|name, attrs, span, body| { // NB: Don't use parse::parse_tts_from_source_str because it parses with // quote_depth > 0. let mut p = parse::new_parser_from_source_str(&self.sess.parse_sess, @@ -670,7 +671,7 @@ impl<'a> CrateReader<'a> { span_fatal!(self.sess, span, E0456, "{}", &message[..]); } - let crate_info = decoder::get_crate_info(ekrate.metadata.as_slice()); + let crate_info = ekrate.metadata.get_crate_info(); match (ekrate.dylib.as_ref(), crate_info.plugin_registrar_fn) { (Some(dylib), Some(reg)) => { Some((dylib.to_path_buf(), crate_info.hash, reg)) @@ -1111,7 +1112,7 @@ pub fn read_local_crates(sess: & Session, pub fn import_codemap(local_codemap: &codemap::CodeMap, metadata: &MetadataBlob) -> Vec { - let external_codemap = decoder::get_imported_filemaps(metadata.as_slice()); + let external_codemap = metadata.get_imported_filemaps(); let imported_filemaps = external_codemap.into_iter().map(|filemap_to_import| { // Try to find an existing FileMap that can be reused for the filemap to diff --git a/src/librustc_metadata/csearch.rs b/src/librustc_metadata/csearch.rs index f650155c0354..8136fc7e845f 100644 --- a/src/librustc_metadata/csearch.rs +++ b/src/librustc_metadata/csearch.rs @@ -10,7 +10,6 @@ use cstore; use common; -use decoder; use encoder; use loader; @@ -40,101 +39,87 @@ use rustc::hir; impl<'tcx> CrateStore<'tcx> for cstore::CStore { fn stability(&self, def: DefId) -> Option { self.dep_graph.read(DepNode::MetaData(def)); - let cdata = self.get_crate_data(def.krate); - decoder::get_stability(&cdata, def.index) + self.get_crate_data(def.krate).get_stability(def.index) } fn deprecation(&self, def: DefId) -> Option { self.dep_graph.read(DepNode::MetaData(def)); - let cdata = self.get_crate_data(def.krate); - decoder::get_deprecation(&cdata, def.index) + self.get_crate_data(def.krate).get_deprecation(def.index) } fn visibility(&self, def: DefId) -> ty::Visibility { self.dep_graph.read(DepNode::MetaData(def)); - let cdata = self.get_crate_data(def.krate); - decoder::get_visibility(&cdata, def.index) + self.get_crate_data(def.krate).get_visibility(def.index) } fn closure_kind(&self, def_id: DefId) -> ty::ClosureKind { assert!(!def_id.is_local()); self.dep_graph.read(DepNode::MetaData(def_id)); - let cdata = self.get_crate_data(def_id.krate); - decoder::closure_kind(&cdata, def_id.index) + self.get_crate_data(def_id.krate).closure_kind(def_id.index) } fn closure_ty<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> ty::ClosureTy<'tcx> { assert!(!def_id.is_local()); self.dep_graph.read(DepNode::MetaData(def_id)); - let cdata = self.get_crate_data(def_id.krate); - decoder::closure_ty(&cdata, def_id.index, tcx) + self.get_crate_data(def_id.krate).closure_ty(def_id.index, tcx) } fn item_variances(&self, def: DefId) -> Vec { self.dep_graph.read(DepNode::MetaData(def)); - let cdata = self.get_crate_data(def.krate); - decoder::get_item_variances(&cdata, def.index) + self.get_crate_data(def.krate).get_item_variances(def.index) } fn item_type<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> Ty<'tcx> { self.dep_graph.read(DepNode::MetaData(def)); - let cdata = self.get_crate_data(def.krate); - decoder::get_type(&cdata, def.index, tcx) + self.get_crate_data(def.krate).get_type(def.index, tcx) } fn item_predicates<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> ty::GenericPredicates<'tcx> { self.dep_graph.read(DepNode::MetaData(def)); - let cdata = self.get_crate_data(def.krate); - decoder::get_predicates(&cdata, def.index, tcx) + self.get_crate_data(def.krate).get_predicates(def.index, tcx) } fn item_super_predicates<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> ty::GenericPredicates<'tcx> { self.dep_graph.read(DepNode::MetaData(def)); - let cdata = self.get_crate_data(def.krate); - decoder::get_super_predicates(&cdata, def.index, tcx) + self.get_crate_data(def.krate).get_super_predicates(def.index, tcx) } fn item_generics<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> &'tcx ty::Generics<'tcx> { self.dep_graph.read(DepNode::MetaData(def)); - let cdata = self.get_crate_data(def.krate); - decoder::get_generics(&cdata, def.index, tcx) + self.get_crate_data(def.krate).get_generics(def.index, tcx) } fn item_attrs(&self, def_id: DefId) -> Vec { self.dep_graph.read(DepNode::MetaData(def_id)); - let cdata = self.get_crate_data(def_id.krate); - decoder::get_item_attrs(&cdata, def_id.index) + self.get_crate_data(def_id.krate).get_item_attrs(def_id.index) } fn trait_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> ty::TraitDef<'tcx> { self.dep_graph.read(DepNode::MetaData(def)); - let cdata = self.get_crate_data(def.krate); - decoder::get_trait_def(&cdata, def.index, tcx) + self.get_crate_data(def.krate).get_trait_def(def.index, tcx) } fn adt_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> ty::AdtDefMaster<'tcx> { self.dep_graph.read(DepNode::MetaData(def)); - let cdata = self.get_crate_data(def.krate); - decoder::get_adt_def(&cdata, def.index, tcx) + self.get_crate_data(def.krate).get_adt_def(def.index, tcx) } fn fn_arg_names(&self, did: DefId) -> Vec { self.dep_graph.read(DepNode::MetaData(did)); - let cdata = self.get_crate_data(did.krate); - decoder::get_fn_arg_names(&cdata, did.index) + self.get_crate_data(did.krate).get_fn_arg_names(did.index) } fn opt_item_name(&self, def: DefId) -> Option { @@ -143,7 +128,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { if def.index == CRATE_DEF_INDEX { Some(token::intern(&cdata.name())) } else { - decoder::maybe_get_item_name(&cdata, def.index) + cdata.maybe_get_item_name(def.index) } } @@ -151,9 +136,8 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { { self.dep_graph.read(DepNode::MetaData(def_id)); let mut result = vec![]; - let cdata = self.get_crate_data(def_id.krate); - decoder::each_inherent_implementation_for_type(&cdata, def_id.index, - |iid| result.push(iid)); + self.get_crate_data(def_id.krate) + .each_inherent_implementation_for_type(def_id.index, |iid| result.push(iid)); result } @@ -164,7 +148,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { } let mut result = vec![]; self.iter_crate_data(|_, cdata| { - decoder::each_implementation_for_trait(cdata, filter, &mut |iid| { + cdata.each_implementation_for_trait(filter, &mut |iid| { result.push(iid) }) }); @@ -174,85 +158,74 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { fn impl_or_trait_items(&self, def_id: DefId) -> Vec { self.dep_graph.read(DepNode::MetaData(def_id)); let mut result = vec![]; - let crate_data = self.get_crate_data(def_id.krate); let get_crate_data = &mut |cnum| self.get_crate_data(cnum); - decoder::each_child_of_item(&crate_data, def_id.index, get_crate_data, - &mut |def, _, _| result.push(def.def_id())); + self.get_crate_data(def_id.krate) + .each_child_of_item(def_id.index, get_crate_data, + &mut |def, _, _| result.push(def.def_id())); result } fn impl_polarity(&self, def: DefId) -> hir::ImplPolarity { self.dep_graph.read(DepNode::MetaData(def)); - let cdata = self.get_crate_data(def.krate); - decoder::get_impl_polarity(&cdata, def.index) + self.get_crate_data(def.krate).get_impl_polarity(def.index) } fn impl_trait_ref<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> Option> { self.dep_graph.read(DepNode::MetaData(def)); - let cdata = self.get_crate_data(def.krate); - decoder::get_impl_trait(&cdata, def.index, tcx) + self.get_crate_data(def.krate).get_impl_trait(def.index, tcx) } fn custom_coerce_unsized_kind(&self, def: DefId) -> Option { self.dep_graph.read(DepNode::MetaData(def)); - let cdata = self.get_crate_data(def.krate); - decoder::get_custom_coerce_unsized_kind(&cdata, def.index) + self.get_crate_data(def.krate).get_custom_coerce_unsized_kind(def.index) } fn impl_parent(&self, impl_def: DefId) -> Option { self.dep_graph.read(DepNode::MetaData(impl_def)); - let cdata = self.get_crate_data(impl_def.krate); - decoder::get_parent_impl(&*cdata, impl_def.index) + self.get_crate_data(impl_def.krate).get_parent_impl(impl_def.index) } fn trait_of_item(&self, def_id: DefId) -> Option { self.dep_graph.read(DepNode::MetaData(def_id)); - let cdata = self.get_crate_data(def_id.krate); - decoder::get_trait_of_item(&cdata, def_id.index) + self.get_crate_data(def_id.krate).get_trait_of_item(def_id.index) } fn impl_or_trait_item<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> Option> { self.dep_graph.read(DepNode::MetaData(def)); - let cdata = self.get_crate_data(def.krate); - decoder::get_impl_or_trait_item(&cdata, def.index, tcx) + self.get_crate_data(def.krate).get_impl_or_trait_item(def.index, tcx) } fn is_const_fn(&self, did: DefId) -> bool { self.dep_graph.read(DepNode::MetaData(did)); - let cdata = self.get_crate_data(did.krate); - decoder::is_const_fn(&cdata, did.index) + self.get_crate_data(did.krate).is_const_fn(did.index) } fn is_defaulted_trait(&self, trait_def_id: DefId) -> bool { self.dep_graph.read(DepNode::MetaData(trait_def_id)); - let cdata = self.get_crate_data(trait_def_id.krate); - decoder::is_defaulted_trait(&cdata, trait_def_id.index) + self.get_crate_data(trait_def_id.krate).is_defaulted_trait(trait_def_id.index) } fn is_default_impl(&self, impl_did: DefId) -> bool { self.dep_graph.read(DepNode::MetaData(impl_did)); - let cdata = self.get_crate_data(impl_did.krate); - decoder::is_default_impl(&cdata, impl_did.index) + self.get_crate_data(impl_did.krate).is_default_impl(impl_did.index) } fn is_extern_item<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, did: DefId) -> bool { self.dep_graph.read(DepNode::MetaData(did)); - let cdata = self.get_crate_data(did.krate); - decoder::is_extern_item(&cdata, did.index, tcx) + self.get_crate_data(did.krate).is_extern_item(did.index, tcx) } fn is_foreign_item(&self, did: DefId) -> bool { - let cdata = self.get_crate_data(did.krate); - decoder::is_foreign_item(&cdata, did.index) + self.get_crate_data(did.krate).is_foreign_item(did.index) } fn is_statically_included_foreign_item(&self, id: ast::NodeId) -> bool @@ -263,21 +236,18 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { fn dylib_dependency_formats(&self, cnum: CrateNum) -> Vec<(CrateNum, LinkagePreference)> { - let cdata = self.get_crate_data(cnum); - decoder::get_dylib_dependency_formats(&cdata) + self.get_crate_data(cnum).get_dylib_dependency_formats() } fn lang_items(&self, cnum: CrateNum) -> Vec<(DefIndex, usize)> { - let crate_data = self.get_crate_data(cnum); - decoder::get_lang_items(&crate_data) + self.get_crate_data(cnum).get_lang_items() } fn missing_lang_items(&self, cnum: CrateNum) -> Vec { - let cdata = self.get_crate_data(cnum); - decoder::get_missing_lang_items(&cdata) + self.get_crate_data(cnum).get_missing_lang_items() } fn is_staged_api(&self, cnum: CrateNum) -> bool @@ -308,11 +278,6 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { self.get_crate_data(cnum).panic_strategy() } - fn crate_attrs(&self, cnum: CrateNum) -> Vec - { - decoder::get_item_attrs(&self.get_crate_data(cnum), CRATE_DEF_INDEX) - } - fn crate_name(&self, cnum: CrateNum) -> token::InternedString { token::intern_and_get_ident(&self.get_crate_data(cnum).name[..]) @@ -348,18 +313,16 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { fn native_libraries(&self, cnum: CrateNum) -> Vec<(NativeLibraryKind, String)> { - let cdata = self.get_crate_data(cnum); - decoder::get_native_libraries(&cdata) + self.get_crate_data(cnum).get_native_libraries() } fn reachable_ids(&self, cnum: CrateNum) -> Vec { - let cdata = self.get_crate_data(cnum); - decoder::get_reachable_ids(&cdata) + self.get_crate_data(cnum).get_reachable_ids() } fn is_no_builtins(&self, cnum: CrateNum) -> bool { - attr::contains_name(&self.crate_attrs(cnum), "no_builtins") + self.get_crate_data(cnum).is_no_builtins() } fn def_index_for_def_key(&self, @@ -380,8 +343,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { // canonical name for an item. // // self.dep_graph.read(DepNode::MetaData(def)); - let cdata = self.get_crate_data(def.krate); - decoder::def_key(&cdata, def.index) + self.get_crate_data(def.krate).def_key(def.index) } fn relative_def_path(&self, def: DefId) -> Option { @@ -389,34 +351,35 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { // commented out: // // self.dep_graph.read(DepNode::MetaData(def)); - let cdata = self.get_crate_data(def.krate); - decoder::def_path(&cdata, def.index) + self.get_crate_data(def.krate).def_path(def.index) } fn struct_ctor_def_id(&self, struct_def_id: DefId) -> Option { self.dep_graph.read(DepNode::MetaData(struct_def_id)); - let cdata = self.get_crate_data(struct_def_id.krate); - decoder::get_struct_ctor_def_id(&cdata, struct_def_id.index) + self.get_crate_data(struct_def_id.krate).get_struct_ctor_def_id(struct_def_id.index) } fn struct_field_names(&self, def: DefId) -> Vec { self.dep_graph.read(DepNode::MetaData(def)); - let cdata = self.get_crate_data(def.krate); - decoder::get_struct_field_names(&cdata, def.index) + self.get_crate_data(def.krate).get_struct_field_names(def.index) } fn item_children(&self, def_id: DefId) -> Vec { self.dep_graph.read(DepNode::MetaData(def_id)); let mut result = vec![]; - let crate_data = self.get_crate_data(def_id.krate); let get_crate_data = &mut |cnum| self.get_crate_data(cnum); - decoder::each_child_of_item(&crate_data, def_id.index, get_crate_data, - &mut |def, name, vis| { - result.push(ChildItem { def: def, name: name, vis: vis }); - }); + self.get_crate_data(def_id.krate) + .each_child_of_item(def_id.index, get_crate_data, + &mut |def, name, vis| { + result.push(ChildItem { + def: def, + name: name, + vis: vis + }); + }); result } @@ -445,8 +408,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { debug!("maybe_get_item_ast({}): inlining item", tcx.item_path_str(def_id)); - let cdata = self.get_crate_data(def_id.krate); - let inlined = decoder::maybe_get_item_ast(&cdata, tcx, def_id.index); + let inlined = self.get_crate_data(def_id.krate).maybe_get_item_ast(tcx, def_id.index); let cache_inlined_item = |original_def_id, inlined_item_id, inlined_root_node_id| { let cache_entry = cstore::CachedInlinedItem { @@ -534,14 +496,12 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { fn maybe_get_item_mir<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> Option> { self.dep_graph.read(DepNode::MetaData(def)); - let cdata = self.get_crate_data(def.krate); - decoder::maybe_get_item_mir(&cdata, tcx, def.index) + self.get_crate_data(def.krate).maybe_get_item_mir(tcx, def.index) } fn is_item_mir_available(&self, def: DefId) -> bool { self.dep_graph.read(DepNode::MetaData(def)); - let cdata = self.get_crate_data(def.krate); - decoder::is_item_mir_available(&cdata, def.index) + self.get_crate_data(def.krate).is_item_mir_available(def.index) } fn crates(&self) -> Vec diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs index 44fdf29aa73c..4151f98b3dae 100644 --- a/src/librustc_metadata/cstore.rs +++ b/src/librustc_metadata/cstore.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![allow(non_camel_case_types)] - // The crate store - a central repo for information collected about external // crates and libraries @@ -17,7 +15,6 @@ pub use self::MetadataBlob::*; use common; use creader; -use decoder; use index; use loader; @@ -297,7 +294,6 @@ impl CStore { } impl CrateMetadata { - pub fn data<'a>(&'a self) -> &'a [u8] { self.data.as_slice() } pub fn name(&self) -> &str { &self.info.name } pub fn hash(&self) -> Svh { self.info.hash } pub fn disambiguator(&self) -> &str { &self.info.disambiguator } @@ -317,37 +313,41 @@ impl CrateMetadata { } pub fn is_staged_api(&self) -> bool { - let attrs = decoder::get_item_attrs(self, CRATE_DEF_INDEX); - attrs.iter().any(|attr| { + self.get_item_attrs(CRATE_DEF_INDEX).iter().any(|attr| { attr.name() == "stable" || attr.name() == "unstable" }) } pub fn is_allocator(&self) -> bool { - let attrs = decoder::get_item_attrs(self, CRATE_DEF_INDEX); + let attrs = self.get_item_attrs(CRATE_DEF_INDEX); attr::contains_name(&attrs, "allocator") } pub fn needs_allocator(&self) -> bool { - let attrs = decoder::get_item_attrs(self, CRATE_DEF_INDEX); + let attrs = self.get_item_attrs(CRATE_DEF_INDEX); attr::contains_name(&attrs, "needs_allocator") } pub fn is_panic_runtime(&self) -> bool { - let attrs = decoder::get_item_attrs(self, CRATE_DEF_INDEX); + let attrs = self.get_item_attrs(CRATE_DEF_INDEX); attr::contains_name(&attrs, "panic_runtime") } pub fn needs_panic_runtime(&self) -> bool { - let attrs = decoder::get_item_attrs(self, CRATE_DEF_INDEX); + let attrs = self.get_item_attrs(CRATE_DEF_INDEX); attr::contains_name(&attrs, "needs_panic_runtime") } pub fn is_compiler_builtins(&self) -> bool { - let attrs = decoder::get_crate_attributes(self.data()); + let attrs = self.get_item_attrs(CRATE_DEF_INDEX); attr::contains_name(&attrs, "compiler_builtins") } + pub fn is_no_builtins(&self) -> bool { + let attrs = self.get_item_attrs(CRATE_DEF_INDEX); + attr::contains_name(&attrs, "no_builtins") + } + pub fn panic_strategy(&self) -> PanicStrategy { self.info.panic_strategy.clone() } diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index c665a7be955d..05bd9e97234e 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -10,14 +10,11 @@ // Decoding metadata from a single crate's metadata -#![allow(non_camel_case_types)] - use astencode::decode_inlined_item; -use cstore::{self, CrateMetadata}; +use cstore::{CrateMetadata, MetadataBlob, NativeLibraryKind}; use common::*; use index; -use rustc::hir::def_id::CRATE_DEF_INDEX; use rustc::hir::svh::Svh; use rustc::hir::map as hir_map; use rustc::hir::map::{DefKey, DefPathData}; @@ -43,7 +40,6 @@ use std::rc::Rc; use std::str; use std::u32; -use rbml::reader; use rbml; use rustc_serialize::{Decodable, Decoder, SpecializedDecoder, opaque}; use syntax::attr; @@ -53,37 +49,36 @@ use syntax_pos::{self, Span, BytePos}; pub struct DecodeContext<'a, 'tcx: 'a> { pub opaque: opaque::Decoder<'a>, - pub tcx: Option>, - pub cdata: Option<&'a cstore::CrateMetadata>, + tcx: Option>, + cdata: Option<&'a CrateMetadata>, pub from_id_range: IdRange, pub to_id_range: IdRange, // Cache the last used filemap for translating spans as an optimization. last_filemap_index: usize, } -impl<'doc> rbml::Doc<'doc> { - pub fn decoder<'tcx>(self) -> DecodeContext<'doc, 'tcx> { +impl<'a, 'tcx> DecodeContext<'a, 'tcx> { + pub fn new(doc: rbml::Doc<'a>, cdata: Option<&'a CrateMetadata>) + -> DecodeContext<'a, 'tcx> { let id_range = IdRange { min: NodeId::from_u32(u32::MIN), max: NodeId::from_u32(u32::MAX) }; DecodeContext { - opaque: opaque::Decoder::new(self.data, self.start), - cdata: None, + opaque: opaque::Decoder::new(doc.data, doc.start), + cdata: cdata, tcx: None, from_id_range: id_range, to_id_range: id_range, last_filemap_index: 0 } } -} -impl<'a, 'tcx> DecodeContext<'a, 'tcx> { pub fn tcx(&self) -> TyCtxt<'a, 'tcx, 'tcx> { self.tcx.expect("missing TyCtxt in DecodeContext") } - pub fn cdata(&self) -> &'a cstore::CrateMetadata { + pub fn cdata(&self) -> &'a CrateMetadata { self.cdata.expect("missing CrateMetadata in DecodeContext") } @@ -91,6 +86,11 @@ impl<'a, 'tcx> DecodeContext<'a, 'tcx> { T::decode(self).unwrap() } + pub fn typed(mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Self { + self.tcx = Some(tcx); + self + } + /// Iterate over the indices of a sequence. /// This will work solely because of `serialize::opaque`'s /// simple encoding of `n: usize` followed by `n` elements. @@ -295,126 +295,86 @@ impl<'a, 'tcx> SpecializedDecoder> for DecodeContext<'a, 'tcx> } } -pub type Cmd<'a> = &'a CrateMetadata; +#[derive(Clone)] +pub struct CrateDep { + pub cnum: CrateNum, + pub name: String, + pub hash: Svh, + pub explicitly_linked: bool, +} -impl CrateMetadata { - fn get_item(&self, item_id: DefIndex) -> Option { - self.index.lookup_item(self.data(), item_id).map(|pos| { - rbml::Doc::at(self.data(), pos as usize) +impl<'a, 'tcx> MetadataBlob { + fn root(&self) -> rbml::Doc { + rbml::Doc::new(self.as_slice()) + } + + fn child_at(&'a self, pos: usize, tag: usize) -> DecodeContext<'a, 'tcx> { + DecodeContext::new(rbml::Doc::at(self.as_slice(), pos).child(tag), None) + } + + fn get(&'a self, tag: usize) -> DecodeContext<'a, 'tcx> { + DecodeContext::new(self.root().child(tag), None) + } + + pub fn load_index(&self) -> index::Index { + index::Index::from_rbml(self.root().child(root_tag::index)) + } + + pub fn crate_rustc_version(&self) -> Option { + self.root().maybe_child(root_tag::rustc_version).map(|s| { + str::from_utf8(&s.data[s.start..s.end]).unwrap().to_string() }) } - fn lookup_item(&self, item_id: DefIndex) -> rbml::Doc { - match self.get_item(item_id) { - None => bug!("lookup_item: id not found: {:?} in crate {:?} with number {}", - item_id, - self.name, - self.cnum), - Some(d) => d - } + // Go through each item in the metadata and create a map from that + // item's def-key to the item's DefIndex. + pub fn load_key_map(&self) -> FnvHashMap { + self.load_index().iter_enumerated(self.as_slice()).map(|(index, pos)| { + (self.child_at(pos as usize, item_tag::def_key).decode(), index) + }).collect() } - fn local_def_id(&self, index: DefIndex) -> DefId { - DefId { - krate: self.cnum, - index: index + pub fn get_crate_deps(&self) -> Vec { + let dcx = self.get(root_tag::crate_deps); + + dcx.seq().enumerate().map(|(crate_num, (name, hash, explicitly_linked))| { + CrateDep { + cnum: CrateNum::new(crate_num + 1), + name: name, + hash: hash, + explicitly_linked: explicitly_linked, + } + }).collect() + } + + pub fn get_crate_info(&self) -> CrateInfo { + self.get(root_tag::crate_info).decode() + } + + pub fn list_crate_metadata(&self, out: &mut io::Write) -> io::Result<()> { + write!(out, "=External Dependencies=\n")?; + for dep in &self.get_crate_deps() { + write!(out, "{} {}-{}\n", dep.cnum, dep.name, dep.hash)?; + } + write!(out, "\n")?; + Ok(()) + } + + pub fn get_imported_filemaps(&self) -> Vec { + self.get(root_tag::codemap).decode() + } + + pub fn each_exported_macro(&self, mut f: F) where + F: FnMut(ast::Name, Vec, Span, String) -> bool, + { + for (name, attrs, span, body) in self.get(root_tag::macro_defs).seq() { + if !f(name, attrs, span, body) { + break; + } } } } -pub fn load_index(data: &[u8]) -> index::Index { - index::Index::from_rbml(rbml::Doc::new(data).get(root_tag::index)) -} - -pub fn crate_rustc_version(data: &[u8]) -> Option { - let doc = rbml::Doc::new(data); - reader::maybe_get_doc(doc, root_tag::rustc_version).map(|s| { - str::from_utf8(&s.data[s.start..s.end]).unwrap().to_string() - }) -} - -// Go through each item in the metadata and create a map from that -// item's def-key to the item's DefIndex. -pub fn load_key_map(data: &[u8]) -> FnvHashMap { - load_index(data).iter_enumerated(data).map(|(index, pos)| { - // load def-key from item - let key = item_def_key(rbml::Doc::at(data, pos as usize)); - (key, index) - }).collect() -} - -fn item_family(item: rbml::Doc) -> Family { - item.get(item_tag::family).decoder().decode() -} - -fn item_visibility(item: rbml::Doc) -> ty::Visibility { - item.get(item_tag::visibility).decoder().decode() -} - -fn entry_data(doc: rbml::Doc, cdata: Cmd) -> EntryData { - let mut dcx = doc.get(item_tag::data).decoder(); - dcx.cdata = Some(cdata); - - dcx.decode() -} - -fn entry_typed_data<'a, 'tcx>(doc: rbml::Doc, tcx: TyCtxt<'a, 'tcx, 'tcx>, cdata: Cmd) - -> EntryTypedData<'tcx> { - let mut dcx = doc.get(item_tag::typed_data).decoder(); - dcx.cdata = Some(cdata); - dcx.tcx = Some(tcx); - - dcx.decode() -} - -fn item_parent_item(cdata: Cmd, d: rbml::Doc) -> Option { - item_def_key(d).parent.map(|index| cdata.local_def_id(index)) -} - -fn doc_type<'a, 'tcx>(doc: rbml::Doc, tcx: TyCtxt<'a, 'tcx, 'tcx>, cdata: Cmd) -> Ty<'tcx> { - maybe_doc_type(doc, tcx, cdata).expect("missing item_tag::ty") -} - -fn maybe_doc_type<'a, 'tcx>(doc: rbml::Doc, tcx: TyCtxt<'a, 'tcx, 'tcx>, cdata: Cmd) - -> Option> { - reader::maybe_get_doc(doc, item_tag::ty).map(|tp| { - let mut dcx = tp.decoder(); - dcx.tcx = Some(tcx); - dcx.cdata = Some(cdata); - dcx.decode() - }) -} - -fn item_name(item: rbml::Doc) -> ast::Name { - maybe_item_name(item).expect("no item in item_name") -} - -fn maybe_item_name(item: rbml::Doc) -> Option { - let name = match item_def_key(item).disambiguated_data.data { - DefPathData::TypeNs(name) | - DefPathData::ValueNs(name) | - DefPathData::Module(name) | - DefPathData::MacroDef(name) | - DefPathData::TypeParam(name) | - DefPathData::LifetimeDef(name) | - DefPathData::EnumVariant(name) | - DefPathData::Field(name) | - DefPathData::Binding(name) => Some(name), - - DefPathData::InlinedRoot(_) => bug!("unexpected DefPathData"), - - DefPathData::CrateRoot | - DefPathData::Misc | - DefPathData::Impl | - DefPathData::ClosureExpr | - DefPathData::StructCtor | - DefPathData::Initializer | - DefPathData::ImplTrait => None - }; - - name.map(|s| token::intern(&s)) -} - impl Family { fn to_def(&self, did: DefId) -> Option { Some(match *self { @@ -444,729 +404,698 @@ impl Family { } } -pub fn get_trait_def<'a, 'tcx>(cdata: Cmd, - item_id: DefIndex, - tcx: TyCtxt<'a, 'tcx, 'tcx>) -> ty::TraitDef<'tcx> -{ - let item_doc = cdata.lookup_item(item_id); - let generics = doc_generics(item_doc, tcx, cdata); +impl<'a, 'tcx> CrateMetadata { + fn maybe_get(&'a self, item: rbml::Doc<'a>, tag: usize) + -> Option> { + item.maybe_child(tag).map(|child| { + DecodeContext::new(child, Some(self)) + }) + } - let data = match entry_data(item_doc, cdata) { - EntryData::Trait(data) => data, - _ => bug!() - }; - let typed_data = match entry_typed_data(item_doc, tcx, cdata) { - EntryTypedData::Trait(data) => data, - _ => bug!() - }; + fn get(&'a self, item: rbml::Doc<'a>, tag: usize) -> DecodeContext<'a, 'tcx> { + match self.maybe_get(item, tag) { + Some(dcx) => dcx, + None => bug!("failed to find child with tag {}", tag) + } + } - ty::TraitDef::new(data.unsafety, data.paren_sugar, generics, typed_data.trait_ref, - def_path(cdata, item_id).unwrap().deterministic_hash(tcx))) -} + fn item_family(&self, item: rbml::Doc) -> Family { + self.get(item, item_tag::family).decode() + } -fn get_variant<'tcx>(cdata: Cmd, - item: rbml::Doc, - index: DefIndex) - -> (ty::VariantDefData<'tcx, 'tcx>, Option) { - let data = match entry_data(item, cdata) { - EntryData::Variant(data) => data, - _ => bug!() - }; + fn item_visibility(&self, item: rbml::Doc) -> ty::Visibility { + self.get(item, item_tag::visibility).decode() + } - let mut dcx = item.get(item_tag::children).decoder(); - dcx.cdata = Some(cdata); + fn item_def_key(&self, item: rbml::Doc) -> hir_map::DefKey { + self.get(item, item_tag::def_key).decode() + } - let fields = dcx.seq().map(|index| { - let f = cdata.lookup_item(index); - ty::FieldDefData::new(cdata.local_def_id(index), - item_name(f), - item_visibility(f)) - }).collect(); + fn item_name(&self, item: rbml::Doc) -> ast::Name { + self.maybe_item_name(item).expect("no item in item_name") + } - (ty::VariantDefData { - did: cdata.local_def_id(data.struct_ctor.unwrap_or(index)), - name: item_name(item), - fields: fields, - disr_val: ConstInt::Infer(data.disr), - kind: data.kind, - }, data.struct_ctor) -} + fn maybe_item_name(&self, item: rbml::Doc) -> Option { + let name = match self.item_def_key(item).disambiguated_data.data { + DefPathData::TypeNs(name) | + DefPathData::ValueNs(name) | + DefPathData::Module(name) | + DefPathData::MacroDef(name) | + DefPathData::TypeParam(name) | + DefPathData::LifetimeDef(name) | + DefPathData::EnumVariant(name) | + DefPathData::Field(name) | + DefPathData::Binding(name) => Some(name), -pub fn get_adt_def<'a, 'tcx>(cdata: Cmd, - item_id: DefIndex, - tcx: TyCtxt<'a, 'tcx, 'tcx>) - -> ty::AdtDefMaster<'tcx> -{ - let doc = cdata.lookup_item(item_id); - let did = cdata.local_def_id(item_id); - let mut ctor_index = None; - let family = item_family(doc); - let variants = if family == Family::Enum { - let mut dcx = doc.get(item_tag::children).decoder(); - dcx.cdata = Some(cdata); + DefPathData::InlinedRoot(_) => bug!("unexpected DefPathData"), - dcx.seq().map(|index| { - let (variant, struct_ctor) = get_variant(cdata, cdata.lookup_item(index), index); - assert_eq!(struct_ctor, None); - variant + DefPathData::CrateRoot | + DefPathData::Misc | + DefPathData::Impl | + DefPathData::ClosureExpr | + DefPathData::StructCtor | + DefPathData::Initializer | + DefPathData::ImplTrait => None + }; + + name.map(|s| token::intern(&s)) + } + + fn maybe_entry(&self, item_id: DefIndex) -> Option { + self.index.lookup_item(self.data.as_slice(), item_id).map(|pos| { + rbml::Doc::at(self.data.as_slice(), pos as usize) + }) + } + + fn entry(&self, item_id: DefIndex) -> rbml::Doc { + match self.maybe_entry(item_id) { + None => bug!("entry: id not found: {:?} in crate {:?} with number {}", + item_id, + self.name, + self.cnum), + Some(d) => d + } + } + + fn local_def_id(&self, index: DefIndex) -> DefId { + DefId { + krate: self.cnum, + index: index + } + } + + fn entry_data(&self, doc: rbml::Doc) -> EntryData { + self.get(doc, item_tag::data).decode() + } + + fn entry_typed_data(&self, doc: rbml::Doc, tcx: TyCtxt<'a, 'tcx, 'tcx>) + -> EntryTypedData<'tcx> { + self.get(doc, item_tag::typed_data).typed(tcx).decode() + } + + fn item_parent_item(&self, d: rbml::Doc) -> Option { + self.item_def_key(d).parent.map(|index| self.local_def_id(index)) + } + + fn doc_type(&self, doc: rbml::Doc, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Ty<'tcx> { + self.maybe_doc_type(doc, tcx).expect("missing item_tag::ty") + } + + fn maybe_doc_type(&self, doc: rbml::Doc, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Option> { + self.maybe_get(doc, item_tag::ty).map(|dcx| dcx.typed(tcx).decode()) + } + + pub fn get_trait_def(&self, + item_id: DefIndex, + tcx: TyCtxt<'a, 'tcx, 'tcx>) -> ty::TraitDef<'tcx> { + let item_doc = self.entry(item_id); + let generics = self.doc_generics(item_doc, tcx); + + let data = match self.entry_data(item_doc) { + EntryData::Trait(data) => data, + _ => bug!() + }; + let typed_data = match self.entry_typed_data(item_doc, tcx) { + EntryTypedData::Trait(data) => data, + _ => bug!() + }; + + ty::TraitDef::new(data.unsafety, data.paren_sugar, generics, typed_data.trait_ref, + self.def_path(item_id).unwrap().deterministic_hash(tcx))) + } + + fn get_variant(&self, item: rbml::Doc, index: DefIndex) + -> (ty::VariantDefData<'tcx, 'tcx>, Option) { + let data = match self.entry_data(item) { + EntryData::Variant(data) => data, + _ => bug!() + }; + + let fields = self.get(item, item_tag::children).seq().map(|index| { + let f = self.entry(index); + ty::FieldDefData::new(self.local_def_id(index), + self.item_name(f), + self.item_visibility(f)) + }).collect(); + + (ty::VariantDefData { + did: self.local_def_id(data.struct_ctor.unwrap_or(index)), + name: self.item_name(item), + fields: fields, + disr_val: ConstInt::Infer(data.disr), + kind: data.kind, + }, data.struct_ctor) + } + + pub fn get_adt_def(&self, item_id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>) + -> ty::AdtDefMaster<'tcx> { + let doc = self.entry(item_id); + let did = self.local_def_id(item_id); + let mut ctor_index = None; + let family = self.item_family(doc); + let variants = if family == Family::Enum { + self.get(doc, item_tag::children).seq().map(|index| { + let (variant, struct_ctor) = self.get_variant(self.entry(index), index); + assert_eq!(struct_ctor, None); + variant + }).collect() + } else{ + let (variant, struct_ctor) = self.get_variant(doc, item_id); + ctor_index = struct_ctor; + vec![variant] + }; + let kind = match family { + Family::Enum => ty::AdtKind::Enum, + Family::Struct => ty::AdtKind::Struct, + Family::Union => ty::AdtKind::Union, + _ => bug!("get_adt_def called on a non-ADT {:?} - {:?}", + family, did) + }; + + let adt = tcx.intern_adt_def(did, kind, variants); + if let Some(ctor_index) = ctor_index { + // Make adt definition available through constructor id as well. + tcx.insert_adt_def(self.local_def_id(ctor_index), adt); + } + + // this needs to be done *after* the variant is interned, + // to support recursive structures + for variant in &adt.variants { + for field in &variant.fields { + debug!("evaluating the type of {:?}::{:?}", variant.name, field.name); + let ty = self.get_type(field.did.index, tcx); + field.fulfill_ty(ty); + debug!("evaluating the type of {:?}::{:?}: {:?}", + variant.name, field.name, ty); + } + } + + adt + } + + pub fn get_predicates(&self, item_id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>) + -> ty::GenericPredicates<'tcx> { + self.doc_predicates(self.entry(item_id), tcx, item_tag::predicates) + } + + pub fn get_super_predicates(&self, item_id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>) + -> ty::GenericPredicates<'tcx> { + self.doc_predicates(self.entry(item_id), tcx, item_tag::super_predicates) + } + + pub fn get_generics(&self, item_id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>) + -> &'tcx ty::Generics<'tcx> { + self.doc_generics(self.entry(item_id), tcx) + } + + pub fn get_type(&self, id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Ty<'tcx> { + self.doc_type(self.entry(id), tcx) + } + + pub fn get_stability(&self, id: DefIndex) -> Option { + self.maybe_get(self.entry(id), item_tag::stability).map(|mut dcx| { + dcx.decode() + }) + } + + pub fn get_deprecation(&self, id: DefIndex) -> Option { + self.maybe_get(self.entry(id), item_tag::deprecation).map(|mut dcx| { + dcx.decode() + }) + } + + pub fn get_visibility(&self, id: DefIndex) -> ty::Visibility { + self.item_visibility(self.entry(id)) + } + + fn get_impl_data(&self, id: DefIndex) -> ImplData { + match self.entry_data(self.entry(id)) { + EntryData::Impl(data) => data, + _ => bug!() + } + } + + pub fn get_parent_impl(&self, id: DefIndex) -> Option { + self.get_impl_data(id).parent_impl + } + + pub fn get_impl_polarity(&self, id: DefIndex) -> hir::ImplPolarity { + self.get_impl_data(id).polarity + } + + pub fn get_custom_coerce_unsized_kind(&self, id: DefIndex) + -> Option { + self.get_impl_data(id).coerce_unsized_kind + } + + pub fn get_impl_trait(&self, + id: DefIndex, + tcx: TyCtxt<'a, 'tcx, 'tcx>) + -> Option> { + match self.entry_typed_data(self.entry(id), tcx) { + EntryTypedData::Impl(data) => data.trait_ref, + _ => bug!() + } + } + + /// Iterates over the language items in the given crate. + pub fn get_lang_items(&self) -> Vec<(DefIndex, usize)> { + self.get(self.data.root(), root_tag::lang_items).decode() + } + + /// Iterates over each child of the given item. + pub fn each_child_of_item(&self, id: DefIndex, + mut get_crate_data: &mut G, + mut callback: &mut F) + where F: FnMut(Def, ast::Name, ty::Visibility), + G: FnMut(CrateNum) -> Rc, + { + // Find the item. + let item_doc = match self.maybe_entry(id) { + None => return, + Some(item_doc) => item_doc, + }; + + let dcx = match self.maybe_get(item_doc, item_tag::children) { + Some(dcx) => dcx, + None => return + }; + + // Iterate over all children. + for child_index in dcx.seq::() { + // Get the item. + if let Some(child) = self.maybe_entry(child_index) { + // Hand off the item to the callback. + let family = self.item_family(child); + if let Family::ForeignMod = family { + self.each_child_of_item(child_index, get_crate_data, callback); + } else if let Some(def) = family.to_def(self.local_def_id(child_index)) { + callback(def, self.item_name(child), self.item_visibility(child)); + } + } + } + + let reexports = match self.entry_data(item_doc) { + EntryData::Mod(data) => data.reexports, + _ => return + }; + for exp in reexports { + // This reexport may be in yet another crate. + let crate_data = if exp.def_id.krate == self.cnum { + None + } else { + Some(get_crate_data(exp.def_id.krate)) + }; + let crate_data = match crate_data { + Some(ref cdata) => &**cdata, + None => self + }; + + // Get the item. + if let Some(child) = crate_data.maybe_entry(exp.def_id.index) { + // Hand off the item to the callback. + if let Some(def) = self.item_family(child).to_def(exp.def_id) { + // These items have a public visibility because they're part of + // a public re-export. + callback(def, exp.name, ty::Visibility::Public); + } + } + } + } + + pub fn maybe_get_item_name(&self, id: DefIndex) -> Option { + self.maybe_item_name(self.entry(id)) + } + + pub fn maybe_get_item_ast(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefIndex) + -> Option<&'tcx InlinedItem> { + debug!("Looking up item: {:?}", id); + let item_doc = self.entry(id); + let item_did = self.local_def_id(id); + let parent_def_id = self.local_def_id(self.def_key(id).parent.unwrap()); + let mut parent_def_path = self.def_path(id).unwrap(); + parent_def_path.data.pop(); + item_doc.maybe_child(item_tag::ast).map(|ast_doc| { + decode_inlined_item(self, tcx, parent_def_path, parent_def_id, ast_doc, item_did) + }) + } + + pub fn is_item_mir_available(&self, id: DefIndex) -> bool { + if let Some(item_doc) = self.maybe_entry(id) { + return item_doc.maybe_child(item_tag::mir).is_some(); + } + + false + } + + pub fn maybe_get_item_mir(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefIndex) + -> Option> { + self.maybe_get(self.entry(id), item_tag::mir).map(|dcx| { + dcx.typed(tcx).decode() + }) + } + + pub fn get_impl_or_trait_item(&self, id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>) + -> Option> { + let item_doc = self.entry(id); + let family = self.item_family(item_doc); + + match family { + Family::AssociatedConst | + Family::Method | + Family::AssociatedType => {} + + _ => return None + } + + let def_id = self.local_def_id(id); + + let container_id = self.item_parent_item(item_doc).unwrap(); + let container = match self.item_family(self.entry(container_id.index)) { + Family::Trait => TraitContainer(container_id), + _ => ImplContainer(container_id), + }; + + let name = self.item_name(item_doc); + let vis = self.item_visibility(item_doc); + + let (defaultness, has_body) = match self.entry_data(item_doc) { + EntryData::TraitAssociated(data) => { + (hir::Defaultness::Default, data.has_default) + } + EntryData::ImplAssociated(data) => { + (data.defaultness, true) + } + _ => bug!() + }; + + Some(match family { + Family::AssociatedConst => { + ty::ConstTraitItem(Rc::new(ty::AssociatedConst { + name: name, + ty: self.doc_type(item_doc, tcx), + vis: vis, + defaultness: defaultness, + def_id: def_id, + container: container, + has_value: has_body, + })) + } + Family::Method => { + let generics = self.doc_generics(item_doc, tcx); + let predicates = self.doc_predicates(item_doc, tcx, item_tag::predicates); + let ity = tcx.lookup_item_type(def_id).ty; + let fty = match ity.sty { + ty::TyFnDef(.., fty) => fty, + _ => bug!( + "the type {:?} of the method {:?} is not a function?", + ity, name) + }; + + let explicit_self = match self.entry_typed_data(item_doc, tcx) { + EntryTypedData::Method(data) => data.explicit_self, + _ => bug!() + }; + ty::MethodTraitItem(Rc::new(ty::Method { + name: name, + generics: generics, + predicates: predicates, + fty: fty, + explicit_self: explicit_self, + vis: vis, + defaultness: defaultness, + has_body: has_body, + def_id: def_id, + container: container, + })) + } + Family::AssociatedType => { + ty::TypeTraitItem(Rc::new(ty::AssociatedType { + name: name, + ty: self.maybe_doc_type(item_doc, tcx), + vis: vis, + defaultness: defaultness, + def_id: def_id, + container: container, + })) + } + _ => bug!() + }) + } + + pub fn get_item_variances(&self, id: DefIndex) -> Vec { + let item_doc = self.entry(id); + self.get(item_doc, item_tag::variances).decode() + } + + pub fn get_struct_ctor_def_id(&self, node_id: DefIndex) -> Option { + let data = match self.entry_data(self.entry(node_id)) { + EntryData::Variant(data) => data, + _ => bug!() + }; + + data.struct_ctor.map(|index| self.local_def_id(index)) + } + + pub fn get_item_attrs(&self, node_id: DefIndex) -> Vec { + // The attributes for a tuple struct are attached to the definition, not the ctor; + // we assume that someone passing in a tuple struct ctor is actually wanting to + // look at the definition + let mut item = self.entry(node_id); + let def_key = self.item_def_key(item); + if def_key.disambiguated_data.data == DefPathData::StructCtor { + item = self.entry(def_key.parent.unwrap()); + } + self.get_attributes(item) + } + + pub fn get_struct_field_names(&self, id: DefIndex) -> Vec { + self.get(self.entry(id), item_tag::children).seq().map(|index| { + self.item_name(self.entry(index)) }).collect() - } else{ - let (variant, struct_ctor) = get_variant(cdata, doc, item_id); - ctor_index = struct_ctor; - vec![variant] - }; - let kind = match family { - Family::Enum => ty::AdtKind::Enum, - Family::Struct => ty::AdtKind::Struct, - Family::Union => ty::AdtKind::Union, - _ => bug!("get_adt_def called on a non-ADT {:?} - {:?}", - family, did) - }; - - let adt = tcx.intern_adt_def(did, kind, variants); - if let Some(ctor_index) = ctor_index { - // Make adt definition available through constructor id as well. - tcx.insert_adt_def(cdata.local_def_id(ctor_index), adt); } - // this needs to be done *after* the variant is interned, - // to support recursive structures - for variant in &adt.variants { - for field in &variant.fields { - debug!("evaluating the type of {:?}::{:?}", variant.name, field.name); - let ty = get_type(cdata, field.did.index, tcx); - field.fulfill_ty(ty); - debug!("evaluating the type of {:?}::{:?}: {:?}", - variant.name, field.name, ty); - } - } + fn get_attributes(&self, md: rbml::Doc) -> Vec { + self.maybe_get(md, item_tag::attributes).map_or(vec![], |mut dcx| { + let mut attrs = dcx.decode::>(); - adt -} - -pub fn get_predicates<'a, 'tcx>(cdata: Cmd, - item_id: DefIndex, - tcx: TyCtxt<'a, 'tcx, 'tcx>) - -> ty::GenericPredicates<'tcx> -{ - let item_doc = cdata.lookup_item(item_id); - doc_predicates(item_doc, tcx, cdata, item_tag::predicates) -} - -pub fn get_super_predicates<'a, 'tcx>(cdata: Cmd, - item_id: DefIndex, - tcx: TyCtxt<'a, 'tcx, 'tcx>) - -> ty::GenericPredicates<'tcx> -{ - let item_doc = cdata.lookup_item(item_id); - doc_predicates(item_doc, tcx, cdata, item_tag::super_predicates) -} - -pub fn get_generics<'a, 'tcx>(cdata: Cmd, - item_id: DefIndex, - tcx: TyCtxt<'a, 'tcx, 'tcx>) - -> &'tcx ty::Generics<'tcx> -{ - let item_doc = cdata.lookup_item(item_id); - doc_generics(item_doc, tcx, cdata) -} - -pub fn get_type<'a, 'tcx>(cdata: Cmd, id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>) - -> Ty<'tcx> -{ - let item_doc = cdata.lookup_item(id); - doc_type(item_doc, tcx, cdata) -} - -pub fn get_stability(cdata: Cmd, id: DefIndex) -> Option { - let item = cdata.lookup_item(id); - reader::maybe_get_doc(item, item_tag::stability).map(|doc| { - doc.decoder().decode() - }) -} - -pub fn get_deprecation(cdata: Cmd, id: DefIndex) -> Option { - let item = cdata.lookup_item(id); - reader::maybe_get_doc(item, item_tag::deprecation).map(|doc| { - doc.decoder().decode() - }) -} - -pub fn get_visibility(cdata: Cmd, id: DefIndex) -> ty::Visibility { - item_visibility(cdata.lookup_item(id)) -} - -fn get_impl_data(cdata: Cmd, id: DefIndex) -> ImplData { - match entry_data(cdata.lookup_item(id), cdata) { - EntryData::Impl(data) => data, - _ => bug!() - } -} - -pub fn get_parent_impl(cdata: Cmd, id: DefIndex) -> Option { - get_impl_data(cdata, id).parent_impl -} - -pub fn get_impl_polarity(cdata: Cmd, id: DefIndex) -> hir::ImplPolarity { - get_impl_data(cdata, id).polarity -} - -pub fn get_custom_coerce_unsized_kind( - cdata: Cmd, - id: DefIndex) - -> Option -{ - get_impl_data(cdata, id).coerce_unsized_kind -} - -pub fn get_impl_trait<'a, 'tcx>(cdata: Cmd, - id: DefIndex, - tcx: TyCtxt<'a, 'tcx, 'tcx>) - -> Option> -{ - match entry_typed_data(cdata.lookup_item(id), tcx, cdata) { - EntryTypedData::Impl(data) => data.trait_ref, - _ => bug!() - } -} - -/// Iterates over the language items in the given crate. -pub fn get_lang_items(cdata: Cmd) -> Vec<(DefIndex, usize)> { - rbml::Doc::new(cdata.data()).get(root_tag::lang_items).decoder().decode() -} - - -/// Iterates over each child of the given item. -pub fn each_child_of_item(cdata: Cmd, id: DefIndex, - mut get_crate_data: &mut G, - mut callback: &mut F) - where F: FnMut(Def, ast::Name, ty::Visibility), - G: FnMut(CrateNum) -> Rc, -{ - // Find the item. - let item_doc = match cdata.get_item(id) { - None => return, - Some(item_doc) => item_doc, - }; - - let mut dcx = match reader::maybe_get_doc(item_doc, item_tag::children) { - Some(doc) => doc.decoder(), - None => return - }; - dcx.cdata = Some(cdata); - - // Iterate over all children. - for child_index in dcx.seq::() { - // Get the item. - if let Some(child) = cdata.get_item(child_index) { - // Hand off the item to the callback. - let family = item_family(child); - if let Family::ForeignMod = family { - each_child_of_item(cdata, child_index, get_crate_data, callback); - } else if let Some(def) = family.to_def(cdata.local_def_id(child_index)) { - callback(def, item_name(child), item_visibility(child)); + // Need new unique IDs: old thread-local IDs won't map to new threads. + for attr in attrs.iter_mut() { + attr.node.id = attr::mk_attr_id(); } - } + + attrs + }) } - let reexports = match entry_data(item_doc, cdata) { - EntryData::Mod(data) => data.reexports, - _ => return - }; - for exp in reexports { - // This reexport may be in yet another crate. - let crate_data = if exp.def_id.krate == cdata.cnum { - None - } else { - Some(get_crate_data(exp.def_id.krate)) - }; - let crate_data = match crate_data { - Some(ref cdata) => &**cdata, - None => cdata - }; - - // Get the item. - if let Some(child) = crate_data.get_item(exp.def_id.index) { - // Hand off the item to the callback. - if let Some(def) = item_family(child).to_def(exp.def_id) { - // These items have a public visibility because they're part of - // a public re-export. - callback(def, exp.name, ty::Visibility::Public); - } - } - } -} - -pub fn maybe_get_item_name(cdata: Cmd, id: DefIndex) -> Option { - maybe_item_name(cdata.lookup_item(id)) -} - -pub fn maybe_get_item_ast<'a, 'tcx>(cdata: Cmd, tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefIndex) - -> Option<&'tcx InlinedItem> { - debug!("Looking up item: {:?}", id); - let item_doc = cdata.lookup_item(id); - let item_did = cdata.local_def_id(id); - let parent_def_id = cdata.local_def_id(def_key(cdata, id).parent.unwrap()); - let mut parent_def_path = def_path(cdata, id).unwrap(); - parent_def_path.data.pop(); - reader::maybe_get_doc(item_doc, item_tag::ast).map(|ast_doc| { - decode_inlined_item(cdata, tcx, parent_def_path, parent_def_id, ast_doc, item_did) - }) -} - -pub fn is_item_mir_available<'tcx>(cdata: Cmd, id: DefIndex) -> bool { - if let Some(item_doc) = cdata.get_item(id) { - return reader::maybe_get_doc(item_doc, item_tag::mir as usize).is_some(); - } - - false -} - -pub fn maybe_get_item_mir<'a, 'tcx>(cdata: Cmd, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - id: DefIndex) - -> Option> { - let item_doc = cdata.lookup_item(id); - - reader::maybe_get_doc(item_doc, item_tag::mir).map(|mir_doc| { - let mut dcx = mir_doc.decoder(); - dcx.tcx = Some(tcx); - dcx.cdata = Some(cdata); - dcx.decode() - }) -} - -pub fn get_impl_or_trait_item<'a, 'tcx>(cdata: Cmd, id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>) - -> Option> { - let item_doc = cdata.lookup_item(id); - let family = item_family(item_doc); - - match family { - Family::AssociatedConst | - Family::Method | - Family::AssociatedType => {} - - _ => return None - } - - let def_id = cdata.local_def_id(id); - - let container_id = item_parent_item(cdata, item_doc).unwrap(); - let container = match item_family(cdata.lookup_item(container_id.index)) { - Family::Trait => TraitContainer(container_id), - _ => ImplContainer(container_id), - }; - - let name = item_name(item_doc); - let vis = item_visibility(item_doc); - - let (defaultness, has_body) = match entry_data(item_doc, cdata) { - EntryData::TraitAssociated(data) => { - (hir::Defaultness::Default, data.has_default) - } - EntryData::ImplAssociated(data) => { - (data.defaultness, true) - } - _ => bug!() - }; - - Some(match family { - Family::AssociatedConst => { - let ty = doc_type(item_doc, tcx, cdata); - ty::ConstTraitItem(Rc::new(ty::AssociatedConst { - name: name, - ty: ty, - vis: vis, - defaultness: defaultness, - def_id: def_id, - container: container, - has_value: has_body, - })) - } - Family::Method => { - let generics = doc_generics(item_doc, tcx, cdata); - let predicates = doc_predicates(item_doc, tcx, cdata, item_tag::predicates); - let ity = tcx.lookup_item_type(def_id).ty; - let fty = match ity.sty { - ty::TyFnDef(.., fty) => fty, - _ => bug!( - "the type {:?} of the method {:?} is not a function?", - ity, name) - }; - - let explicit_self = match entry_typed_data(item_doc, tcx, cdata) { - EntryTypedData::Method(data) => data.explicit_self, - _ => bug!() - }; - ty::MethodTraitItem(Rc::new(ty::Method { - name: name, - generics: generics, - predicates: predicates, - fty: fty, - explicit_self: explicit_self, - vis: vis, - defaultness: defaultness, - has_body: has_body, - def_id: def_id, - container: container, - })) - } - Family::AssociatedType => { - let ty = maybe_doc_type(item_doc, tcx, cdata); - ty::TypeTraitItem(Rc::new(ty::AssociatedType { - name: name, - ty: ty, - vis: vis, - defaultness: defaultness, - def_id: def_id, - container: container, - })) - } - _ => bug!() - }) -} - -pub fn get_item_variances(cdata: Cmd, id: DefIndex) -> Vec { - let item_doc = cdata.lookup_item(id); - item_doc.get(item_tag::variances).decoder().decode() -} - -pub fn get_struct_ctor_def_id(cdata: Cmd, node_id: DefIndex) -> Option -{ - let data = match entry_data(cdata.lookup_item(node_id), cdata) { - EntryData::Variant(data) => data, - _ => bug!() - }; - - data.struct_ctor.map(|index| cdata.local_def_id(index)) -} - -pub fn get_item_attrs(cdata: Cmd, - node_id: DefIndex) - -> Vec { - // The attributes for a tuple struct are attached to the definition, not the ctor; - // we assume that someone passing in a tuple struct ctor is actually wanting to - // look at the definition - let mut item = cdata.lookup_item(node_id); - let def_key = item_def_key(item); - if def_key.disambiguated_data.data == DefPathData::StructCtor { - item = cdata.lookup_item(def_key.parent.unwrap()); - } - get_attributes(item) -} - -pub fn get_struct_field_names(cdata: Cmd, id: DefIndex) -> Vec { - let mut dcx = cdata.lookup_item(id).get(item_tag::children).decoder(); - dcx.cdata = Some(cdata); - - dcx.seq().map(|index| item_name(cdata.lookup_item(index))).collect() -} - -fn get_attributes(md: rbml::Doc) -> Vec { - reader::maybe_get_doc(md, item_tag::attributes).map_or(vec![], |attrs_doc| { - let mut attrs = attrs_doc.decoder().decode::>(); - - // Need new unique IDs: old thread-local IDs won't map to new threads. - for attr in attrs.iter_mut() { - attr.node.id = attr::mk_attr_id(); - } - - attrs - }) -} - -#[derive(Clone)] -pub struct CrateDep { - pub cnum: CrateNum, - pub name: String, - pub hash: Svh, - pub explicitly_linked: bool, -} - -pub fn get_crate_deps(data: &[u8]) -> Vec { - let dcx = rbml::Doc::new(data).get(root_tag::crate_deps).decoder(); - - dcx.seq().enumerate().map(|(crate_num, (name, hash, explicitly_linked))| { - CrateDep { - cnum: CrateNum::new(crate_num + 1), - name: name, - hash: hash, - explicitly_linked: explicitly_linked, - } - }).collect() -} - -fn list_crate_deps(data: &[u8], out: &mut io::Write) -> io::Result<()> { - write!(out, "=External Dependencies=\n")?; - for dep in &get_crate_deps(data) { - write!(out, "{} {}-{}\n", dep.cnum, dep.name, dep.hash)?; - } - write!(out, "\n")?; - Ok(()) -} - -pub fn get_crate_info(data: &[u8]) -> CrateInfo { - rbml::Doc::new(data).get(root_tag::crate_info).decoder().decode() -} - -pub fn list_crate_metadata(bytes: &[u8], out: &mut io::Write) -> io::Result<()> { - list_crate_deps(bytes, out) -} - -// Translate a DefId from the current compilation environment to a DefId -// for an external crate. -fn reverse_translate_def_id(cdata: Cmd, did: DefId) -> Option { - for (local, &global) in cdata.cnum_map.borrow().iter_enumerated() { - if global == did.krate { - return Some(DefId { krate: local, index: did.index }); - } - } - - None -} - -pub fn each_inherent_implementation_for_type(cdata: Cmd, - id: DefIndex, - mut callback: F) - where F: FnMut(DefId), -{ - let item_doc = cdata.lookup_item(id); - let mut dcx = item_doc.get(item_tag::inherent_impls).decoder(); - dcx.cdata = Some(cdata); - - for impl_def_id in dcx.seq() { - callback(impl_def_id); - } -} - -pub fn each_implementation_for_trait(cdata: Cmd, - filter: Option, - mut callback: F) where - F: FnMut(DefId), -{ - // Do a reverse lookup beforehand to avoid touching the crate_num - // hash map in the loop below. - let filter = match filter.map(|def_id| reverse_translate_def_id(cdata, def_id)) { - Some(Some(def_id)) => Some(def_id), - Some(None) => return, - None => None - }; - - // FIXME(eddyb) Make this O(1) instead of O(n). - for trait_doc in rbml::Doc::new(cdata.data()).get(root_tag::impls).children() { - let mut dcx = trait_doc.decoder(); - dcx.cdata = Some(cdata); - - let (krate, index) = dcx.decode(); - if let Some(local_did) = filter { - if (local_did.krate.as_u32(), local_did.index) != (krate, index) { - continue; + // Translate a DefId from the current compilation environment to a DefId + // for an external crate. + fn reverse_translate_def_id(&self, did: DefId) -> Option { + for (local, &global) in self.cnum_map.borrow().iter_enumerated() { + if global == did.krate { + return Some(DefId { krate: local, index: did.index }); } } - for impl_def_id in dcx.seq() { + None + } + + pub fn each_inherent_implementation_for_type(&self, id: DefIndex, mut callback: F) + where F: FnMut(DefId), + { + for impl_def_id in self.get(self.entry(id), item_tag::inherent_impls).seq() { callback(impl_def_id); } } -} -pub fn get_trait_of_item(cdata: Cmd, id: DefIndex) -> Option { - let item_doc = cdata.lookup_item(id); - let parent_item_id = match item_parent_item(cdata, item_doc) { - None => return None, - Some(item_id) => item_id, - }; - match item_family(cdata.lookup_item(parent_item_id.index)) { - Family::Trait => Some(parent_item_id), - _ => None - } -} + pub fn each_implementation_for_trait(&self, + filter: Option, + mut callback: F) where + F: FnMut(DefId), + { + // Do a reverse lookup beforehand to avoid touching the crate_num + // hash map in the loop below. + let filter = match filter.map(|def_id| self.reverse_translate_def_id(def_id)) { + Some(Some(def_id)) => Some(def_id), + Some(None) => return, + None => None + }; + // FIXME(eddyb) Make this O(1) instead of O(n). + for trait_doc in self.data.root().children_of(root_tag::impls) { + let mut dcx = DecodeContext::new(trait_doc, Some(self)); -pub fn get_native_libraries(cdata: Cmd) - -> Vec<(cstore::NativeLibraryKind, String)> { - rbml::Doc::new(cdata.data()).get(root_tag::native_libraries).decoder().decode() -} - -pub fn each_exported_macro(data: &[u8], mut f: F) where - F: FnMut(ast::Name, Vec, Span, String) -> bool, -{ - let dcx = rbml::Doc::new(data).get(root_tag::macro_defs).decoder(); - for (name, attrs, span, body) in dcx.seq() { - if !f(name, attrs, span, body) { - break; - } - } -} - -pub fn get_dylib_dependency_formats(cdata: Cmd) - -> Vec<(CrateNum, LinkagePreference)> -{ - let dcx = rbml::Doc::new(cdata.data()).get(root_tag::dylib_dependency_formats).decoder(); - - dcx.seq::>().enumerate().flat_map(|(i, link)| { - let cnum = CrateNum::new(i + 1); - link.map(|link| (cdata.cnum_map.borrow()[cnum], link)) - }).collect() -} - -pub fn get_missing_lang_items(cdata: Cmd) -> Vec { - rbml::Doc::new(cdata.data()).get(root_tag::lang_items_missing).decoder().decode() -} - -pub fn get_fn_arg_names(cdata: Cmd, id: DefIndex) -> Vec { - let method_doc = cdata.lookup_item(id); - match reader::maybe_get_doc(method_doc, item_tag::fn_arg_names) { - Some(args_doc) => args_doc.decoder().decode(), - None => vec![], - } -} - -pub fn get_reachable_ids(cdata: Cmd) -> Vec { - let dcx = rbml::Doc::new(cdata.data()).get(root_tag::reachable_ids).decoder(); - - dcx.seq().map(|index| cdata.local_def_id(index)).collect() -} - -pub fn is_const_fn(cdata: Cmd, id: DefIndex) -> bool { - let constness = match entry_data(cdata.lookup_item(id), cdata) { - EntryData::ImplAssociated(data) => data.constness, - EntryData::Fn(data) => data.constness, - _ => hir::Constness::NotConst - }; - constness == hir::Constness::Const -} - -pub fn is_extern_item<'a, 'tcx>(cdata: Cmd, - id: DefIndex, - tcx: TyCtxt<'a, 'tcx, 'tcx>) - -> bool { - let item_doc = match cdata.get_item(id) { - Some(doc) => doc, - None => return false, - }; - let applicable = match item_family(item_doc) { - Family::ImmStatic | - Family::MutStatic | - Family::ForeignImmStatic | - Family::ForeignMutStatic => true, - - Family::Fn | Family::ForeignFn => { - get_generics(cdata, id, tcx).types.is_empty() - } - - _ => false, - }; - - if applicable { - attr::contains_extern_indicator(tcx.sess.diagnostic(), - &get_attributes(item_doc)) - } else { - false - } -} - -pub fn is_foreign_item(cdata: Cmd, id: DefIndex) -> bool { - match item_family(cdata.lookup_item(id)) { - Family::ForeignImmStatic | - Family::ForeignMutStatic | - Family::ForeignFn => true, - _ => false - } -} - -fn doc_generics<'a, 'tcx>(base_doc: rbml::Doc, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - cdata: Cmd) - -> &'tcx ty::Generics<'tcx> -{ - let mut dcx = base_doc.get(item_tag::generics).decoder(); - dcx.tcx = Some(tcx); - dcx.cdata = Some(cdata); - tcx.alloc_generics(dcx.decode()) -} - -fn doc_predicates<'a, 'tcx>(base_doc: rbml::Doc, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - cdata: Cmd, - tag: usize) - -> ty::GenericPredicates<'tcx> -{ - let mut dcx = base_doc.get(tag).decoder(); - dcx.cdata = Some(cdata); - dcx.tcx = Some(tcx); - - ty::GenericPredicates { - parent: dcx.decode(), - predicates: (0..dcx.decode::()).map(|_| { - // Handle shorthands first, if we have an usize > 0x80. - if dcx.opaque.data[dcx.opaque.position()] & 0x80 != 0 { - let pos = dcx.decode::(); - assert!(pos >= SHORTHAND_OFFSET); - let pos = pos - SHORTHAND_OFFSET; - - let mut dcx = rbml::Doc { - data: cdata.data(), - start: pos, - end: cdata.data().len(), - }.decoder(); - dcx.tcx = Some(tcx); - dcx.cdata = Some(cdata); - dcx.decode() - } else { - dcx.decode() + let (krate, index) = dcx.decode(); + if let Some(local_did) = filter { + if (local_did.krate.as_u32(), local_did.index) != (krate, index) { + continue; + } } + + for impl_def_id in dcx.seq() { + callback(impl_def_id); + } + } + } + + pub fn get_trait_of_item(&self, id: DefIndex) -> Option { + let item_doc = self.entry(id); + let parent_item_id = match self.item_parent_item(item_doc) { + None => return None, + Some(item_id) => item_id, + }; + match self.item_family(self.entry(parent_item_id.index)) { + Family::Trait => Some(parent_item_id), + _ => None + } + } + + + pub fn get_native_libraries(&self) -> Vec<(NativeLibraryKind, String)> { + self.get(self.data.root(), root_tag::native_libraries).decode() + } + + pub fn get_dylib_dependency_formats(&self) -> Vec<(CrateNum, LinkagePreference)> { + let dcx = self.get(self.data.root(), root_tag::dylib_dependency_formats); + + dcx.seq::>().enumerate().flat_map(|(i, link)| { + let cnum = CrateNum::new(i + 1); + link.map(|link| (self.cnum_map.borrow()[cnum], link)) }).collect() } -} -pub fn is_defaulted_trait(cdata: Cmd, trait_id: DefIndex) -> bool { - match entry_data(cdata.lookup_item(trait_id), cdata) { - EntryData::Trait(data) => data.has_default_impl, - _ => bug!() - } -} - -pub fn is_default_impl(cdata: Cmd, impl_id: DefIndex) -> bool { - item_family(cdata.lookup_item(impl_id)) == Family::DefaultImpl -} - -pub fn get_imported_filemaps(metadata: &[u8]) -> Vec { - rbml::Doc::new(metadata).get(root_tag::codemap).decoder().decode() -} - -pub fn closure_kind(cdata: Cmd, closure_id: DefIndex) -> ty::ClosureKind { - match entry_data(cdata.lookup_item(closure_id), cdata) { - EntryData::Closure(data) => data.kind, - _ => bug!() - } -} - -pub fn closure_ty<'a, 'tcx>(cdata: Cmd, closure_id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>) - -> ty::ClosureTy<'tcx> { - match entry_typed_data(cdata.lookup_item(closure_id), tcx, cdata) { - EntryTypedData::Closure(data) => data.ty, - _ => bug!() - } -} - -pub fn def_key(cdata: Cmd, id: DefIndex) -> hir_map::DefKey { - debug!("def_key: id={:?}", id); - item_def_key(cdata.lookup_item(id)) -} - -fn item_def_key(item_doc: rbml::Doc) -> hir_map::DefKey { - item_doc.get(item_tag::def_key).decoder().decode() -} - -// Returns the path leading to the thing with this `id`. Note that -// some def-ids don't wind up in the metadata, so `def_path` sometimes -// returns `None` -pub fn def_path(cdata: Cmd, id: DefIndex) -> Option { - debug!("def_path(id={:?})", id); - if cdata.get_item(id).is_some() { - Some(hir_map::DefPath::make(cdata.cnum, id, |parent| def_key(cdata, parent))) - } else { - None + pub fn get_missing_lang_items(&self) -> Vec { + self.get(self.data.root(), root_tag::lang_items_missing).decode() + } + + pub fn get_fn_arg_names(&self, id: DefIndex) -> Vec { + self.maybe_get(self.entry(id), item_tag::fn_arg_names) + .map_or(vec![], |mut dcx| dcx.decode()) + } + + pub fn get_reachable_ids(&self) -> Vec { + let dcx = self.get(self.data.root(), root_tag::reachable_ids); + + dcx.seq().map(|index| self.local_def_id(index)).collect() + } + + pub fn is_const_fn(&self, id: DefIndex) -> bool { + let constness = match self.entry_data(self.entry(id)) { + EntryData::ImplAssociated(data) => data.constness, + EntryData::Fn(data) => data.constness, + _ => hir::Constness::NotConst + }; + constness == hir::Constness::Const + } + + pub fn is_extern_item(&self, id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> bool { + let item_doc = match self.maybe_entry(id) { + Some(doc) => doc, + None => return false, + }; + let applicable = match self.item_family(item_doc) { + Family::ImmStatic | + Family::MutStatic | + Family::ForeignImmStatic | + Family::ForeignMutStatic => true, + + Family::Fn | Family::ForeignFn => { + self.get_generics(id, tcx).types.is_empty() + } + + _ => false, + }; + + if applicable { + attr::contains_extern_indicator(tcx.sess.diagnostic(), + &self.get_attributes(item_doc)) + } else { + false + } + } + + pub fn is_foreign_item(&self, id: DefIndex) -> bool { + match self.item_family(self.entry(id)) { + Family::ForeignImmStatic | + Family::ForeignMutStatic | + Family::ForeignFn => true, + _ => false + } + } + + fn doc_generics(&self, base_doc: rbml::Doc, tcx: TyCtxt<'a, 'tcx, 'tcx>) + -> &'tcx ty::Generics<'tcx> { + let generics = self.get(base_doc, item_tag::generics).typed(tcx).decode(); + tcx.alloc_generics(generics) + } + + fn doc_predicates(&self, base_doc: rbml::Doc, tcx: TyCtxt<'a, 'tcx, 'tcx>, tag: usize) + -> ty::GenericPredicates<'tcx> { + let mut dcx = self.get(base_doc, tag).typed(tcx); + + ty::GenericPredicates { + parent: dcx.decode(), + predicates: (0..dcx.decode::()).map(|_| { + // Handle shorthands first, if we have an usize > 0x80. + if dcx.opaque.data[dcx.opaque.position()] & 0x80 != 0 { + let pos = dcx.decode::(); + assert!(pos >= SHORTHAND_OFFSET); + let pos = pos - SHORTHAND_OFFSET; + + let data = self.data.as_slice(); + let doc = rbml::Doc { + data: data, + start: pos, + end: data.len(), + }; + DecodeContext::new(doc, Some(self)).typed(tcx).decode() + } else { + dcx.decode() + } + }).collect() + } + } + + pub fn is_defaulted_trait(&self, trait_id: DefIndex) -> bool { + match self.entry_data(self.entry(trait_id)) { + EntryData::Trait(data) => data.has_default_impl, + _ => bug!() + } + } + + pub fn is_default_impl(&self, impl_id: DefIndex) -> bool { + self.item_family(self.entry(impl_id)) == Family::DefaultImpl + } + + pub fn closure_kind(&self, closure_id: DefIndex) -> ty::ClosureKind { + match self.entry_data(self.entry(closure_id)) { + EntryData::Closure(data) => data.kind, + _ => bug!() + } + } + + pub fn closure_ty(&self, closure_id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>) + -> ty::ClosureTy<'tcx> { + match self.entry_typed_data(self.entry(closure_id), tcx) { + EntryTypedData::Closure(data) => data.ty, + _ => bug!() + } + } + + pub fn def_key(&self, id: DefIndex) -> hir_map::DefKey { + debug!("def_key: id={:?}", id); + self.item_def_key(self.entry(id)) + } + + // Returns the path leading to the thing with this `id`. Note that + // some def-ids don't wind up in the metadata, so `def_path` sometimes + // returns `None` + pub fn def_path(&self, id: DefIndex) -> Option { + debug!("def_path(id={:?})", id); + if self.maybe_entry(id).is_some() { + Some(hir_map::DefPath::make(self.cnum, id, |parent| self.def_key(parent))) + } else { + None + } } } diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 637228725e0b..e345129b327e 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -11,7 +11,6 @@ // Metadata encoding #![allow(unused_must_use)] // everything is just a MemWriter, can't fail -#![allow(non_camel_case_types)] use astencode::encode_inlined_item; use common::*; @@ -226,9 +225,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { struct_ctor: struct_ctor }) } -} -impl<'a, 'tcx> EncodeContext<'a, 'tcx> { /// Encode data for the given variant of the given ADT. The /// index of the variant is untracked: this is ok because we /// will have to lookup the adt-def by its id, and that gives us @@ -249,8 +246,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.encode_visibility(enum_vis); let attrs = tcx.get_attrs(vid); - encode_attributes(self, &attrs); - encode_stability(self, vid); + self.encode_attributes(&attrs); + self.encode_stability(vid); let data = self.encode_variant(variant, None); @@ -264,9 +261,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.encode_bounds_and_type_for_item(vid); } -} -impl<'a, 'tcx> EncodeContext<'a, 'tcx> { fn encode_info_for_mod(&mut self, FromId(id, (md, attrs, vis)): FromId<(&hir::Mod, &[ast::Attribute], &hir::Visibility)>) { @@ -276,8 +271,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.encode_def_key(def_id); self.encode_family(Family::Mod); self.encode_visibility(vis); - encode_stability(self, def_id); - encode_attributes(self, attrs); + self.encode_stability(def_id); + self.encode_attributes(attrs); debug!("(encoding info for module) encoding info for module ID {}", id); // Encode info about all the module children. @@ -371,8 +366,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let variant_id = tcx.map.as_local_node_id(variant.did).unwrap(); let variant_data = tcx.map.expect_variant_data(variant_id); - encode_attributes(self, &variant_data.fields()[field_index].attrs); - encode_stability(self, field.did); + self.encode_attributes(&variant_data.fields()[field_index].attrs); + self.encode_stability(field.did); } fn encode_struct_ctor(&mut self, ctor_def_id: DefId) { @@ -380,7 +375,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.encode_family(Family::Struct); self.encode_bounds_and_type_for_item(ctor_def_id); - encode_stability(self, ctor_def_id); + self.encode_stability(ctor_def_id); } fn encode_generics(&mut self, @@ -445,8 +440,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.encode_family(family); self.encode_visibility(trait_item.vis()); - encode_stability(self, def_id); - encode_attributes(self, &ast_item.attrs); + self.encode_stability(def_id); + self.encode_attributes(&ast_item.attrs); if let hir::MethodTraitItem(ref sig, _) = ast_item.node { self.encode_fn_arg_names(&sig.decl); }; @@ -499,8 +494,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.encode_def_key(def_id); self.encode_family(family); self.encode_visibility(impl_item.vis()); - encode_attributes(self, &ast_item.attrs); - encode_stability(self, def_id); + self.encode_attributes(&ast_item.attrs); + self.encode_stability(def_id); let constness = if let hir::ImplItemKind::Method(ref sig, _) = ast_item.node { if sig.constness == hir::Constness::Const { @@ -555,33 +550,30 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.end_tag(); } } -} -// Encodes the inherent implementations of a structure, enumeration, or trait. -fn encode_inherent_implementations(ecx: &mut EncodeContext, - def_id: DefId) { - ecx.start_tag(item_tag::inherent_impls); - match ecx.tcx.inherent_impls.borrow().get(&def_id) { - None => <[DefId]>::encode(&[], ecx).unwrap(), - Some(implementations) => implementations.encode(ecx).unwrap() + // Encodes the inherent implementations of a structure, enumeration, or trait. + fn encode_inherent_implementations(&mut self, def_id: DefId) { + self.start_tag(item_tag::inherent_impls); + match self.tcx.inherent_impls.borrow().get(&def_id) { + None => <[DefId]>::encode(&[], self).unwrap(), + Some(implementations) => implementations.encode(self).unwrap() + } + self.end_tag(); } - ecx.end_tag(); -} -fn encode_stability(ecx: &mut EncodeContext, def_id: DefId) { - ecx.tcx.lookup_stability(def_id).map(|stab| { - ecx.start_tag(item_tag::stability); - stab.encode(ecx).unwrap(); - ecx.end_tag(); - }); - ecx.tcx.lookup_deprecation(def_id).map(|depr| { - ecx.start_tag(item_tag::deprecation); - depr.encode(ecx).unwrap(); - ecx.end_tag(); - }); -} + fn encode_stability(&mut self, def_id: DefId) { + self.tcx.lookup_stability(def_id).map(|stab| { + self.start_tag(item_tag::stability); + stab.encode(self).unwrap(); + self.end_tag(); + }); + self.tcx.lookup_deprecation(def_id).map(|depr| { + self.start_tag(item_tag::deprecation); + depr.encode(self).unwrap(); + self.end_tag(); + }); + } -impl<'a, 'tcx> EncodeContext<'a, 'tcx> { fn encode_info_for_item(&mut self, (def_id, item): (DefId, &hir::Item)) { let tcx = self.tcx; @@ -652,7 +644,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.end_tag(); // Encode inherent implementations for self enumeration. - encode_inherent_implementations(self, def_id); + self.encode_inherent_implementations(def_id); (Family::Enum, EntryData::Other, EntryTypedData::Other) } @@ -675,7 +667,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let data = self.encode_variant(variant, struct_ctor); // Encode inherent implementations for self structure. - encode_inherent_implementations(self, def_id); + self.encode_inherent_implementations(def_id); (Family::Struct, data, EntryTypedData::Other) } @@ -691,7 +683,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let data = self.encode_variant(def.struct_variant(), None); // Encode inherent implementations for self union. - encode_inherent_implementations(self, def_id); + self.encode_inherent_implementations(def_id); (Family::Union, data, EntryTypedData::Other) } @@ -752,7 +744,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.end_tag(); // Encode inherent implementations for self trait. - encode_inherent_implementations(self, def_id); + self.encode_inherent_implementations(def_id); (Family::Trait, EntryData::Trait(TraitData { @@ -772,8 +764,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.encode_family(family); self.encode_def_key(def_id); self.encode_visibility(&item.vis); - encode_attributes(self, &item.attrs); - encode_stability(self, def_id); + self.encode_attributes(&item.attrs); + self.encode_stability(def_id); self.start_tag(item_tag::data); data.encode(self).unwrap(); @@ -883,8 +875,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { EntryTypedData::Other.encode(self).unwrap(); self.end_tag(); - encode_attributes(self, &nitem.attrs); - encode_stability(self, def_id); + self.encode_attributes(&nitem.attrs); + self.encode_stability(def_id); } } @@ -970,152 +962,153 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { assert!(self.mir_map.map.contains_key(&def_id)); self.encode_mir(def_id); } -} -fn encode_info_for_items(ecx: &mut EncodeContext) -> IndexData { - let krate = ecx.tcx.map.krate(); + fn encode_info_for_items(&mut self) -> IndexData { + let krate = self.tcx.map.krate(); - // FIXME(eddyb) Avoid wrapping the items in a doc. - ecx.start_tag(0).unwrap(); + // FIXME(eddyb) Avoid wrapping the items in a doc. + self.start_tag(0).unwrap(); - let items = { - let mut index = IndexBuilder::new(ecx); - index.record(DefId::local(CRATE_DEF_INDEX), - EncodeContext::encode_info_for_mod, - FromId(CRATE_NODE_ID, (&krate.module, &krate.attrs, &hir::Public))); - let mut visitor = EncodeVisitor { - index: index, + let items = { + let mut index = IndexBuilder::new(self); + index.record(DefId::local(CRATE_DEF_INDEX), + EncodeContext::encode_info_for_mod, + FromId(CRATE_NODE_ID, (&krate.module, &krate.attrs, &hir::Public))); + let mut visitor = EncodeVisitor { + index: index, + }; + krate.visit_all_items(&mut visitor); + visitor.index.into_items() }; - krate.visit_all_items(&mut visitor); - visitor.index.into_items() - }; - ecx.end_tag(); + self.end_tag(); - items -} - -fn encode_item_index(ecx: &mut EncodeContext, index: IndexData) { - ecx.start_tag(root_tag::index); - index.write_index(&mut ecx.opaque.cursor); - ecx.end_tag(); -} - -fn encode_attributes(ecx: &mut EncodeContext, attrs: &[ast::Attribute]) { - ecx.start_tag(item_tag::attributes); - attrs.encode(ecx).unwrap(); - ecx.end_tag(); -} - -fn encode_crate_deps(ecx: &mut EncodeContext, cstore: &cstore::CStore) { - fn get_ordered_deps(cstore: &cstore::CStore) - -> Vec<(CrateNum, Rc)> { - // Pull the cnums and name,vers,hash out of cstore - let mut deps = Vec::new(); - cstore.iter_crate_data(|cnum, val| { - deps.push((cnum, val.clone())); - }); - - // Sort by cnum - deps.sort_by(|kv1, kv2| kv1.0.cmp(&kv2.0)); - - // Sanity-check the crate numbers - let mut expected_cnum = 1; - for &(n, _) in &deps { - assert_eq!(n, CrateNum::new(expected_cnum)); - expected_cnum += 1; - } - - deps + items } - // We're just going to write a list of crate 'name-hash-version's, with - // the assumption that they are numbered 1 to n. - // FIXME (#2166): This is not nearly enough to support correct versioning - // but is enough to get transitive crate dependencies working. - ecx.start_tag(root_tag::crate_deps); - ecx.seq(&get_ordered_deps(cstore), |_, &(_, ref dep)| { - (dep.name(), dep.hash(), dep.explicitly_linked.get()) - }); - ecx.end_tag(); -} + fn encode_item_index(&mut self, index: IndexData) { + self.start_tag(root_tag::index); + index.write_index(&mut self.opaque.cursor); + self.end_tag(); + } -fn encode_lang_items(ecx: &mut EncodeContext) { - let tcx = ecx.tcx; - let lang_items = || { - tcx.lang_items.items().iter().enumerate().filter_map(|(i, &opt_def_id)| { - if let Some(def_id) = opt_def_id { - if def_id.is_local() { - return Some((def_id.index, i)); - } + fn encode_attributes(&mut self, attrs: &[ast::Attribute]) { + self.start_tag(item_tag::attributes); + attrs.encode(self).unwrap(); + self.end_tag(); + } + + fn encode_crate_deps(&mut self) { + fn get_ordered_deps(cstore: &cstore::CStore) + -> Vec<(CrateNum, Rc)> { + // Pull the cnums and name,vers,hash out of cstore + let mut deps = Vec::new(); + cstore.iter_crate_data(|cnum, val| { + deps.push((cnum, val.clone())); + }); + + // Sort by cnum + deps.sort_by(|kv1, kv2| kv1.0.cmp(&kv2.0)); + + // Sanity-check the crate numbers + let mut expected_cnum = 1; + for &(n, _) in &deps { + assert_eq!(n, CrateNum::new(expected_cnum)); + expected_cnum += 1; } - None - }) - }; - let count = lang_items().count(); - let mut lang_items = lang_items(); + deps + } - ecx.start_tag(root_tag::lang_items); - ecx.seq(0..count, |_, _| lang_items.next().unwrap()); - ecx.end_tag(); + // We're just going to write a list of crate 'name-hash-version's, with + // the assumption that they are numbered 1 to n. + // FIXME (#2166): This is not nearly enough to support correct versioning + // but is enough to get transitive crate dependencies working. + self.start_tag(root_tag::crate_deps); + let deps = get_ordered_deps(self.cstore); + self.seq(&deps, |_, &(_, ref dep)| { + (dep.name(), dep.hash(), dep.explicitly_linked.get()) + }); + self.end_tag(); + } - ecx.start_tag(root_tag::lang_items_missing); - tcx.lang_items.missing.encode(ecx).unwrap(); - ecx.end_tag(); -} - -fn encode_native_libraries(ecx: &mut EncodeContext) { - let used_libraries = ecx.tcx.sess.cstore.used_libraries(); - let libs = || { - used_libraries.iter().filter_map(|&(ref lib, kind)| { - match kind { - cstore::NativeStatic => None, // these libraries are not propagated - cstore::NativeFramework | cstore::NativeUnknown => { - Some((kind, lib)) + fn encode_lang_items(&mut self) { + let tcx = self.tcx; + let lang_items = || { + tcx.lang_items.items().iter().enumerate().filter_map(|(i, &opt_def_id)| { + if let Some(def_id) = opt_def_id { + if def_id.is_local() { + return Some((def_id.index, i)); + } } - } - }) - }; + None + }) + }; - let count = libs().count(); - let mut libs = libs(); + let count = lang_items().count(); + let mut lang_items = lang_items(); - ecx.start_tag(root_tag::native_libraries); - ecx.seq(0..count, |_, _| libs.next().unwrap()); - ecx.end_tag(); -} + self.start_tag(root_tag::lang_items); + self.seq(0..count, |_, _| lang_items.next().unwrap()); + self.end_tag(); -fn encode_codemap(ecx: &mut EncodeContext) { - let codemap = ecx.tcx.sess.codemap(); - let all_filemaps = codemap.files.borrow(); - let filemaps = || { - // No need to export empty filemaps, as they can't contain spans - // that need translation. - // Also no need to re-export imported filemaps, as any downstream - // crate will import them from their original source. - all_filemaps.iter().filter(|filemap| { - !filemap.lines.borrow().is_empty() && !filemap.is_imported() - }) - }; + self.start_tag(root_tag::lang_items_missing); + tcx.lang_items.missing.encode(self).unwrap(); + self.end_tag(); + } - let count = filemaps().count(); - let mut filemaps = filemaps(); + fn encode_native_libraries(&mut self) { + let used_libraries = self.tcx.sess.cstore.used_libraries(); + let libs = || { + used_libraries.iter().filter_map(|&(ref lib, kind)| { + match kind { + cstore::NativeStatic => None, // these libraries are not propagated + cstore::NativeFramework | cstore::NativeUnknown => { + Some((kind, lib)) + } + } + }) + }; - ecx.start_tag(root_tag::codemap); - ecx.seq(0..count, |_, _| filemaps.next().unwrap()); - ecx.end_tag(); -} + let count = libs().count(); + let mut libs = libs(); -/// Serialize the text of the exported macros -fn encode_macro_defs(ecx: &mut EncodeContext) { - let tcx = ecx.tcx; - ecx.start_tag(root_tag::macro_defs); - ecx.seq(&tcx.map.krate().exported_macros, |_, def| { - let body = ::syntax::print::pprust::tts_to_string(&def.body); - (def.name, &def.attrs, def.span, body) - }); - ecx.end_tag(); + self.start_tag(root_tag::native_libraries); + self.seq(0..count, |_, _| libs.next().unwrap()); + self.end_tag(); + } + + fn encode_codemap(&mut self) { + let codemap = self.tcx.sess.codemap(); + let all_filemaps = codemap.files.borrow(); + let filemaps = || { + // No need to export empty filemaps, as they can't contain spans + // that need translation. + // Also no need to re-export imported filemaps, as any downstream + // crate will import them from their original source. + all_filemaps.iter().filter(|filemap| { + !filemap.lines.borrow().is_empty() && !filemap.is_imported() + }) + }; + + let count = filemaps().count(); + let mut filemaps = filemaps(); + + self.start_tag(root_tag::codemap); + self.seq(0..count, |_, _| filemaps.next().unwrap()); + self.end_tag(); + } + + /// Serialize the text of the exported macros + fn encode_macro_defs(&mut self) { + let tcx = self.tcx; + self.start_tag(root_tag::macro_defs); + self.seq(&tcx.map.krate().exported_macros, |_, def| { + let body = ::syntax::print::pprust::tts_to_string(&def.body); + (def.name, &def.attrs, def.span, body) + }); + self.end_tag(); + } } struct ImplVisitor<'a, 'tcx:'a> { @@ -1136,59 +1129,61 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ImplVisitor<'a, 'tcx> { } } -/// Encodes an index, mapping each trait to its (local) implementations. -fn encode_impls(ecx: &mut EncodeContext) { - let mut visitor = ImplVisitor { - tcx: ecx.tcx, - impls: FnvHashMap() - }; - ecx.tcx.map.krate().visit_all_items(&mut visitor); +impl<'a, 'tcx> EncodeContext<'a, 'tcx> { + /// Encodes an index, mapping each trait to its (local) implementations. + fn encode_impls(&mut self) { + let mut visitor = ImplVisitor { + tcx: self.tcx, + impls: FnvHashMap() + }; + self.tcx.map.krate().visit_all_items(&mut visitor); - ecx.start_tag(root_tag::impls); - for (trait_def_id, trait_impls) in visitor.impls { - // FIXME(eddyb) Avoid wrapping the entries in docs. - ecx.start_tag(0); - (trait_def_id.krate.as_u32(), trait_def_id.index).encode(ecx).unwrap(); - trait_impls.encode(ecx).unwrap(); - ecx.end_tag(); - } - ecx.end_tag(); -} - -// Encodes all reachable symbols in this crate into the metadata. -// -// This pass is seeded off the reachability list calculated in the -// middle::reachable module but filters out items that either don't have a -// symbol associated with them (they weren't translated) or if they're an FFI -// definition (as that's not defined in this crate). -fn encode_reachable(ecx: &mut EncodeContext) { - ecx.start_tag(root_tag::reachable_ids); - - let reachable = ecx.reachable; - ecx.seq(reachable, |ecx, &id| ecx.tcx.map.local_def_id(id).index); - - ecx.end_tag(); -} - -fn encode_dylib_dependency_formats(ecx: &mut EncodeContext) { - ecx.start_tag(root_tag::dylib_dependency_formats); - match ecx.tcx.sess.dependency_formats.borrow().get(&config::CrateTypeDylib) { - Some(arr) => { - ecx.seq(arr, |_, slot| { - match *slot { - Linkage::NotLinked | - Linkage::IncludedFromDylib => None, - - Linkage::Dynamic => Some(LinkagePreference::RequireDynamic), - Linkage::Static => Some(LinkagePreference::RequireStatic), - } - }); - } - None => { - <[Option]>::encode(&[], ecx).unwrap(); + self.start_tag(root_tag::impls); + for (trait_def_id, trait_impls) in visitor.impls { + // FIXME(eddyb) Avoid wrapping the entries in docs. + self.start_tag(0); + (trait_def_id.krate.as_u32(), trait_def_id.index).encode(self).unwrap(); + trait_impls.encode(self).unwrap(); + self.end_tag(); } + self.end_tag(); + } + + // Encodes all reachable symbols in this crate into the metadata. + // + // This pass is seeded off the reachability list calculated in the + // middle::reachable module but filters out items that either don't have a + // symbol associated with them (they weren't translated) or if they're an FFI + // definition (as that's not defined in this crate). + fn encode_reachable(&mut self) { + self.start_tag(root_tag::reachable_ids); + + let reachable = self.reachable; + self.seq(reachable, |ecx, &id| ecx.tcx.map.local_def_id(id).index); + + self.end_tag(); + } + + fn encode_dylib_dependency_formats(&mut self) { + self.start_tag(root_tag::dylib_dependency_formats); + match self.tcx.sess.dependency_formats.borrow().get(&config::CrateTypeDylib) { + Some(arr) => { + self.seq(arr, |_, slot| { + match *slot { + Linkage::NotLinked | + Linkage::IncludedFromDylib => None, + + Linkage::Dynamic => Some(LinkagePreference::RequireDynamic), + Linkage::Static => Some(LinkagePreference::RequireStatic), + } + }); + } + None => { + <[Option]>::encode(&[], self).unwrap(); + } + } + self.end_tag(); } - ecx.end_tag(); } pub fn encode_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -1281,47 +1276,47 @@ fn encode_metadata_inner(ecx: &mut EncodeContext) { ecx.end_tag(); let mut i = ecx.position(); - encode_crate_deps(ecx, ecx.cstore); - encode_dylib_dependency_formats(ecx); + ecx.encode_crate_deps(); + ecx.encode_dylib_dependency_formats(); let dep_bytes = ecx.position() - i; // Encode the language items. i = ecx.position(); - encode_lang_items(ecx); + ecx.encode_lang_items(); let lang_item_bytes = ecx.position() - i; // Encode the native libraries used i = ecx.position(); - encode_native_libraries(ecx); + ecx.encode_native_libraries(); let native_lib_bytes = ecx.position() - i; // Encode codemap i = ecx.position(); - encode_codemap(ecx); + ecx.encode_codemap(); let codemap_bytes = ecx.position() - i; // Encode macro definitions i = ecx.position(); - encode_macro_defs(ecx); + ecx.encode_macro_defs(); let macro_defs_bytes = ecx.position() - i; // Encode the def IDs of impls, for coherence checking. i = ecx.position(); - encode_impls(ecx); + ecx.encode_impls(); let impl_bytes = ecx.position() - i; // Encode reachability info. i = ecx.position(); - encode_reachable(ecx); + ecx.encode_reachable(); let reachable_bytes = ecx.position() - i; // Encode and index the items. i = ecx.position(); - let items = encode_info_for_items(ecx); + let items = ecx.encode_info_for_items(); let item_bytes = ecx.position() - i; i = ecx.position(); - encode_item_index(ecx, items); + ecx.encode_item_index(items); let index_bytes = ecx.position() - i; let total_bytes = ecx.position(); diff --git a/src/librustc_metadata/loader.rs b/src/librustc_metadata/loader.rs index 47bf65bead9a..883004b8486f 100644 --- a/src/librustc_metadata/loader.rs +++ b/src/librustc_metadata/loader.rs @@ -214,7 +214,6 @@ use cstore::{MetadataBlob, MetadataVec, MetadataArchive}; use common::{metadata_encoding_version, rustc_version}; -use decoder; use rustc::hir::svh::Svh; use rustc::session::Session; @@ -511,7 +510,7 @@ impl<'a> Context<'a> { if let Some((ref p, _)) = lib.rlib { err.note(&format!("path: {}", p.display())); } - let crate_info = decoder::get_crate_info(lib.metadata.as_slice()); + let crate_info = lib.metadata.get_crate_info(); note_crate_name(&mut err, &crate_info.name); } err.emit(); @@ -550,7 +549,7 @@ impl<'a> Context<'a> { info!("{} reading metadata from: {}", flavor, lib.display()); let (hash, metadata) = match get_metadata_section(self.target, flavor, &lib) { Ok(blob) => { - if let Some(h) = self.crate_matches(blob.as_slice(), &lib) { + if let Some(h) = self.crate_matches(&blob, &lib) { (h, blob) } else { info!("metadata mismatch"); @@ -597,8 +596,8 @@ impl<'a> Context<'a> { } } - fn crate_matches(&mut self, crate_data: &[u8], libpath: &Path) -> Option { - let crate_rustc_version = decoder::crate_rustc_version(crate_data); + fn crate_matches(&mut self, metadata: &MetadataBlob, libpath: &Path) -> Option { + let crate_rustc_version = metadata.crate_rustc_version(); if crate_rustc_version != Some(rustc_version()) { let message = crate_rustc_version.unwrap_or(format!("an unknown compiler")); info!("Rejecting via version: expected {} got {}", rustc_version(), message); @@ -609,7 +608,7 @@ impl<'a> Context<'a> { return None; } - let crate_info = decoder::get_crate_info(crate_data); + let crate_info = metadata.get_crate_info(); if self.should_match_name { if self.crate_name != crate_info.name { info!("Rejecting via crate name"); return None; @@ -895,7 +894,7 @@ pub fn list_file_metadata(target: &Target, path: &Path, let filename = path.file_name().unwrap().to_str().unwrap(); let flavor = if filename.ends_with(".rlib") { CrateFlavor::Rlib } else { CrateFlavor::Dylib }; match get_metadata_section(target, flavor, path) { - Ok(bytes) => decoder::list_crate_metadata(bytes.as_slice(), out), + Ok(metadata) => metadata.list_crate_metadata(out), Err(msg) => { write!(out, "{}\n", msg) } diff --git a/src/librustc_metadata/rbml/reader.rs b/src/librustc_metadata/rbml/reader.rs index 24a0329602be..c4cfc32d6330 100644 --- a/src/librustc_metadata/rbml/reader.rs +++ b/src/librustc_metadata/rbml/reader.rs @@ -52,6 +52,15 @@ use test::Bencher; use std::fmt; use std::str; +macro_rules! try_or { + ($e:expr, $r:expr) => ( + match $e { + Ok(x) => x, + Err(_) => return $r + } + ) +} + #[derive(Clone, Copy)] pub struct Doc<'a> { pub data: &'a [u8], @@ -79,17 +88,34 @@ impl<'doc> Doc<'doc> { } } - pub fn get(&self, tag: usize) -> Doc<'doc> { - match maybe_get_doc(*self, tag) { + pub fn maybe_child(&self, tag: usize) -> Option> { + let mut pos = self.start; + while pos < self.end { + let elt_tag = try_or!(tag_at(self.data, pos), None); + let elt_size = try_or!(tag_len_at(self.data, elt_tag.next), None); + pos = elt_size.next + elt_size.val; + if elt_tag.val == tag { + return Some(Doc { + data: self.data, + start: elt_size.next, + end: pos, + }); + } + } + None + } + + pub fn child(&self, tag: usize) -> Doc<'doc> { + match self.maybe_child(tag) { Some(d) => d, None => { - bug!("failed to find block with tag {:?}", tag); + bug!("failed to find child with tag {:?}", tag); } } } - pub fn children(self) -> DocsIterator<'doc> { - DocsIterator { d: self } + pub fn children_of(&self, tag: usize) -> DocsIterator<'doc> { + DocsIterator { d: self.child(tag) } } } @@ -106,24 +132,10 @@ impl fmt::Display for Error { } } -// rbml reading - -macro_rules! try_or { - ($e:expr, $r:expr) => ( - match $e { - Ok(e) => e, - Err(e) => { - debug!("ignored error: {:?}", e); - return $r - } - } - ) -} - #[derive(Copy, Clone)] -pub struct Res { - pub val: usize, - pub next: usize, +struct Res { + val: usize, + next: usize, } fn tag_at(data: &[u8], start: usize) -> Result { @@ -235,23 +247,6 @@ fn tag_len_at(data: &[u8], next: usize) -> Result { vuint_at(data, next) } -pub fn maybe_get_doc<'a>(d: Doc<'a>, tg: usize) -> Option> { - let mut pos = d.start; - while pos < d.end { - let elt_tag = try_or!(tag_at(d.data, pos), None); - let elt_size = try_or!(tag_len_at(d.data, elt_tag.next), None); - pos = elt_size.next + elt_size.val; - if elt_tag.val == tg { - return Some(Doc { - data: d.data, - start: elt_size.next, - end: pos, - }); - } - } - None -} - pub struct DocsIterator<'a> { d: Doc<'a>, } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 43a9b4e49e39..0acf211a27c5 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -237,8 +237,8 @@ pub struct ExternalCrate { impl Clean for CrateNum { fn clean(&self, cx: &DocContext) -> ExternalCrate { let mut primitives = Vec::new(); + let root = DefId { krate: self.0, index: CRATE_DEF_INDEX }; cx.tcx_opt().map(|tcx| { - let root = DefId { krate: self.0, index: CRATE_DEF_INDEX }; for item in tcx.sess.cstore.item_children(root) { let did = match item.def { Def::Mod(did) => did, @@ -250,7 +250,7 @@ impl Clean for CrateNum { }); ExternalCrate { name: (&cx.sess().cstore.crate_name(self.0)[..]).to_owned(), - attrs: cx.sess().cstore.crate_attrs(self.0).clean(cx), + attrs: cx.sess().cstore.item_attrs(root).clean(cx), primitives: primitives, } } From 24aef24e1aa732115c1a98feb06510de372fcf0c Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Thu, 15 Sep 2016 11:05:45 +0300 Subject: [PATCH 427/443] rustc_metadata: split the Def description of a DefId from item_children. --- src/librustc/middle/cstore.rs | 13 ++--- src/librustc_metadata/csearch.rs | 36 +++++------- src/librustc_metadata/decoder.rs | 62 ++++++++++----------- src/librustc_metadata/encoder.rs | 1 + src/librustc_resolve/build_reduced_graph.rs | 25 ++++++--- src/librustc_typeck/check/method/suggest.rs | 20 +++---- src/librustdoc/clean/inline.rs | 10 ++-- src/librustdoc/clean/mod.rs | 6 +- src/librustdoc/visit_lib.rs | 31 ++++------- 9 files changed, 95 insertions(+), 109 deletions(-) diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 6324995f328b..dbbd5eca4832 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -96,13 +96,6 @@ pub enum InlinedItemRef<'a> { ImplItem(DefId, &'a hir::ImplItem) } -#[derive(Copy, Clone)] -pub struct ChildItem { - pub def: Def, - pub name: ast::Name, - pub vis: ty::Visibility, -} - #[derive(Copy, Clone, Debug)] pub struct ExternCrate { /// def_id of an `extern crate` in the current crate that caused @@ -128,6 +121,7 @@ pub struct ExternCrate { /// can be accessed. pub trait CrateStore<'tcx> { // item info + fn describe_def(&self, def: DefId) -> Option; fn stability(&self, def: DefId) -> Option; fn deprecation(&self, def: DefId) -> Option; fn visibility(&self, def: DefId) -> ty::Visibility; @@ -209,7 +203,7 @@ pub trait CrateStore<'tcx> { fn relative_def_path(&self, def: DefId) -> Option; fn struct_ctor_def_id(&self, struct_def_id: DefId) -> Option; fn struct_field_names(&self, def: DefId) -> Vec; - fn item_children(&self, did: DefId) -> Vec; + fn item_children(&self, did: DefId) -> Vec; // misc. metadata fn maybe_get_item_ast<'a>(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) @@ -286,6 +280,7 @@ pub struct DummyCrateStore; #[allow(unused_variables)] impl<'tcx> CrateStore<'tcx> for DummyCrateStore { // item info + fn describe_def(&self, def: DefId) -> Option { bug!("describe_def") } fn stability(&self, def: DefId) -> Option { bug!("stability") } fn deprecation(&self, def: DefId) -> Option { bug!("deprecation") } fn visibility(&self, def: DefId) -> ty::Visibility { bug!("visibility") } @@ -386,7 +381,7 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { fn struct_ctor_def_id(&self, struct_def_id: DefId) -> Option { bug!("struct_ctor_def_id") } fn struct_field_names(&self, def: DefId) -> Vec { bug!("struct_field_names") } - fn item_children(&self, did: DefId) -> Vec { bug!("item_children") } + fn item_children(&self, did: DefId) -> Vec { bug!("item_children") } // misc. metadata fn maybe_get_item_ast<'a>(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) diff --git a/src/librustc_metadata/csearch.rs b/src/librustc_metadata/csearch.rs index 8136fc7e845f..8569dbcd5073 100644 --- a/src/librustc_metadata/csearch.rs +++ b/src/librustc_metadata/csearch.rs @@ -13,9 +13,9 @@ use common; use encoder; use loader; -use rustc::middle::cstore::{InlinedItem, CrateStore, CrateSource, ChildItem, ExternCrate}; +use rustc::middle::cstore::{InlinedItem, CrateStore, CrateSource, ExternCrate}; use rustc::middle::cstore::{NativeLibraryKind, LinkMeta, LinkagePreference}; -use rustc::hir::def; +use rustc::hir::def::{self, Def}; use rustc::middle::lang_items; use rustc::ty::{self, Ty, TyCtxt}; use rustc::hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX}; @@ -37,6 +37,11 @@ use rustc_back::target::Target; use rustc::hir; impl<'tcx> CrateStore<'tcx> for cstore::CStore { + fn describe_def(&self, def: DefId) -> Option { + self.dep_graph.read(DepNode::MetaData(def)); + self.get_crate_data(def.krate).get_def(def.index) + } + fn stability(&self, def: DefId) -> Option { self.dep_graph.read(DepNode::MetaData(def)); self.get_crate_data(def.krate).get_stability(def.index) @@ -158,10 +163,8 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { fn impl_or_trait_items(&self, def_id: DefId) -> Vec { self.dep_graph.read(DepNode::MetaData(def_id)); let mut result = vec![]; - let get_crate_data = &mut |cnum| self.get_crate_data(cnum); self.get_crate_data(def_id.krate) - .each_child_of_item(def_id.index, get_crate_data, - &mut |def, _, _| result.push(def.def_id())); + .each_child_of_item(def_id.index, |child| result.push(child.def_id)); result } @@ -366,20 +369,12 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { self.get_crate_data(def.krate).get_struct_field_names(def.index) } - fn item_children(&self, def_id: DefId) -> Vec + fn item_children(&self, def_id: DefId) -> Vec { self.dep_graph.read(DepNode::MetaData(def_id)); let mut result = vec![]; - let get_crate_data = &mut |cnum| self.get_crate_data(cnum); self.get_crate_data(def_id.krate) - .each_child_of_item(def_id.index, get_crate_data, - &mut |def, name, vis| { - result.push(ChildItem { - def: def, - name: name, - vis: vis - }); - }); + .each_child_of_item(def_id.index, |child| result.push(child)); result } @@ -567,7 +562,6 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { let mut visible_parent_map = self.visible_parent_map.borrow_mut(); if !visible_parent_map.is_empty() { return visible_parent_map; } - use rustc::middle::cstore::ChildItem; use std::collections::vec_deque::VecDeque; use std::collections::hash_map::Entry; for cnum in (1 .. self.next_crate_num().as_usize()).map(CrateNum::new) { @@ -580,12 +574,12 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { } let mut bfs_queue = &mut VecDeque::new(); - let mut add_child = |bfs_queue: &mut VecDeque<_>, child: ChildItem, parent: DefId| { - let child = if child.vis == ty::Visibility::Public { - child.def.def_id() - } else { + let mut add_child = |bfs_queue: &mut VecDeque<_>, child: def::Export, parent: DefId| { + let child = child.def_id; + + if self.visibility(child) != ty::Visibility::Public { return; - }; + } match visible_parent_map.entry(child) { Entry::Occupied(mut entry) => { diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 05bd9e97234e..a34daba70009 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -23,7 +23,7 @@ use rustc::hir; use rustc::hir::intravisit::IdRange; use rustc::middle::cstore::{InlinedItem, LinkagePreference}; -use rustc::hir::def::Def; +use rustc::hir::def::{self, Def}; use rustc::hir::def_id::{CrateNum, DefId, DefIndex, LOCAL_CRATE}; use rustc::middle::lang_items; use rustc::ty::{ImplContainer, TraitContainer}; @@ -505,6 +505,10 @@ impl<'a, 'tcx> CrateMetadata { self.maybe_get(doc, item_tag::ty).map(|dcx| dcx.typed(tcx).decode()) } + pub fn get_def(&self, index: DefIndex) -> Option { + self.item_family(self.entry(index)).to_def(self.local_def_id(index)) + } + pub fn get_trait_def(&self, item_id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> ty::TraitDef<'tcx> { @@ -664,11 +668,8 @@ impl<'a, 'tcx> CrateMetadata { } /// Iterates over each child of the given item. - pub fn each_child_of_item(&self, id: DefIndex, - mut get_crate_data: &mut G, - mut callback: &mut F) - where F: FnMut(Def, ast::Name, ty::Visibility), - G: FnMut(CrateNum) -> Rc, + pub fn each_child_of_item(&self, id: DefIndex, mut callback: F) + where F: FnMut(def::Export) { // Find the item. let item_doc = match self.maybe_entry(id) { @@ -682,15 +683,31 @@ impl<'a, 'tcx> CrateMetadata { }; // Iterate over all children. - for child_index in dcx.seq::() { + for child_index in dcx.seq() { // Get the item. if let Some(child) = self.maybe_entry(child_index) { // Hand off the item to the callback. - let family = self.item_family(child); - if let Family::ForeignMod = family { - self.each_child_of_item(child_index, get_crate_data, callback); - } else if let Some(def) = family.to_def(self.local_def_id(child_index)) { - callback(def, self.item_name(child), self.item_visibility(child)); + match self.item_family(child) { + // FIXME(eddyb) Don't encode these in children. + Family::ForeignMod => { + for child_index in self.get(child, item_tag::children).seq() { + callback(def::Export { + def_id: self.local_def_id(child_index), + name: self.item_name(self.entry(child_index)) + }); + } + continue; + } + Family::Impl | Family::DefaultImpl => continue, + + _ => {} + } + + if let Some(name) = self.maybe_item_name(child) { + callback(def::Export { + def_id: self.local_def_id(child_index), + name: name + }); } } } @@ -700,26 +717,7 @@ impl<'a, 'tcx> CrateMetadata { _ => return }; for exp in reexports { - // This reexport may be in yet another crate. - let crate_data = if exp.def_id.krate == self.cnum { - None - } else { - Some(get_crate_data(exp.def_id.krate)) - }; - let crate_data = match crate_data { - Some(ref cdata) => &**cdata, - None => self - }; - - // Get the item. - if let Some(child) = crate_data.maybe_entry(exp.def_id.index) { - // Hand off the item to the callback. - if let Some(def) = self.item_family(child).to_def(exp.def_id) { - // These items have a public visibility because they're part of - // a public re-export. - callback(def, exp.name, ty::Visibility::Public); - } - } + callback(exp); } } diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index e345129b327e..e690e5198795 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -373,6 +373,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { fn encode_struct_ctor(&mut self, ctor_def_id: DefId) { self.encode_def_key(ctor_def_id); self.encode_family(Family::Struct); + self.encode_visibility(ty::Visibility::Public); self.encode_bounds_and_type_for_item(ctor_def_id); self.encode_stability(ctor_def_id); diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 77a01aac7395..1714398f2fed 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -21,7 +21,6 @@ use ParentLink::{ModuleParentLink, BlockParentLink}; use Resolver; use {resolve_error, resolve_struct_error, ResolutionError}; -use rustc::middle::cstore::ChildItem; use rustc::hir::def::*; use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId}; use rustc::hir::map::DefPathData; @@ -387,10 +386,22 @@ impl<'b> Resolver<'b> { } /// Builds the reduced graph for a single item in an external crate. - fn build_reduced_graph_for_external_crate_def(&mut self, parent: Module<'b>, child: ChildItem) { - let def = child.def; + fn build_reduced_graph_for_external_crate_def(&mut self, parent: Module<'b>, + child: Export) { + let def_id = child.def_id; let name = child.name; - let vis = if parent.is_trait() { ty::Visibility::Public } else { child.vis }; + + let def = if let Some(def) = self.session.cstore.describe_def(def_id) { + def + } else { + return; + }; + + let vis = if parent.is_trait() { + ty::Visibility::Public + } else { + self.session.cstore.visibility(def_id) + }; match def { Def::Mod(_) | Def::Enum(..) => { @@ -416,7 +427,7 @@ impl<'b> Resolver<'b> { name); let _ = self.try_define(parent, name, ValueNS, (def, DUMMY_SP, vis)); } - Def::Trait(def_id) => { + Def::Trait(_) => { debug!("(building reduced graph for external crate) building type {}", name); // If this is a trait, add all the trait item names to the trait @@ -443,7 +454,7 @@ impl<'b> Resolver<'b> { debug!("(building reduced graph for external crate) building type {}", name); let _ = self.try_define(parent, name, TypeNS, (def, DUMMY_SP, vis)); } - Def::Struct(def_id) + Def::Struct(_) if self.session.cstore.def_key(def_id).disambiguated_data.data != DefPathData::StructCtor => { @@ -459,7 +470,7 @@ impl<'b> Resolver<'b> { let fields = self.session.cstore.struct_field_names(def_id); self.structs.insert(def_id, fields); } - Def::Union(def_id) => { + Def::Union(_) => { let _ = self.try_define(parent, name, TypeNS, (def, DUMMY_SP, vis)); // Record the def ID and fields of this union. diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index 7ec491807023..34bcd2ba046e 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -451,27 +451,27 @@ pub fn all_traits<'a>(ccx: &'a CrateCtxt) -> AllTraits<'a> { fn handle_external_def(ccx: &CrateCtxt, traits: &mut AllTraitsVec, external_mods: &mut FnvHashSet, - def: Def) { - match def { - Def::Trait(did) => { - traits.push(TraitInfo::new(did)); + def_id: DefId) { + match ccx.tcx.sess.cstore.describe_def(def_id) { + Some(Def::Trait(_)) => { + traits.push(TraitInfo::new(def_id)); } - Def::Mod(did) => { - if !external_mods.insert(did) { + Some(Def::Mod(_)) => { + if !external_mods.insert(def_id) { return; } - for child in ccx.tcx.sess.cstore.item_children(did) { - handle_external_def(ccx, traits, external_mods, child.def) + for child in ccx.tcx.sess.cstore.item_children(def_id) { + handle_external_def(ccx, traits, external_mods, child.def_id) } } _ => {} } } for cnum in ccx.tcx.sess.cstore.crates() { - handle_external_def(ccx, &mut traits, &mut external_mods, Def::Mod(DefId { + handle_external_def(ccx, &mut traits, &mut external_mods, DefId { krate: cnum, index: CRATE_DEF_INDEX - })); + }); } *ccx.all_traits.borrow_mut() = Some(traits); diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 855b135b8636..c4d6ff43eff0 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -498,10 +498,12 @@ fn build_module<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>, // visit each node at most once. let mut visited = FnvHashSet(); for item in tcx.sess.cstore.item_children(did) { - if item.vis == ty::Visibility::Public { - if !visited.insert(item.def) { continue } - if let Some(i) = try_inline_def(cx, tcx, item.def) { - items.extend(i) + if tcx.sess.cstore.visibility(item.def_id) == ty::Visibility::Public { + if !visited.insert(item.def_id) { continue } + if let Some(def) = tcx.sess.cstore.describe_def(item.def_id) { + if let Some(i) = try_inline_def(cx, tcx, def) { + items.extend(i) + } } } } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 0acf211a27c5..9f208b7bed70 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -240,11 +240,7 @@ impl Clean for CrateNum { let root = DefId { krate: self.0, index: CRATE_DEF_INDEX }; cx.tcx_opt().map(|tcx| { for item in tcx.sess.cstore.item_children(root) { - let did = match item.def { - Def::Mod(did) => did, - _ => continue - }; - let attrs = inline::load_attrs(cx, tcx, did); + let attrs = inline::load_attrs(cx, tcx, item.def_id); PrimitiveType::find(&attrs).map(|prim| primitives.push(prim)); } }); diff --git a/src/librustdoc/visit_lib.rs b/src/librustdoc/visit_lib.rs index d93ca75a8da0..285b47fe60ab 100644 --- a/src/librustdoc/visit_lib.rs +++ b/src/librustdoc/visit_lib.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use rustc::middle::cstore::{CrateStore, ChildItem}; +use rustc::middle::cstore::CrateStore; use rustc::middle::privacy::{AccessLevels, AccessLevel}; use rustc::hir::def::Def; use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId}; @@ -64,38 +64,27 @@ impl<'a, 'b, 'tcx> LibEmbargoVisitor<'a, 'b, 'tcx> { } } - pub fn visit_mod(&mut self, did: DefId) { - for item in self.cstore.item_children(did) { - match item.def { - Def::Mod(did) | - Def::Trait(did) | - Def::Struct(did) | - Def::Union(did) | - Def::Enum(did) | - Def::TyAlias(did) | - Def::Fn(did) | - Def::Method(did) | - Def::Static(did, _) | - Def::Const(did) => self.visit_item(did, item), - _ => {} - } + pub fn visit_mod(&mut self, def_id: DefId) { + for item in self.cstore.item_children(def_id) { + self.visit_item(item.def_id); } } - fn visit_item(&mut self, did: DefId, item: ChildItem) { - let inherited_item_level = if item.vis == Visibility::Public { + fn visit_item(&mut self, def_id: DefId) { + let vis = self.cstore.visibility(def_id); + let inherited_item_level = if vis == Visibility::Public { self.prev_level } else { None }; - let item_level = self.update(did, inherited_item_level); + let item_level = self.update(def_id, inherited_item_level); - if let Def::Mod(did) = item.def { + if let Some(Def::Mod(_)) = self.cstore.describe_def(def_id) { let orig_level = self.prev_level; self.prev_level = item_level; - self.visit_mod(did); + self.visit_mod(def_id); self.prev_level = orig_level; } } From a96abca2a4ec14df912b7ebee69dbeac19d630c4 Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Fri, 16 Sep 2016 17:25:54 +0300 Subject: [PATCH 428/443] rustc_metadata: replace RBML with a simple and type-safe scheme. --- src/librustc/middle/cstore.rs | 8 +- src/librustc/ty/mod.rs | 5 +- src/librustc_metadata/Cargo.toml | 1 - src/librustc_metadata/astencode.rs | 221 ++- src/librustc_metadata/common.rs | 206 --- src/librustc_metadata/creader.rs | 211 +-- src/librustc_metadata/csearch.rs | 19 +- src/librustc_metadata/cstore.rs | 69 +- src/librustc_metadata/decoder.rs | 963 ++++++------- src/librustc_metadata/encoder.rs | 1526 +++++++++++---------- src/librustc_metadata/index.rs | 118 +- src/librustc_metadata/index_builder.rs | 26 +- src/librustc_metadata/lib.rs | 13 +- src/librustc_metadata/loader.rs | 48 +- src/librustc_metadata/rbml/reader.rs | 411 ------ src/librustc_metadata/rbml/writer.rs | 134 -- src/librustc_metadata/schema.rs | 299 ++++ src/librustc_typeck/collect.rs | 13 + src/librustdoc/clean/mod.rs | 2 +- src/rustc/Cargo.lock | 1 - src/test/run-pass-fulldeps/issue-11881.rs | 6 +- 21 files changed, 1828 insertions(+), 2472 deletions(-) delete mode 100644 src/librustc_metadata/common.rs delete mode 100644 src/librustc_metadata/rbml/reader.rs delete mode 100644 src/librustc_metadata/rbml/writer.rs create mode 100644 src/librustc_metadata/schema.rs diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index dbbd5eca4832..658825d417e4 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -138,11 +138,11 @@ pub trait CrateStore<'tcx> { fn item_super_predicates<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> ty::GenericPredicates<'tcx>; fn item_generics<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) - -> &'tcx ty::Generics<'tcx>; + -> ty::Generics<'tcx>; fn item_attrs(&self, def_id: DefId) -> Vec; fn trait_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)-> ty::TraitDef<'tcx>; fn adt_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> ty::AdtDefMaster<'tcx>; - fn fn_arg_names(&self, did: DefId) -> Vec; + fn fn_arg_names(&self, did: DefId) -> Vec; fn inherent_implementations_for_type(&self, def_id: DefId) -> Vec; // trait info @@ -299,13 +299,13 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { fn item_super_predicates<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> ty::GenericPredicates<'tcx> { bug!("item_super_predicates") } fn item_generics<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) - -> &'tcx ty::Generics<'tcx> { bug!("item_generics") } + -> ty::Generics<'tcx> { bug!("item_generics") } fn item_attrs(&self, def_id: DefId) -> Vec { bug!("item_attrs") } fn trait_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)-> ty::TraitDef<'tcx> { bug!("trait_def") } fn adt_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> ty::AdtDefMaster<'tcx> { bug!("adt_def") } - fn fn_arg_names(&self, did: DefId) -> Vec { bug!("fn_arg_names") } + fn fn_arg_names(&self, did: DefId) -> Vec { bug!("fn_arg_names") } fn inherent_implementations_for_type(&self, def_id: DefId) -> Vec { vec![] } // trait info diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 8171a99beb90..8a9b2846ac66 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -737,6 +737,9 @@ pub struct GenericPredicates<'tcx> { pub predicates: Vec>, } +impl<'tcx> serialize::UseSpecializedEncodable for GenericPredicates<'tcx> {} +impl<'tcx> serialize::UseSpecializedDecodable for GenericPredicates<'tcx> {} + impl<'a, 'gcx, 'tcx> GenericPredicates<'tcx> { pub fn instantiate(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, substs: &Substs<'tcx>) -> InstantiatedPredicates<'tcx> { @@ -2457,7 +2460,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn lookup_generics(self, did: DefId) -> &'gcx Generics<'gcx> { lookup_locally_or_in_crate_store( "generics", did, &self.generics, - || self.sess.cstore.item_generics(self.global_tcx(), did)) + || self.alloc_generics(self.sess.cstore.item_generics(self.global_tcx(), did))) } /// Given the did of an item, returns its full set of predicates. diff --git a/src/librustc_metadata/Cargo.toml b/src/librustc_metadata/Cargo.toml index fede6f663418..680d55955bb9 100644 --- a/src/librustc_metadata/Cargo.toml +++ b/src/librustc_metadata/Cargo.toml @@ -13,7 +13,6 @@ flate = { path = "../libflate" } log = { path = "../liblog" } rustc = { path = "../librustc" } rustc_back = { path = "../librustc_back" } -rustc_bitflags = { path = "../librustc_bitflags" } rustc_const_math = { path = "../librustc_const_math" } rustc_data_structures = { path = "../librustc_data_structures" } rustc_errors = { path = "../librustc_errors" } diff --git a/src/librustc_metadata/astencode.rs b/src/librustc_metadata/astencode.rs index f48c31fc2f9d..c9dbedacbc1a 100644 --- a/src/librustc_metadata/astencode.rs +++ b/src/librustc_metadata/astencode.rs @@ -13,43 +13,92 @@ use rustc::hir::map as ast_map; use rustc::hir::intravisit::{Visitor, IdRangeComputingVisitor, IdRange}; use cstore::CrateMetadata; -use decoder::DecodeContext; use encoder::EncodeContext; +use schema::*; use rustc::middle::cstore::{InlinedItem, InlinedItemRef}; -use rustc::hir::def; +use rustc::middle::const_qualif::ConstQualif; +use rustc::hir::def::{self, Def}; use rustc::hir::def_id::DefId; -use rustc::ty::TyCtxt; +use rustc::ty::{self, TyCtxt, Ty}; use syntax::ast; -use rbml; -use rustc_serialize::{Decodable, Encodable}; +use rustc_serialize::Encodable; -// ______________________________________________________________________ -// Top-level methods. +#[derive(RustcEncodable, RustcDecodable)] +pub struct Ast<'tcx> { + id_range: IdRange, + item: Lazy, + side_tables: LazySeq<(ast::NodeId, TableEntry<'tcx>)> +} -pub fn encode_inlined_item(ecx: &mut EncodeContext, ii: InlinedItemRef) { - ecx.tag(::common::item_tag::ast, |ecx| { - let mut visitor = IdRangeComputingVisitor::new(); +#[derive(RustcEncodable, RustcDecodable)] +enum TableEntry<'tcx> { + Def(Def), + NodeType(Ty<'tcx>), + ItemSubsts(ty::ItemSubsts<'tcx>), + Adjustment(ty::adjustment::AutoAdjustment<'tcx>), + ConstQualif(ConstQualif) +} + +impl<'a, 'tcx> EncodeContext<'a, 'tcx> { + pub fn encode_inlined_item(&mut self, ii: InlinedItemRef) -> Lazy> { + let mut id_visitor = IdRangeComputingVisitor::new(); match ii { - InlinedItemRef::Item(_, i) => visitor.visit_item(i), - InlinedItemRef::TraitItem(_, ti) => visitor.visit_trait_item(ti), - InlinedItemRef::ImplItem(_, ii) => visitor.visit_impl_item(ii) + InlinedItemRef::Item(_, i) => id_visitor.visit_item(i), + InlinedItemRef::TraitItem(_, ti) => id_visitor.visit_trait_item(ti), + InlinedItemRef::ImplItem(_, ii) => id_visitor.visit_impl_item(ii) } - visitor.result().encode(ecx).unwrap(); - ii.encode(ecx).unwrap(); + let ii_pos = self.position(); + ii.encode(self).unwrap(); - let mut visitor = SideTableEncodingIdVisitor { - ecx: ecx + let tables_pos = self.position(); + let tables_count = { + let mut visitor = SideTableEncodingIdVisitor { + ecx: self, + count: 0 + }; + match ii { + InlinedItemRef::Item(_, i) => visitor.visit_item(i), + InlinedItemRef::TraitItem(_, ti) => visitor.visit_trait_item(ti), + InlinedItemRef::ImplItem(_, ii) => visitor.visit_impl_item(ii) + } + visitor.count }; - match ii { - InlinedItemRef::Item(_, i) => visitor.visit_item(i), - InlinedItemRef::TraitItem(_, ti) => visitor.visit_trait_item(ti), - InlinedItemRef::ImplItem(_, ii) => visitor.visit_impl_item(ii) - } - }); + + self.lazy(&Ast { + id_range: id_visitor.result(), + item: Lazy::with_position(ii_pos), + side_tables: LazySeq::with_position_and_length(tables_pos, tables_count) + }) + } +} + +struct SideTableEncodingIdVisitor<'a, 'b:'a, 'tcx:'b> { + ecx: &'a mut EncodeContext<'b, 'tcx>, + count: usize +} + +impl<'a, 'b, 'tcx, 'v> Visitor<'v> for SideTableEncodingIdVisitor<'a, 'b, 'tcx> { + fn visit_id(&mut self, id: ast::NodeId) { + debug!("Encoding side tables for id {}", id); + + let tcx = self.ecx.tcx; + let mut encode = |entry: Option| { + if let Some(entry) = entry { + (id, entry).encode(self.ecx).unwrap(); + self.count += 1; + } + }; + + encode(tcx.expect_def_or_none(id).map(TableEntry::Def)); + encode(tcx.node_types().get(&id).cloned().map(TableEntry::NodeType)); + encode(tcx.tables.borrow().item_substs.get(&id).cloned().map(TableEntry::ItemSubsts)); + encode(tcx.tables.borrow().adjustments.get(&id).cloned().map(TableEntry::Adjustment)); + encode(tcx.const_qualif_map.borrow().get(&id).cloned().map(TableEntry::ConstQualif)); + } } /// Decodes an item from its AST in the cdata's metadata and adds it to the @@ -58,17 +107,19 @@ pub fn decode_inlined_item<'a, 'tcx>(cdata: &CrateMetadata, tcx: TyCtxt<'a, 'tcx, 'tcx>, parent_def_path: ast_map::DefPath, parent_did: DefId, - ast_doc: rbml::Doc, + ast: Ast<'tcx>, orig_did: DefId) -> &'tcx InlinedItem { debug!("> Decoding inlined fn: {:?}", tcx.item_path_str(orig_did)); - let dcx = &mut DecodeContext::new(ast_doc, Some(cdata)).typed(tcx); - dcx.from_id_range = IdRange::decode(dcx).unwrap(); - let cnt = dcx.from_id_range.max.as_usize() - dcx.from_id_range.min.as_usize(); - dcx.to_id_range.min = tcx.sess.reserve_node_ids(cnt); - dcx.to_id_range.max = ast::NodeId::new(dcx.to_id_range.min.as_usize() + cnt); - let ii = InlinedItem::decode(dcx).unwrap(); + let cnt = ast.id_range.max.as_usize() - ast.id_range.min.as_usize(); + let start = tcx.sess.reserve_node_ids(cnt); + let id_ranges = [ast.id_range, IdRange { + min: start, + max: ast::NodeId::new(start.as_usize() + cnt) + }]; + + let ii = ast.item.decode((cdata, tcx, id_ranges)); let ii = ast_map::map_decoded_item(&tcx.map, parent_def_path, parent_did, @@ -83,107 +134,25 @@ pub fn decode_inlined_item<'a, 'tcx>(cdata: &CrateMetadata, let inlined_did = tcx.map.local_def_id(item_node_id); tcx.register_item_type(inlined_did, tcx.lookup_item_type(orig_did)); - decode_side_tables(dcx, ast_doc); - - ii -} - -// ______________________________________________________________________ -// Encoding and decoding the side tables - -impl<'a, 'tcx> EncodeContext<'a, 'tcx> { - fn tag(&mut self, - tag_id: usize, - f: F) where - F: FnOnce(&mut Self), - { - self.start_tag(tag_id).unwrap(); - f(self); - self.end_tag().unwrap(); - } - - fn entry(&mut self, table: Table, id: ast::NodeId) { - table.encode(self).unwrap(); - id.encode(self).unwrap(); - } -} - -struct SideTableEncodingIdVisitor<'a, 'b:'a, 'tcx:'b> { - ecx: &'a mut EncodeContext<'b, 'tcx>, -} - -impl<'a, 'b, 'tcx, 'v> Visitor<'v> for SideTableEncodingIdVisitor<'a, 'b, 'tcx> { - fn visit_id(&mut self, id: ast::NodeId) { - encode_side_tables_for_id(self.ecx, id) - } -} - -#[derive(RustcEncodable, RustcDecodable, Debug)] -enum Table { - Def, - NodeType, - ItemSubsts, - Adjustment, - ConstQualif -} - -fn encode_side_tables_for_id(ecx: &mut EncodeContext, id: ast::NodeId) { - let tcx = ecx.tcx; - - debug!("Encoding side tables for id {}", id); - - if let Some(def) = tcx.expect_def_or_none(id) { - ecx.entry(Table::Def, id); - def.encode(ecx).unwrap(); - } - - if let Some(ty) = tcx.node_types().get(&id) { - ecx.entry(Table::NodeType, id); - ty.encode(ecx).unwrap(); - } - - if let Some(item_substs) = tcx.tables.borrow().item_substs.get(&id) { - ecx.entry(Table::ItemSubsts, id); - item_substs.substs.encode(ecx).unwrap(); - } - - if let Some(adjustment) = tcx.tables.borrow().adjustments.get(&id) { - ecx.entry(Table::Adjustment, id); - adjustment.encode(ecx).unwrap(); - } - - if let Some(qualif) = tcx.const_qualif_map.borrow().get(&id) { - ecx.entry(Table::ConstQualif, id); - qualif.encode(ecx).unwrap(); - } -} - -fn decode_side_tables(dcx: &mut DecodeContext, ast_doc: rbml::Doc) { - while dcx.opaque.position() < ast_doc.end { - let table = Decodable::decode(dcx).unwrap(); - let id = Decodable::decode(dcx).unwrap(); - debug!("decode_side_tables: entry for id={}, table={:?}", id, table); - match table { - Table::Def => { - let def = Decodable::decode(dcx).unwrap(); - dcx.tcx().def_map.borrow_mut().insert(id, def::PathResolution::new(def)); + for (id, entry) in ast.side_tables.decode((cdata, tcx, id_ranges)) { + match entry { + TableEntry::Def(def) => { + tcx.def_map.borrow_mut().insert(id, def::PathResolution::new(def)); } - Table::NodeType => { - let ty = Decodable::decode(dcx).unwrap(); - dcx.tcx().node_type_insert(id, ty); + TableEntry::NodeType(ty) => { + tcx.node_type_insert(id, ty); } - Table::ItemSubsts => { - let item_substs = Decodable::decode(dcx).unwrap(); - dcx.tcx().tables.borrow_mut().item_substs.insert(id, item_substs); + TableEntry::ItemSubsts(item_substs) => { + tcx.tables.borrow_mut().item_substs.insert(id, item_substs); } - Table::Adjustment => { - let adj = Decodable::decode(dcx).unwrap(); - dcx.tcx().tables.borrow_mut().adjustments.insert(id, adj); + TableEntry::Adjustment(adj) => { + tcx.tables.borrow_mut().adjustments.insert(id, adj); } - Table::ConstQualif => { - let qualif = Decodable::decode(dcx).unwrap(); - dcx.tcx().const_qualif_map.borrow_mut().insert(id, qualif); + TableEntry::ConstQualif(qualif) => { + tcx.const_qualif_map.borrow_mut().insert(id, qualif); } } } + + ii } diff --git a/src/librustc_metadata/common.rs b/src/librustc_metadata/common.rs deleted file mode 100644 index f30551cadd97..000000000000 --- a/src/librustc_metadata/common.rs +++ /dev/null @@ -1,206 +0,0 @@ -// 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. - -#![allow(non_camel_case_types, non_upper_case_globals)] - -use rustc::hir; -use rustc::hir::def; -use rustc::hir::def_id::{DefIndex, DefId}; -use rustc::ty; -use rustc::session::config::PanicStrategy; - -#[derive(Clone, Copy, Debug, PartialEq, RustcEncodable, RustcDecodable)] -pub enum Family { - ImmStatic, - MutStatic, - ForeignImmStatic, - ForeignMutStatic, - Fn, - ForeignFn, - Method, - AssociatedType, - Type, - Mod, - ForeignMod, - Enum, - Variant, - Impl, - DefaultImpl, - Trait, - Struct, - Union, - Field, - Const, - AssociatedConst, - Closure -} - -// NB: increment this if you change the format of metadata such that -// rustc_version can't be found. -pub const metadata_encoding_version : &'static [u8] = &[b'r', b'u', b's', b't', 0, 0, 0, 2]; - -// GAP 0x7c -// GAP 0x108 -pub fn rustc_version() -> String { - format!( - "rustc {}", - option_env!("CFG_VERSION").unwrap_or("unknown version") - ) -} - -#[derive(RustcEncodable, RustcDecodable)] -pub struct CrateInfo { - pub name: String, - pub triple: String, - pub hash: hir::svh::Svh, - pub disambiguator: String, - pub panic_strategy: PanicStrategy, - pub plugin_registrar_fn: Option, - pub macro_derive_registrar: Option -} - -pub mod root_tag { - pub const rustc_version: usize = 0x10f; - - pub const crate_info: usize = 0x104; - - pub const index: usize = 0x110; - pub const crate_deps: usize = 0x102; - pub const dylib_dependency_formats: usize = 0x106; - pub const native_libraries: usize = 0x10a; - pub const lang_items: usize = 0x107; - pub const lang_items_missing: usize = 0x76; - pub const impls: usize = 0x109; - pub const reachable_ids: usize = 0x10c; - pub const macro_defs: usize = 0x10e; - pub const codemap: usize = 0xa1; -} - -#[derive(RustcEncodable, RustcDecodable)] -pub struct ModData { - pub reexports: Vec -} - -#[derive(RustcEncodable, RustcDecodable)] -pub struct VariantData { - pub kind: ty::VariantKind, - pub disr: u64, - - /// If this is a struct's only variant, this - /// is the index of the "struct ctor" item. - pub struct_ctor: Option -} - -#[derive(RustcEncodable, RustcDecodable)] -pub struct TraitData { - pub unsafety: hir::Unsafety, - pub paren_sugar: bool, - pub has_default_impl: bool -} - -#[derive(RustcEncodable, RustcDecodable)] -pub struct ImplData { - pub polarity: hir::ImplPolarity, - pub parent_impl: Option, - pub coerce_unsized_kind: Option, -} - -#[derive(RustcEncodable, RustcDecodable)] -pub struct TraitAssociatedData { - pub has_default: bool -} - -#[derive(RustcEncodable, RustcDecodable)] -pub struct ImplAssociatedData { - pub defaultness: hir::Defaultness, - pub constness: hir::Constness -} - -#[derive(RustcEncodable, RustcDecodable)] -pub struct FnData { - pub constness: hir::Constness -} - -#[derive(RustcEncodable, RustcDecodable)] -pub struct ClosureData { - pub kind: ty::ClosureKind -} - -#[derive(RustcEncodable, RustcDecodable)] -pub enum EntryData { - Other, - Mod(ModData), - Variant(VariantData), - Trait(TraitData), - Impl(ImplData), - TraitAssociated(TraitAssociatedData), - ImplAssociated(ImplAssociatedData), - Fn(FnData), - Closure(ClosureData) -} - -#[derive(RustcEncodable, RustcDecodable)] -pub struct TraitTypedData<'tcx> { - pub trait_ref: ty::TraitRef<'tcx> -} - -#[derive(RustcEncodable, RustcDecodable)] -pub struct ImplTypedData<'tcx> { - pub trait_ref: Option> -} - -#[derive(RustcEncodable, RustcDecodable)] -pub struct MethodTypedData<'tcx> { - pub explicit_self: ty::ExplicitSelfCategory<'tcx> -} - -#[derive(RustcEncodable, RustcDecodable)] -pub struct ClosureTypedData<'tcx> { - pub ty: ty::ClosureTy<'tcx> -} - -#[derive(RustcEncodable, RustcDecodable)] -pub enum EntryTypedData<'tcx> { - Other, - Trait(TraitTypedData<'tcx>), - Impl(ImplTypedData<'tcx>), - Method(MethodTypedData<'tcx>), - Closure(ClosureTypedData<'tcx>) -} - -pub mod item_tag { - pub const def_key: usize = 0x2c; - pub const family: usize = 0x24; - pub const attributes: usize = 0x101; - pub const visibility: usize = 0x78; - pub const children: usize = 0x7b; - pub const stability: usize = 0x88; - pub const deprecation: usize = 0xa7; - - pub const ty: usize = 0x25; - pub const inherent_impls: usize = 0x79; - pub const variances: usize = 0x43; - pub const generics: usize = 0x8f; - pub const predicates: usize = 0x95; - pub const super_predicates: usize = 0xa3; - - pub const ast: usize = 0x50; - pub const mir: usize = 0x52; - - pub const data: usize = 0x3c; - pub const typed_data: usize = 0x3d; - - pub const fn_arg_names: usize = 0x85; -} - -/// The shorthand encoding uses an enum's variant index `usize` -/// and is offset by this value so it never matches a real variant. -/// This offset is also chosen so that the first byte is never < 0x80. -pub const SHORTHAND_OFFSET: usize = 0x80; diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 77a583f7379c..95be77c24f46 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -8,13 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![allow(non_camel_case_types)] - //! Validates all used crates and extern libraries and loads their metadata -use common::CrateInfo; use cstore::{self, CStore, CrateSource, MetadataBlob}; use loader::{self, CratePaths}; +use schema::CrateRoot; use rustc::hir::def_id::{CrateNum, DefIndex}; use rustc::hir::svh::Svh; @@ -34,12 +32,11 @@ use std::fs; use syntax::ast; use syntax::abi::Abi; -use syntax::codemap; use syntax::parse; use syntax::attr; use syntax::parse::token::InternedString; use syntax::visit; -use syntax_pos::{self, Span, mk_sp, Pos}; +use syntax_pos::{self, Span, mk_sp}; use log; struct LocalCrateReader<'a> { @@ -148,7 +145,7 @@ impl Deref for PMDSource { fn deref(&self) -> &MetadataBlob { match *self { - PMDSource::Registered(ref cmd) => &cmd.data, + PMDSource::Registered(ref cmd) => &cmd.blob, PMDSource::Owned(ref lib) => &lib.metadata } } @@ -261,28 +258,28 @@ impl<'a> CrateReader<'a> { fn verify_no_symbol_conflicts(&self, span: Span, - info: &CrateInfo) { + root: &CrateRoot) { // Check for (potential) conflicts with the local crate - if self.local_crate_name == info.name && - self.sess.local_crate_disambiguator() == &info.disambiguator[..] { + if self.local_crate_name == root.name && + self.sess.local_crate_disambiguator() == &root.disambiguator[..] { span_fatal!(self.sess, span, E0519, "the current crate is indistinguishable from one of its \ dependencies: it has the same crate-name `{}` and was \ compiled with the same `-C metadata` arguments. This \ will result in symbol conflicts between the two.", - info.name) + root.name) } // Check for conflicts with any crate loaded so far self.cstore.iter_crate_data(|_, other| { - if other.name() == info.name && // same crate-name - other.disambiguator() == info.disambiguator && // same crate-disambiguator - other.hash() != info.hash { // but different SVH + if other.name() == root.name && // same crate-name + other.disambiguator() == root.disambiguator && // same crate-disambiguator + other.hash() != root.hash { // but different SVH span_fatal!(self.sess, span, E0523, "found two different crates with name `{}` that are \ not distinguished by differing `-C metadata`. This \ will result in symbol conflicts between the two.", - info.name) + root.name) } }); } @@ -297,8 +294,8 @@ impl<'a> CrateReader<'a> { -> (CrateNum, Rc, cstore::CrateSource) { info!("register crate `extern crate {} as {}`", name, ident); - let crate_info = lib.metadata.get_crate_info(); - self.verify_no_symbol_conflicts(span, &crate_info); + let crate_root = lib.metadata.get_root(); + self.verify_no_symbol_conflicts(span, &crate_root); // Claim this crate number and cache it let cnum = self.next_crate_num; @@ -319,9 +316,9 @@ impl<'a> CrateReader<'a> { let loader::Library { dylib, rlib, metadata } = lib; - let cnum_map = self.resolve_crate_deps(root, &metadata, cnum, span); + let cnum_map = self.resolve_crate_deps(root, &crate_root, &metadata, cnum, span); - if crate_info.macro_derive_registrar.is_some() { + if crate_root.macro_derive_registrar.is_some() { self.sess.span_err(span, "crates of the `rustc-macro` crate type \ cannot be linked at runtime"); } @@ -329,10 +326,9 @@ impl<'a> CrateReader<'a> { let cmeta = Rc::new(cstore::CrateMetadata { name: name.to_string(), extern_crate: Cell::new(None), - info: crate_info, - index: metadata.load_index(), - key_map: metadata.load_key_map(), - data: metadata, + key_map: metadata.load_key_map(crate_root.index), + root: crate_root, + blob: metadata, cnum_map: RefCell::new(cnum_map), cnum: cnum, codemap_import_info: RefCell::new(vec![]), @@ -416,11 +412,11 @@ impl<'a> CrateReader<'a> { // Note that we only do this for target triple crates, though, as we // don't want to match a host crate against an equivalent target one // already loaded. - let crate_info = library.metadata.get_crate_info(); + let root = library.metadata.get_root(); if loader.triple == self.sess.opts.target_triple { let mut result = LoadResult::Loaded(library); self.cstore.iter_crate_data(|cnum, data| { - if data.name() == crate_info.name && crate_info.hash == data.hash() { + if data.name() == root.name && root.hash == data.hash() { assert!(loader.hash.is_none()); info!("load success, going to previous cnum: {}", cnum); result = LoadResult::Previous(cnum); @@ -467,6 +463,7 @@ impl<'a> CrateReader<'a> { // Go through the crate metadata and load any crates that it references fn resolve_crate_deps(&mut self, root: &Option, + crate_root: &CrateRoot, metadata: &MetadataBlob, krate: CrateNum, span: Span) @@ -474,16 +471,17 @@ impl<'a> CrateReader<'a> { debug!("resolving deps of external crate"); // The map from crate numbers in the crate we're resolving to local crate // numbers - let map: FnvHashMap<_, _> = metadata.get_crate_deps().iter().map(|dep| { + let deps = crate_root.crate_deps.decode(metadata); + let map: FnvHashMap<_, _> = deps.enumerate().map(|(crate_num, dep)| { debug!("resolving dep crate {} hash: `{}`", dep.name, dep.hash); let (local_cnum, ..) = self.resolve_crate(root, - &dep.name, - &dep.name, + &dep.name.as_str(), + &dep.name.as_str(), Some(&dep.hash), span, PathKind::Dependency, dep.explicitly_linked); - (dep.cnum, local_cnum) + (CrateNum::new(crate_num + 1), local_cnum) }).collect(); let max_cnum = map.values().cloned().max().map(|cnum| cnum.as_u32()).unwrap_or(0); @@ -568,21 +566,21 @@ impl<'a> CrateReader<'a> { let ci = self.extract_crate_info(item).unwrap(); let ekrate = self.read_extension_crate(item.span, &ci); - let crate_info = ekrate.metadata.get_crate_info(); + let root = ekrate.metadata.get_root(); let source_name = format!("<{} macros>", item.ident); let mut ret = Macros { macro_rules: Vec::new(), custom_derive_registrar: None, - svh: crate_info.hash, + svh: root.hash, dylib: None, }; - ekrate.metadata.each_exported_macro(|name, attrs, span, body| { + for def in root.macro_defs.decode(&*ekrate.metadata) { // NB: Don't use parse::parse_tts_from_source_str because it parses with // quote_depth > 0. let mut p = parse::new_parser_from_source_str(&self.sess.parse_sess, self.local_crate_config.clone(), source_name.clone(), - body); + def.body); let lo = p.span.lo; let body = match p.parse_all_token_trees() { Ok(body) => body, @@ -595,13 +593,13 @@ impl<'a> CrateReader<'a> { let local_span = mk_sp(lo, p.last_span.hi); // Mark the attrs as used - for attr in &attrs { + for attr in &def.attrs { attr::mark_used(attr); } ret.macro_rules.push(ast::MacroDef { - ident: ast::Ident::with_empty_ctxt(name), - attrs: attrs, + ident: ast::Ident::with_empty_ctxt(def.name), + attrs: def.attrs, id: ast::DUMMY_NODE_ID, span: local_span, imported_from: Some(item.ident), @@ -613,11 +611,10 @@ impl<'a> CrateReader<'a> { body: body, }); self.sess.imported_macro_spans.borrow_mut() - .insert(local_span, (name.as_str().to_string(), span)); - true - }); + .insert(local_span, (def.name.as_str().to_string(), def.span)); + } - match crate_info.macro_derive_registrar { + match root.macro_derive_registrar { Some(id) => ret.custom_derive_registrar = Some(id), // If this crate is not a rustc-macro crate then we might be able to @@ -671,10 +668,10 @@ impl<'a> CrateReader<'a> { span_fatal!(self.sess, span, E0456, "{}", &message[..]); } - let crate_info = ekrate.metadata.get_crate_info(); - match (ekrate.dylib.as_ref(), crate_info.plugin_registrar_fn) { + let root = ekrate.metadata.get_root(); + match (ekrate.dylib.as_ref(), root.plugin_registrar_fn) { (Some(dylib), Some(reg)) => { - Some((dylib.to_path_buf(), crate_info.hash, reg)) + Some((dylib.to_path_buf(), root.hash, reg)) } (None, Some(_)) => { span_err!(self.sess, span, E0457, @@ -1086,133 +1083,3 @@ pub fn read_local_crates(sess: & Session, dep_graph: &DepGraph) { LocalCrateReader::new(sess, cstore, defs, krate, local_crate_name).read_crates(dep_graph) } - -/// Imports the codemap from an external crate into the codemap of the crate -/// currently being compiled (the "local crate"). -/// -/// The import algorithm works analogous to how AST items are inlined from an -/// external crate's metadata: -/// For every FileMap in the external codemap an 'inline' copy is created in the -/// local codemap. The correspondence relation between external and local -/// FileMaps is recorded in the `ImportedFileMap` objects returned from this -/// function. When an item from an external crate is later inlined into this -/// crate, this correspondence information is used to translate the span -/// information of the inlined item so that it refers the correct positions in -/// the local codemap (see `>`). -/// -/// The import algorithm in the function below will reuse FileMaps already -/// existing in the local codemap. For example, even if the FileMap of some -/// source file of libstd gets imported many times, there will only ever be -/// one FileMap object for the corresponding file in the local codemap. -/// -/// Note that imported FileMaps do not actually contain the source code of the -/// file they represent, just information about length, line breaks, and -/// multibyte characters. This information is enough to generate valid debuginfo -/// for items inlined from other crates. -pub fn import_codemap(local_codemap: &codemap::CodeMap, - metadata: &MetadataBlob) - -> Vec { - let external_codemap = metadata.get_imported_filemaps(); - - let imported_filemaps = external_codemap.into_iter().map(|filemap_to_import| { - // Try to find an existing FileMap that can be reused for the filemap to - // be imported. A FileMap is reusable if it is exactly the same, just - // positioned at a different offset within the codemap. - let reusable_filemap = { - local_codemap.files - .borrow() - .iter() - .find(|fm| are_equal_modulo_startpos(&fm, &filemap_to_import)) - .map(|rc| rc.clone()) - }; - - match reusable_filemap { - Some(fm) => { - cstore::ImportedFileMap { - original_start_pos: filemap_to_import.start_pos, - original_end_pos: filemap_to_import.end_pos, - translated_filemap: fm - } - } - None => { - // We can't reuse an existing FileMap, so allocate a new one - // containing the information we need. - let syntax_pos::FileMap { - name, - abs_path, - start_pos, - end_pos, - lines, - multibyte_chars, - .. - } = filemap_to_import; - - let source_length = (end_pos - start_pos).to_usize(); - - // Translate line-start positions and multibyte character - // position into frame of reference local to file. - // `CodeMap::new_imported_filemap()` will then translate those - // coordinates to their new global frame of reference when the - // offset of the FileMap is known. - let mut lines = lines.into_inner(); - for pos in &mut lines { - *pos = *pos - start_pos; - } - let mut multibyte_chars = multibyte_chars.into_inner(); - for mbc in &mut multibyte_chars { - mbc.pos = mbc.pos - start_pos; - } - - let local_version = local_codemap.new_imported_filemap(name, - abs_path, - source_length, - lines, - multibyte_chars); - cstore::ImportedFileMap { - original_start_pos: start_pos, - original_end_pos: end_pos, - translated_filemap: local_version - } - } - } - }).collect(); - - return imported_filemaps; - - fn are_equal_modulo_startpos(fm1: &syntax_pos::FileMap, - fm2: &syntax_pos::FileMap) - -> bool { - if fm1.name != fm2.name { - return false; - } - - let lines1 = fm1.lines.borrow(); - let lines2 = fm2.lines.borrow(); - - if lines1.len() != lines2.len() { - return false; - } - - for (&line1, &line2) in lines1.iter().zip(lines2.iter()) { - if (line1 - fm1.start_pos) != (line2 - fm2.start_pos) { - return false; - } - } - - let multibytes1 = fm1.multibyte_chars.borrow(); - let multibytes2 = fm2.multibyte_chars.borrow(); - - if multibytes1.len() != multibytes2.len() { - return false; - } - - for (mb1, mb2) in multibytes1.iter().zip(multibytes2.iter()) { - if (mb1.bytes != mb2.bytes) || - ((mb1.pos - fm1.start_pos) != (mb2.pos - fm2.start_pos)) { - return false; - } - } - - true - } -} diff --git a/src/librustc_metadata/csearch.rs b/src/librustc_metadata/csearch.rs index 8569dbcd5073..f508c5dc9cfb 100644 --- a/src/librustc_metadata/csearch.rs +++ b/src/librustc_metadata/csearch.rs @@ -9,9 +9,9 @@ // except according to those terms. use cstore; -use common; use encoder; use loader; +use schema; use rustc::middle::cstore::{InlinedItem, CrateStore, CrateSource, ExternCrate}; use rustc::middle::cstore::{NativeLibraryKind, LinkMeta, LinkagePreference}; @@ -97,7 +97,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { } fn item_generics<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) - -> &'tcx ty::Generics<'tcx> + -> ty::Generics<'tcx> { self.dep_graph.read(DepNode::MetaData(def)); self.get_crate_data(def.krate).get_generics(def.index, tcx) @@ -121,7 +121,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { self.get_crate_data(def.krate).get_adt_def(def.index, tcx) } - fn fn_arg_names(&self, did: DefId) -> Vec + fn fn_arg_names(&self, did: DefId) -> Vec { self.dep_graph.read(DepNode::MetaData(did)); self.get_crate_data(did.krate).get_fn_arg_names(did.index) @@ -140,10 +140,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { fn inherent_implementations_for_type(&self, def_id: DefId) -> Vec { self.dep_graph.read(DepNode::MetaData(def_id)); - let mut result = vec![]; - self.get_crate_data(def_id.krate) - .each_inherent_implementation_for_type(def_id.index, |iid| result.push(iid)); - result + self.get_crate_data(def_id.krate).get_inherent_implementations_for_type(def_id.index) } fn implementations_of_trait(&self, filter: Option) -> Vec @@ -153,9 +150,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { } let mut result = vec![]; self.iter_crate_data(|_, cdata| { - cdata.each_implementation_for_trait(filter, &mut |iid| { - result.push(iid) - }) + cdata.get_implementations_for_trait(filter, &mut result) }); result } @@ -308,7 +303,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { fn plugin_registrar_fn(&self, cnum: CrateNum) -> Option { - self.get_crate_data(cnum).info.plugin_registrar_fn.map(|index| DefId { + self.get_crate_data(cnum).root.plugin_registrar_fn.map(|index| DefId { krate: cnum, index: index }) @@ -552,7 +547,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { fn metadata_encoding_version(&self) -> &[u8] { - common::metadata_encoding_version + schema::METADATA_HEADER } /// Returns a map from a sufficiently visible external item (i.e. an external item that is diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs index 4151f98b3dae..0a1ff70a0497 100644 --- a/src/librustc_metadata/cstore.rs +++ b/src/librustc_metadata/cstore.rs @@ -11,12 +11,8 @@ // The crate store - a central repo for information collected about external // crates and libraries -pub use self::MetadataBlob::*; - -use common; -use creader; -use index; use loader; +use schema; use rustc::dep_graph::DepGraph; use rustc::hir::def_id::{CRATE_DEF_INDEX, CrateNum, DefIndex, DefId}; @@ -27,13 +23,12 @@ use rustc::session::config::PanicStrategy; use rustc_data_structures::indexed_vec::IndexVec; use rustc::util::nodemap::{FnvHashMap, NodeMap, NodeSet, DefIdMap, FnvHashSet}; -use std::cell::{RefCell, Ref, Cell}; +use std::cell::{RefCell, Cell}; use std::rc::Rc; use std::path::PathBuf; use flate::Bytes; use syntax::ast::{self, Ident}; use syntax::attr; -use syntax::codemap; use syntax_pos; pub use rustc::middle::cstore::{NativeLibraryKind, LinkagePreference}; @@ -47,12 +42,12 @@ pub use rustc::middle::cstore::{CrateSource, LinkMeta}; pub type CrateNumMap = IndexVec; pub enum MetadataBlob { - MetadataVec(Bytes), - MetadataArchive(loader::ArchiveMetadata), + Inflated(Bytes), + Archive(loader::ArchiveMetadata), } /// Holds information about a syntax_pos::FileMap imported from another crate. -/// See creader::import_codemap() for more information. +/// See `imported_filemaps()` for more information. pub struct ImportedFileMap { /// This FileMap's byte-offset within the codemap of its original crate pub original_start_pos: syntax_pos::BytePos, @@ -70,13 +65,12 @@ pub struct CrateMetadata { /// (e.g., by the allocator) pub extern_crate: Cell>, - pub data: MetadataBlob, + pub blob: MetadataBlob, pub cnum_map: RefCell, pub cnum: CrateNum, pub codemap_import_info: RefCell>, - pub info: common::CrateInfo, - pub index: index::Index, + pub root: schema::CrateRoot, /// For each public item in this crate, we encode a key. When the /// crate is loaded, we read all the keys and put them in this @@ -294,23 +288,9 @@ impl CStore { } impl CrateMetadata { - pub fn name(&self) -> &str { &self.info.name } - pub fn hash(&self) -> Svh { self.info.hash } - pub fn disambiguator(&self) -> &str { &self.info.disambiguator } - pub fn imported_filemaps<'a>(&'a self, codemap: &codemap::CodeMap) - -> Ref<'a, Vec> { - let filemaps = self.codemap_import_info.borrow(); - if filemaps.is_empty() { - drop(filemaps); - let filemaps = creader::import_codemap(codemap, &self.data); - - // This shouldn't borrow twice, but there is no way to downgrade RefMut to Ref. - *self.codemap_import_info.borrow_mut() = filemaps; - self.codemap_import_info.borrow() - } else { - filemaps - } - } + pub fn name(&self) -> &str { &self.root.name } + pub fn hash(&self) -> Svh { self.root.hash } + pub fn disambiguator(&self) -> &str { &self.root.disambiguator } pub fn is_staged_api(&self) -> bool { self.get_item_attrs(CRATE_DEF_INDEX).iter().any(|attr| { @@ -349,33 +329,6 @@ impl CrateMetadata { } pub fn panic_strategy(&self) -> PanicStrategy { - self.info.panic_strategy.clone() - } -} - -impl MetadataBlob { - pub fn as_slice_raw<'a>(&'a self) -> &'a [u8] { - match *self { - MetadataVec(ref vec) => &vec[..], - MetadataArchive(ref ar) => ar.as_slice(), - } - } - - pub fn as_slice<'a>(&'a self) -> &'a [u8] { - let slice = self.as_slice_raw(); - let len_offset = 4 + common::metadata_encoding_version.len(); - if slice.len() < len_offset+4 { - &[] // corrupt metadata - } else { - let len = (((slice[len_offset+0] as u32) << 24) | - ((slice[len_offset+1] as u32) << 16) | - ((slice[len_offset+2] as u32) << 8) | - ((slice[len_offset+3] as u32) << 0)) as usize; - if len <= slice.len() - 4 - len_offset { - &slice[len_offset + 4..len_offset + len + 4] - } else { - &[] // corrupt or old metadata - } - } + self.root.panic_strategy.clone() } } diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index a34daba70009..7a4d3ed657a1 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -11,11 +11,10 @@ // Decoding metadata from a single crate's metadata use astencode::decode_inlined_item; -use cstore::{CrateMetadata, MetadataBlob, NativeLibraryKind}; -use common::*; -use index; +use cstore::{self, CrateMetadata, MetadataBlob, NativeLibraryKind}; +use index::Index; +use schema::*; -use rustc::hir::svh::Svh; use rustc::hir::map as hir_map; use rustc::hir::map::{DefKey, DefPathData}; use rustc::util::nodemap::FnvHashMap; @@ -26,7 +25,6 @@ use rustc::middle::cstore::{InlinedItem, LinkagePreference}; use rustc::hir::def::{self, Def}; use rustc::hir::def_id::{CrateNum, DefId, DefIndex, LOCAL_CRATE}; use rustc::middle::lang_items; -use rustc::ty::{ImplContainer, TraitContainer}; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::subst::Substs; @@ -34,46 +32,102 @@ use rustc_const_math::ConstInt; use rustc::mir::repr::Mir; +use std::cell::Ref; use std::io; use std::mem; use std::rc::Rc; use std::str; use std::u32; -use rbml; use rustc_serialize::{Decodable, Decoder, SpecializedDecoder, opaque}; use syntax::attr; use syntax::ast::{self, NodeId}; +use syntax::codemap; use syntax::parse::token; -use syntax_pos::{self, Span, BytePos}; +use syntax_pos::{self, Span, BytePos, Pos}; pub struct DecodeContext<'a, 'tcx: 'a> { - pub opaque: opaque::Decoder<'a>, + opaque: opaque::Decoder<'a>, tcx: Option>, cdata: Option<&'a CrateMetadata>, - pub from_id_range: IdRange, - pub to_id_range: IdRange, + from_id_range: IdRange, + to_id_range: IdRange, // Cache the last used filemap for translating spans as an optimization. last_filemap_index: usize, } -impl<'a, 'tcx> DecodeContext<'a, 'tcx> { - pub fn new(doc: rbml::Doc<'a>, cdata: Option<&'a CrateMetadata>) - -> DecodeContext<'a, 'tcx> { +/// Abstract over the various ways one can create metadata decoders. +pub trait Metadata<'a, 'tcx>: Copy { + fn raw_bytes(self) -> &'a [u8]; + fn cdata(self) -> Option<&'a CrateMetadata> { None } + fn tcx(self) -> Option> { None } + + fn decoder(self, pos: usize) -> DecodeContext<'a, 'tcx> { let id_range = IdRange { min: NodeId::from_u32(u32::MIN), max: NodeId::from_u32(u32::MAX) }; DecodeContext { - opaque: opaque::Decoder::new(doc.data, doc.start), - cdata: cdata, - tcx: None, + opaque: opaque::Decoder::new(self.raw_bytes(), pos), + cdata: self.cdata(), + tcx: self.tcx(), from_id_range: id_range, to_id_range: id_range, last_filemap_index: 0 } } +} +impl<'a, 'tcx> Metadata<'a, 'tcx> for &'a MetadataBlob { + fn raw_bytes(self) -> &'a [u8] { + match *self { + MetadataBlob::Inflated(ref vec) => &vec[..], + MetadataBlob::Archive(ref ar) => ar.as_slice(), + } + } +} + +impl<'a, 'tcx> Metadata<'a, 'tcx> for &'a CrateMetadata { + fn raw_bytes(self) -> &'a [u8] { self.blob.raw_bytes() } + fn cdata(self) -> Option<&'a CrateMetadata> { Some(self) } +} + +impl<'a, 'tcx> Metadata<'a, 'tcx> for (&'a CrateMetadata, TyCtxt<'a, 'tcx, 'tcx>) { + fn raw_bytes(self) -> &'a [u8] { self.0.raw_bytes() } + fn cdata(self) -> Option<&'a CrateMetadata> { Some(self.0) } + fn tcx(self) -> Option> { Some(self.1) } +} + +// HACK(eddyb) Only used by astencode to customize the from/to IdRange's. +impl<'a, 'tcx> Metadata<'a, 'tcx> for (&'a CrateMetadata, TyCtxt<'a, 'tcx, 'tcx>, [IdRange; 2]) { + fn raw_bytes(self) -> &'a [u8] { self.0.raw_bytes() } + fn cdata(self) -> Option<&'a CrateMetadata> { Some(self.0) } + fn tcx(self) -> Option> { Some(self.1) } + + fn decoder(self, pos: usize) -> DecodeContext<'a, 'tcx> { + let mut dcx = (self.0, self.1).decoder(pos); + dcx.from_id_range = self.2[0]; + dcx.to_id_range = self.2[1]; + dcx + } +} + +impl<'a, 'tcx: 'a, T: Decodable> Lazy { + pub fn decode>(self, meta: M) -> T { + T::decode(&mut meta.decoder(self.position)).unwrap() + } +} + +impl<'a, 'tcx: 'a, T: Decodable> LazySeq { + pub fn decode>(self, meta: M) -> impl Iterator + 'a { + let mut dcx = meta.decoder(self.position); + (0..self.len).map(move |_| { + T::decode(&mut dcx).unwrap() + }) + } +} + +impl<'a, 'tcx> DecodeContext<'a, 'tcx> { pub fn tcx(&self) -> TyCtxt<'a, 'tcx, 'tcx> { self.tcx.expect("missing TyCtxt in DecodeContext") } @@ -82,22 +136,12 @@ impl<'a, 'tcx> DecodeContext<'a, 'tcx> { self.cdata.expect("missing CrateMetadata in DecodeContext") } - pub fn decode(&mut self) -> T { - T::decode(self).unwrap() - } - - pub fn typed(mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Self { - self.tcx = Some(tcx); - self - } - - /// Iterate over the indices of a sequence. - /// This will work solely because of `serialize::opaque`'s - /// simple encoding of `n: usize` followed by `n` elements. - pub fn seq(mut self) -> impl Iterator { - (0..self.read_usize().unwrap()).map(move |_| { - self.decode() - }) + fn with_position R, R>(&mut self, pos: usize, f: F) -> R { + let new = opaque::Decoder::new(self.opaque.data, pos); + let old = mem::replace(&mut self.opaque, new); + let r = f(self); + self.opaque = old; + r } } @@ -139,6 +183,19 @@ impl<'doc, 'tcx> Decoder for DecodeContext<'doc, 'tcx> { } } +impl<'a, 'tcx, T> SpecializedDecoder> for DecodeContext<'a, 'tcx> { + fn specialized_decode(&mut self) -> Result, Self::Error> { + Ok(Lazy::with_position(self.read_usize()?)) + } +} + +impl<'a, 'tcx, T> SpecializedDecoder> for DecodeContext<'a, 'tcx> { + fn specialized_decode(&mut self) -> Result, Self::Error> { + let len = self.read_usize()?; + Ok(LazySeq::with_position_and_length(self.read_usize()?, len)) + } +} + impl<'a, 'tcx> SpecializedDecoder for DecodeContext<'a, 'tcx> { fn specialized_decode(&mut self) -> Result { let id = u32::decode(self)?; @@ -252,15 +309,33 @@ impl<'a, 'tcx> SpecializedDecoder> for DecodeContext<'a, 'tcx> { return Ok(ty); } - let new = opaque::Decoder::new(self.opaque.data, key.pos); - let old = mem::replace(&mut self.opaque, new); - let ty = Ty::decode(self)?; - self.opaque = old; + let ty = self.with_position(key.pos, Ty::decode)?; tcx.rcache.borrow_mut().insert(key, ty); - return Ok(ty); + Ok(ty) + } else { + Ok(tcx.mk_ty(ty::TypeVariants::decode(self)?)) } + } +} - Ok(tcx.mk_ty(ty::TypeVariants::decode(self)?)) + +impl<'a, 'tcx> SpecializedDecoder> for DecodeContext<'a, 'tcx> { + fn specialized_decode(&mut self) -> Result, Self::Error> { + Ok(ty::GenericPredicates { + parent: Decodable::decode(self)?, + predicates: (0..self.read_usize()?).map(|_| { + // Handle shorthands first, if we have an usize > 0x80. + if self.opaque.data[self.opaque.position()] & 0x80 != 0 { + let pos = self.read_usize()?; + assert!(pos >= SHORTHAND_OFFSET); + let pos = pos - SHORTHAND_OFFSET; + + self.with_position(pos, ty::Predicate::decode) + } else { + ty::Predicate::decode(self) + } + }).collect()? + }) } } @@ -295,185 +370,110 @@ impl<'a, 'tcx> SpecializedDecoder> for DecodeContext<'a, 'tcx> } } -#[derive(Clone)] -pub struct CrateDep { - pub cnum: CrateNum, - pub name: String, - pub hash: Svh, - pub explicitly_linked: bool, -} - impl<'a, 'tcx> MetadataBlob { - fn root(&self) -> rbml::Doc { - rbml::Doc::new(self.as_slice()) + pub fn is_compatible(&self) -> bool { + self.raw_bytes().starts_with(METADATA_HEADER) } - fn child_at(&'a self, pos: usize, tag: usize) -> DecodeContext<'a, 'tcx> { - DecodeContext::new(rbml::Doc::at(self.as_slice(), pos).child(tag), None) + pub fn get_root(&self) -> CrateRoot { + let slice = self.raw_bytes(); + let offset = METADATA_HEADER.len(); + let pos = (((slice[offset + 0] as u32) << 24) | + ((slice[offset + 1] as u32) << 16) | + ((slice[offset + 2] as u32) << 8) | + ((slice[offset + 3] as u32) << 0)) as usize; + Lazy::with_position(pos).decode(self) } - fn get(&'a self, tag: usize) -> DecodeContext<'a, 'tcx> { - DecodeContext::new(self.root().child(tag), None) - } - - pub fn load_index(&self) -> index::Index { - index::Index::from_rbml(self.root().child(root_tag::index)) - } - - pub fn crate_rustc_version(&self) -> Option { - self.root().maybe_child(root_tag::rustc_version).map(|s| { - str::from_utf8(&s.data[s.start..s.end]).unwrap().to_string() - }) - } - - // Go through each item in the metadata and create a map from that - // item's def-key to the item's DefIndex. - pub fn load_key_map(&self) -> FnvHashMap { - self.load_index().iter_enumerated(self.as_slice()).map(|(index, pos)| { - (self.child_at(pos as usize, item_tag::def_key).decode(), index) + /// Go through each item in the metadata and create a map from that + /// item's def-key to the item's DefIndex. + pub fn load_key_map(&self, index: LazySeq) -> FnvHashMap { + index.iter_enumerated(self.raw_bytes()).map(|(index, item)| { + (item.decode(self).def_key.decode(self), index) }).collect() } - pub fn get_crate_deps(&self) -> Vec { - let dcx = self.get(root_tag::crate_deps); - - dcx.seq().enumerate().map(|(crate_num, (name, hash, explicitly_linked))| { - CrateDep { - cnum: CrateNum::new(crate_num + 1), - name: name, - hash: hash, - explicitly_linked: explicitly_linked, - } - }).collect() - } - - pub fn get_crate_info(&self) -> CrateInfo { - self.get(root_tag::crate_info).decode() - } - pub fn list_crate_metadata(&self, out: &mut io::Write) -> io::Result<()> { write!(out, "=External Dependencies=\n")?; - for dep in &self.get_crate_deps() { - write!(out, "{} {}-{}\n", dep.cnum, dep.name, dep.hash)?; + let root = self.get_root(); + for (i, dep) in root.crate_deps.decode(self).enumerate() { + write!(out, "{} {}-{}\n", i + 1, dep.name, dep.hash)?; } write!(out, "\n")?; Ok(()) } - - pub fn get_imported_filemaps(&self) -> Vec { - self.get(root_tag::codemap).decode() - } - - pub fn each_exported_macro(&self, mut f: F) where - F: FnMut(ast::Name, Vec, Span, String) -> bool, - { - for (name, attrs, span, body) in self.get(root_tag::macro_defs).seq() { - if !f(name, attrs, span, body) { - break; - } - } - } } -impl Family { +impl<'tcx> EntryKind<'tcx> { fn to_def(&self, did: DefId) -> Option { Some(match *self { - Family::Const => Def::Const(did), - Family::AssociatedConst => Def::AssociatedConst(did), - Family::ImmStatic | Family::ForeignImmStatic => Def::Static(did, false), - Family::MutStatic | Family::ForeignMutStatic => Def::Static(did, true), - Family::Struct => Def::Struct(did), - Family::Union => Def::Union(did), - Family::Fn | Family::ForeignFn => Def::Fn(did), - Family::Method => Def::Method(did), - Family::Type => Def::TyAlias(did), - Family::AssociatedType => Def::AssociatedTy(did), - Family::Mod => Def::Mod(did), - Family::Variant => Def::Variant(did), - Family::Trait => Def::Trait(did), - Family::Enum => Def::Enum(did), + EntryKind::Const => Def::Const(did), + EntryKind::AssociatedConst(_) => Def::AssociatedConst(did), + EntryKind::ImmStatic | + EntryKind::ForeignImmStatic => Def::Static(did, false), + EntryKind::MutStatic | + EntryKind::ForeignMutStatic => Def::Static(did, true), + EntryKind::Struct(_) => Def::Struct(did), + EntryKind::Union(_) => Def::Union(did), + EntryKind::Fn(_) | + EntryKind::ForeignFn(_) => Def::Fn(did), + EntryKind::Method(_) => Def::Method(did), + EntryKind::Type => Def::TyAlias(did), + EntryKind::AssociatedType(_) => Def::AssociatedTy(did), + EntryKind::Mod(_) => Def::Mod(did), + EntryKind::Variant(_) => Def::Variant(did), + EntryKind::Trait(_) => Def::Trait(did), + EntryKind::Enum => Def::Enum(did), - Family::ForeignMod | - Family::Impl | - Family::DefaultImpl | - Family::Field | - Family::Closure => { + EntryKind::ForeignMod | + EntryKind::Impl(_) | + EntryKind::DefaultImpl(_) | + EntryKind::Field | + EntryKind::Closure (_) => { return None } }) } } -impl<'a, 'tcx> CrateMetadata { - fn maybe_get(&'a self, item: rbml::Doc<'a>, tag: usize) - -> Option> { - item.maybe_child(tag).map(|child| { - DecodeContext::new(child, Some(self)) - }) - } - - fn get(&'a self, item: rbml::Doc<'a>, tag: usize) -> DecodeContext<'a, 'tcx> { - match self.maybe_get(item, tag) { - Some(dcx) => dcx, - None => bug!("failed to find child with tag {}", tag) +fn def_key_name(def_key: &hir_map::DefKey) -> Option { + match def_key.disambiguated_data.data { + DefPathData::TypeNs(ref name) | + DefPathData::ValueNs(ref name) | + DefPathData::Module(ref name) | + DefPathData::MacroDef(ref name) | + DefPathData::TypeParam(ref name) | + DefPathData::LifetimeDef(ref name) | + DefPathData::EnumVariant(ref name) | + DefPathData::Field(ref name) | + DefPathData::Binding(ref name) => { + Some(token::intern(name)) } + + DefPathData::InlinedRoot(_) => bug!("unexpected DefPathData"), + + DefPathData::CrateRoot | + DefPathData::Misc | + DefPathData::Impl | + DefPathData::ClosureExpr | + DefPathData::StructCtor | + DefPathData::Initializer | + DefPathData::ImplTrait => None + } +} + +impl<'a, 'tcx> CrateMetadata { + fn maybe_entry(&self, item_id: DefIndex) -> Option>> { + self.root.index.lookup(self.blob.raw_bytes(), item_id) } - fn item_family(&self, item: rbml::Doc) -> Family { - self.get(item, item_tag::family).decode() - } - - fn item_visibility(&self, item: rbml::Doc) -> ty::Visibility { - self.get(item, item_tag::visibility).decode() - } - - fn item_def_key(&self, item: rbml::Doc) -> hir_map::DefKey { - self.get(item, item_tag::def_key).decode() - } - - fn item_name(&self, item: rbml::Doc) -> ast::Name { - self.maybe_item_name(item).expect("no item in item_name") - } - - fn maybe_item_name(&self, item: rbml::Doc) -> Option { - let name = match self.item_def_key(item).disambiguated_data.data { - DefPathData::TypeNs(name) | - DefPathData::ValueNs(name) | - DefPathData::Module(name) | - DefPathData::MacroDef(name) | - DefPathData::TypeParam(name) | - DefPathData::LifetimeDef(name) | - DefPathData::EnumVariant(name) | - DefPathData::Field(name) | - DefPathData::Binding(name) => Some(name), - - DefPathData::InlinedRoot(_) => bug!("unexpected DefPathData"), - - DefPathData::CrateRoot | - DefPathData::Misc | - DefPathData::Impl | - DefPathData::ClosureExpr | - DefPathData::StructCtor | - DefPathData::Initializer | - DefPathData::ImplTrait => None - }; - - name.map(|s| token::intern(&s)) - } - - fn maybe_entry(&self, item_id: DefIndex) -> Option { - self.index.lookup_item(self.data.as_slice(), item_id).map(|pos| { - rbml::Doc::at(self.data.as_slice(), pos as usize) - }) - } - - fn entry(&self, item_id: DefIndex) -> rbml::Doc { + fn entry(&self, item_id: DefIndex) -> Entry<'tcx> { match self.maybe_entry(item_id) { None => bug!("entry: id not found: {:?} in crate {:?} with number {}", item_id, self.name, self.cnum), - Some(d) => d + Some(d) => d.decode(self) } } @@ -484,62 +484,42 @@ impl<'a, 'tcx> CrateMetadata { } } - fn entry_data(&self, doc: rbml::Doc) -> EntryData { - self.get(doc, item_tag::data).decode() - } - - fn entry_typed_data(&self, doc: rbml::Doc, tcx: TyCtxt<'a, 'tcx, 'tcx>) - -> EntryTypedData<'tcx> { - self.get(doc, item_tag::typed_data).typed(tcx).decode() - } - - fn item_parent_item(&self, d: rbml::Doc) -> Option { - self.item_def_key(d).parent.map(|index| self.local_def_id(index)) - } - - fn doc_type(&self, doc: rbml::Doc, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Ty<'tcx> { - self.maybe_doc_type(doc, tcx).expect("missing item_tag::ty") - } - - fn maybe_doc_type(&self, doc: rbml::Doc, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Option> { - self.maybe_get(doc, item_tag::ty).map(|dcx| dcx.typed(tcx).decode()) + fn item_name(&self, item: &Entry<'tcx>) -> ast::Name { + def_key_name(&item.def_key.decode(self)).expect("no name in item_name") } pub fn get_def(&self, index: DefIndex) -> Option { - self.item_family(self.entry(index)).to_def(self.local_def_id(index)) + self.entry(index).kind.to_def(self.local_def_id(index)) } pub fn get_trait_def(&self, item_id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> ty::TraitDef<'tcx> { - let item_doc = self.entry(item_id); - let generics = self.doc_generics(item_doc, tcx); - - let data = match self.entry_data(item_doc) { - EntryData::Trait(data) => data, - _ => bug!() - }; - let typed_data = match self.entry_typed_data(item_doc, tcx) { - EntryTypedData::Trait(data) => data, + let data = match self.entry(item_id).kind { + EntryKind::Trait(data) => data.decode(self), _ => bug!() }; - ty::TraitDef::new(data.unsafety, data.paren_sugar, generics, typed_data.trait_ref, - self.def_path(item_id).unwrap().deterministic_hash(tcx))) + ty::TraitDef::new(data.unsafety, data.paren_sugar, + tcx.lookup_generics(self.local_def_id(item_id)), + data.trait_ref.decode((self, tcx)), + self.def_path(item_id).unwrap().deterministic_hash(tcx)) } - fn get_variant(&self, item: rbml::Doc, index: DefIndex) - -> (ty::VariantDefData<'tcx, 'tcx>, Option) { - let data = match self.entry_data(item) { - EntryData::Variant(data) => data, + fn get_variant(&self, item: &Entry<'tcx>, index: DefIndex) + -> (ty::VariantDefData<'tcx, 'tcx>, Option) { + let data = match item.kind { + EntryKind::Variant(data) | + EntryKind::Struct(data) | + EntryKind::Union(data) => data.decode(self), _ => bug!() }; - let fields = self.get(item, item_tag::children).seq().map(|index| { + let fields = item.children.decode(self).map(|index| { let f = self.entry(index); ty::FieldDefData::new(self.local_def_id(index), - self.item_name(f), - self.item_visibility(f)) + self.item_name(&f), + f.visibility) }).collect(); (ty::VariantDefData { @@ -553,27 +533,25 @@ impl<'a, 'tcx> CrateMetadata { pub fn get_adt_def(&self, item_id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> ty::AdtDefMaster<'tcx> { - let doc = self.entry(item_id); + let item = self.entry(item_id); let did = self.local_def_id(item_id); let mut ctor_index = None; - let family = self.item_family(doc); - let variants = if family == Family::Enum { - self.get(doc, item_tag::children).seq().map(|index| { - let (variant, struct_ctor) = self.get_variant(self.entry(index), index); + let variants = if let EntryKind::Enum = item.kind { + item.children.decode(self).map(|index| { + let (variant, struct_ctor) = self.get_variant(&self.entry(index), index); assert_eq!(struct_ctor, None); variant }).collect() } else{ - let (variant, struct_ctor) = self.get_variant(doc, item_id); + let (variant, struct_ctor) = self.get_variant(&item, item_id); ctor_index = struct_ctor; vec![variant] }; - let kind = match family { - Family::Enum => ty::AdtKind::Enum, - Family::Struct => ty::AdtKind::Struct, - Family::Union => ty::AdtKind::Union, - _ => bug!("get_adt_def called on a non-ADT {:?} - {:?}", - family, did) + let kind = match item.kind { + EntryKind::Enum => ty::AdtKind::Enum, + EntryKind::Struct(_) => ty::AdtKind::Struct, + EntryKind::Union(_) => ty::AdtKind::Union, + _ => bug!("get_adt_def called on a non-ADT {:?}", did) }; let adt = tcx.intern_adt_def(did, kind, variants); @@ -599,42 +577,43 @@ impl<'a, 'tcx> CrateMetadata { pub fn get_predicates(&self, item_id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> ty::GenericPredicates<'tcx> { - self.doc_predicates(self.entry(item_id), tcx, item_tag::predicates) + self.entry(item_id).predicates.unwrap().decode((self, tcx)) } pub fn get_super_predicates(&self, item_id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> ty::GenericPredicates<'tcx> { - self.doc_predicates(self.entry(item_id), tcx, item_tag::super_predicates) + match self.entry(item_id).kind { + EntryKind::Trait(data) => { + data.decode(self).super_predicates.decode((self, tcx)) + } + _ => bug!() + } } pub fn get_generics(&self, item_id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>) - -> &'tcx ty::Generics<'tcx> { - self.doc_generics(self.entry(item_id), tcx) + -> ty::Generics<'tcx> { + self.entry(item_id).generics.unwrap().decode((self, tcx)) } pub fn get_type(&self, id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Ty<'tcx> { - self.doc_type(self.entry(id), tcx) + self.entry(id).ty.unwrap().decode((self, tcx)) } pub fn get_stability(&self, id: DefIndex) -> Option { - self.maybe_get(self.entry(id), item_tag::stability).map(|mut dcx| { - dcx.decode() - }) + self.entry(id).stability.map(|stab| stab.decode(self)) } pub fn get_deprecation(&self, id: DefIndex) -> Option { - self.maybe_get(self.entry(id), item_tag::deprecation).map(|mut dcx| { - dcx.decode() - }) + self.entry(id).deprecation.map(|depr| depr.decode(self)) } pub fn get_visibility(&self, id: DefIndex) -> ty::Visibility { - self.item_visibility(self.entry(id)) + self.entry(id).visibility } - fn get_impl_data(&self, id: DefIndex) -> ImplData { - match self.entry_data(self.entry(id)) { - EntryData::Impl(data) => data, + fn get_impl_data(&self, id: DefIndex) -> ImplData<'tcx> { + match self.entry(id).kind { + EntryKind::Impl(data) => data.decode(self), _ => bug!() } } @@ -656,15 +635,12 @@ impl<'a, 'tcx> CrateMetadata { id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Option> { - match self.entry_typed_data(self.entry(id), tcx) { - EntryTypedData::Impl(data) => data.trait_ref, - _ => bug!() - } + self.get_impl_data(id).trait_ref.map(|tr| tr.decode((self, tcx))) } /// Iterates over the language items in the given crate. pub fn get_lang_items(&self) -> Vec<(DefIndex, usize)> { - self.get(self.data.root(), root_tag::lang_items).decode() + self.root.lang_items.decode(self).collect() } /// Iterates over each child of the given item. @@ -672,38 +648,34 @@ impl<'a, 'tcx> CrateMetadata { where F: FnMut(def::Export) { // Find the item. - let item_doc = match self.maybe_entry(id) { + let item = match self.maybe_entry(id) { None => return, - Some(item_doc) => item_doc, - }; - - let dcx = match self.maybe_get(item_doc, item_tag::children) { - Some(dcx) => dcx, - None => return + Some(item) => item.decode(self), }; // Iterate over all children. - for child_index in dcx.seq() { + for child_index in item.children.decode(self) { // Get the item. if let Some(child) = self.maybe_entry(child_index) { + let child = child.decode(self); // Hand off the item to the callback. - match self.item_family(child) { + match child.kind { // FIXME(eddyb) Don't encode these in children. - Family::ForeignMod => { - for child_index in self.get(child, item_tag::children).seq() { + EntryKind::ForeignMod => { + for child_index in child.children.decode(self) { callback(def::Export { def_id: self.local_def_id(child_index), - name: self.item_name(self.entry(child_index)) + name: self.item_name(&self.entry(child_index)) }); } continue; } - Family::Impl | Family::DefaultImpl => continue, + EntryKind::Impl(_) | EntryKind::DefaultImpl(_) => continue, _ => {} } - if let Some(name) = self.maybe_item_name(child) { + if let Some(name) = def_key_name(&child.def_key.decode(self)) { callback(def::Export { def_id: self.local_def_id(child_index), name: name @@ -712,17 +684,15 @@ impl<'a, 'tcx> CrateMetadata { } } - let reexports = match self.entry_data(item_doc) { - EntryData::Mod(data) => data.reexports, - _ => return - }; - for exp in reexports { - callback(exp); + if let EntryKind::Mod(data) = item.kind { + for exp in data.decode(self).reexports.decode(self) { + callback(exp); + } } } pub fn maybe_get_item_name(&self, id: DefIndex) -> Option { - self.maybe_item_name(self.entry(id)) + def_key_name(&self.entry(id).def_key.decode(self)) } pub fn maybe_get_item_ast(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefIndex) @@ -733,76 +703,46 @@ impl<'a, 'tcx> CrateMetadata { let parent_def_id = self.local_def_id(self.def_key(id).parent.unwrap()); let mut parent_def_path = self.def_path(id).unwrap(); parent_def_path.data.pop(); - item_doc.maybe_child(item_tag::ast).map(|ast_doc| { - decode_inlined_item(self, tcx, parent_def_path, parent_def_id, ast_doc, item_did) + item_doc.ast.map(|ast| { + let ast = ast.decode(self); + decode_inlined_item(self, tcx, parent_def_path, parent_def_id, ast, item_did) }) } pub fn is_item_mir_available(&self, id: DefIndex) -> bool { - if let Some(item_doc) = self.maybe_entry(id) { - return item_doc.maybe_child(item_tag::mir).is_some(); - } - - false + self.maybe_entry(id).and_then(|item| item.decode(self).mir).is_some() } pub fn maybe_get_item_mir(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefIndex) -> Option> { - self.maybe_get(self.entry(id), item_tag::mir).map(|dcx| { - dcx.typed(tcx).decode() - }) + self.entry(id).mir.map(|mir| mir.decode((self, tcx))) } pub fn get_impl_or_trait_item(&self, id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Option> { - let item_doc = self.entry(id); - let family = self.item_family(item_doc); - - match family { - Family::AssociatedConst | - Family::Method | - Family::AssociatedType => {} - - _ => return None - } - - let def_id = self.local_def_id(id); - - let container_id = self.item_parent_item(item_doc).unwrap(); - let container = match self.item_family(self.entry(container_id.index)) { - Family::Trait => TraitContainer(container_id), - _ => ImplContainer(container_id), + let item = self.entry(id); + let parent_and_name = || { + let def_key = item.def_key.decode(self); + (self.local_def_id(def_key.parent.unwrap()), + def_key_name(&def_key).unwrap()) }; - let name = self.item_name(item_doc); - let vis = self.item_visibility(item_doc); - - let (defaultness, has_body) = match self.entry_data(item_doc) { - EntryData::TraitAssociated(data) => { - (hir::Defaultness::Default, data.has_default) - } - EntryData::ImplAssociated(data) => { - (data.defaultness, true) - } - _ => bug!() - }; - - Some(match family { - Family::AssociatedConst => { + Some(match item.kind { + EntryKind::AssociatedConst(container) => { + let (parent, name) = parent_and_name(); ty::ConstTraitItem(Rc::new(ty::AssociatedConst { name: name, - ty: self.doc_type(item_doc, tcx), - vis: vis, - defaultness: defaultness, - def_id: def_id, - container: container, - has_value: has_body, + ty: item.ty.unwrap().decode((self, tcx)), + vis: item.visibility, + defaultness: container.defaultness(), + def_id: self.local_def_id(id), + container: container.with_def_id(parent), + has_value: container.has_body(), })) } - Family::Method => { - let generics = self.doc_generics(item_doc, tcx); - let predicates = self.doc_predicates(item_doc, tcx, item_tag::predicates); - let ity = tcx.lookup_item_type(def_id).ty; + EntryKind::Method(data) => { + let (parent, name) = parent_and_name(); + let ity = item.ty.unwrap().decode((self, tcx)); let fty = match ity.sty { ty::TyFnDef(.., fty) => fty, _ => bug!( @@ -810,49 +750,46 @@ impl<'a, 'tcx> CrateMetadata { ity, name) }; - let explicit_self = match self.entry_typed_data(item_doc, tcx) { - EntryTypedData::Method(data) => data.explicit_self, - _ => bug!() - }; + let data = data.decode(self); ty::MethodTraitItem(Rc::new(ty::Method { name: name, - generics: generics, - predicates: predicates, + generics: tcx.lookup_generics(self.local_def_id(id)), + predicates: item.predicates.unwrap().decode((self, tcx)), fty: fty, - explicit_self: explicit_self, - vis: vis, - defaultness: defaultness, - has_body: has_body, - def_id: def_id, - container: container, + explicit_self: data.explicit_self.decode((self, tcx)), + vis: item.visibility, + defaultness: data.container.defaultness(), + has_body: data.container.has_body(), + def_id: self.local_def_id(id), + container: data.container.with_def_id(parent), })) } - Family::AssociatedType => { + EntryKind::AssociatedType(container) => { + let (parent, name) = parent_and_name(); ty::TypeTraitItem(Rc::new(ty::AssociatedType { name: name, - ty: self.maybe_doc_type(item_doc, tcx), - vis: vis, - defaultness: defaultness, - def_id: def_id, - container: container, + ty: item.ty.map(|ty| ty.decode((self, tcx))), + vis: item.visibility, + defaultness: container.defaultness(), + def_id: self.local_def_id(id), + container: container.with_def_id(parent), })) } - _ => bug!() + _ => return None }) } pub fn get_item_variances(&self, id: DefIndex) -> Vec { - let item_doc = self.entry(id); - self.get(item_doc, item_tag::variances).decode() + self.entry(id).variances.decode(self).collect() } pub fn get_struct_ctor_def_id(&self, node_id: DefIndex) -> Option { - let data = match self.entry_data(self.entry(node_id)) { - EntryData::Variant(data) => data, - _ => bug!() - }; - - data.struct_ctor.map(|index| self.local_def_id(index)) + match self.entry(node_id).kind { + EntryKind::Struct(data) => { + data.decode(self).struct_ctor.map(|index| self.local_def_id(index)) + } + _ => None + } } pub fn get_item_attrs(&self, node_id: DefIndex) -> Vec { @@ -860,30 +797,25 @@ impl<'a, 'tcx> CrateMetadata { // we assume that someone passing in a tuple struct ctor is actually wanting to // look at the definition let mut item = self.entry(node_id); - let def_key = self.item_def_key(item); + let def_key = item.def_key.decode(self); if def_key.disambiguated_data.data == DefPathData::StructCtor { item = self.entry(def_key.parent.unwrap()); } - self.get_attributes(item) + self.get_attributes(&item) } pub fn get_struct_field_names(&self, id: DefIndex) -> Vec { - self.get(self.entry(id), item_tag::children).seq().map(|index| { - self.item_name(self.entry(index)) + self.entry(id).children.decode(self).map(|index| { + self.item_name(&self.entry(index)) }).collect() } - fn get_attributes(&self, md: rbml::Doc) -> Vec { - self.maybe_get(md, item_tag::attributes).map_or(vec![], |mut dcx| { - let mut attrs = dcx.decode::>(); - + fn get_attributes(&self, item: &Entry<'tcx>) -> Vec { + item.attributes.decode(self).map(|mut attr| { // Need new unique IDs: old thread-local IDs won't map to new threads. - for attr in attrs.iter_mut() { - attr.node.id = attr::mk_attr_id(); - } - - attrs - }) + attr.node.id = attr::mk_attr_id(); + attr + }).collect() } // Translate a DefId from the current compilation environment to a DefId @@ -898,106 +830,97 @@ impl<'a, 'tcx> CrateMetadata { None } - pub fn each_inherent_implementation_for_type(&self, id: DefIndex, mut callback: F) - where F: FnMut(DefId), - { - for impl_def_id in self.get(self.entry(id), item_tag::inherent_impls).seq() { - callback(impl_def_id); - } + pub fn get_inherent_implementations_for_type(&self, id: DefIndex) -> Vec { + self.entry(id).inherent_impls.decode(self).map(|index| { + self.local_def_id(index) + }).collect() } - pub fn each_implementation_for_trait(&self, - filter: Option, - mut callback: F) where - F: FnMut(DefId), - { + pub fn get_implementations_for_trait(&self, filter: Option, result: &mut Vec) { // Do a reverse lookup beforehand to avoid touching the crate_num // hash map in the loop below. let filter = match filter.map(|def_id| self.reverse_translate_def_id(def_id)) { - Some(Some(def_id)) => Some(def_id), + Some(Some(def_id)) => Some((def_id.krate.as_u32(), def_id.index)), Some(None) => return, None => None }; // FIXME(eddyb) Make this O(1) instead of O(n). - for trait_doc in self.data.root().children_of(root_tag::impls) { - let mut dcx = DecodeContext::new(trait_doc, Some(self)); - - let (krate, index) = dcx.decode(); - if let Some(local_did) = filter { - if (local_did.krate.as_u32(), local_did.index) != (krate, index) { - continue; - } + for trait_impls in self.root.impls.decode(self) { + if filter.is_some() && filter != Some(trait_impls.trait_id) { + continue; } - for impl_def_id in dcx.seq() { - callback(impl_def_id); + result.extend(trait_impls.impls.decode(self).map(|index| { + self.local_def_id(index) + })); + + if filter.is_some() { + break; } } } pub fn get_trait_of_item(&self, id: DefIndex) -> Option { - let item_doc = self.entry(id); - let parent_item_id = match self.item_parent_item(item_doc) { - None => return None, - Some(item_id) => item_id, - }; - match self.item_family(self.entry(parent_item_id.index)) { - Family::Trait => Some(parent_item_id), - _ => None - } + self.entry(id).def_key.decode(self).parent.and_then(|parent_index| { + match self.entry(parent_index).kind { + EntryKind::Trait(_) => Some(self.local_def_id(parent_index)), + _ => None + } + }) } pub fn get_native_libraries(&self) -> Vec<(NativeLibraryKind, String)> { - self.get(self.data.root(), root_tag::native_libraries).decode() + self.root.native_libraries.decode(self).collect() } pub fn get_dylib_dependency_formats(&self) -> Vec<(CrateNum, LinkagePreference)> { - let dcx = self.get(self.data.root(), root_tag::dylib_dependency_formats); - - dcx.seq::>().enumerate().flat_map(|(i, link)| { + self.root.dylib_dependency_formats.decode(self).enumerate().flat_map(|(i, link)| { let cnum = CrateNum::new(i + 1); link.map(|link| (self.cnum_map.borrow()[cnum], link)) }).collect() } pub fn get_missing_lang_items(&self) -> Vec { - self.get(self.data.root(), root_tag::lang_items_missing).decode() + self.root.lang_items_missing.decode(self).collect() } - pub fn get_fn_arg_names(&self, id: DefIndex) -> Vec { - self.maybe_get(self.entry(id), item_tag::fn_arg_names) - .map_or(vec![], |mut dcx| dcx.decode()) + pub fn get_fn_arg_names(&self, id: DefIndex) -> Vec { + let arg_names = match self.entry(id).kind { + EntryKind::Fn(data) | + EntryKind::ForeignFn(data) => data.decode(self).arg_names, + EntryKind::Method(data) => data.decode(self).fn_data.arg_names, + _ => LazySeq::empty() + }; + arg_names.decode(self).collect() } pub fn get_reachable_ids(&self) -> Vec { - let dcx = self.get(self.data.root(), root_tag::reachable_ids); - - dcx.seq().map(|index| self.local_def_id(index)).collect() + self.root.reachable_ids.decode(self).map(|index| self.local_def_id(index)).collect() } pub fn is_const_fn(&self, id: DefIndex) -> bool { - let constness = match self.entry_data(self.entry(id)) { - EntryData::ImplAssociated(data) => data.constness, - EntryData::Fn(data) => data.constness, + let constness = match self.entry(id).kind { + EntryKind::Method(data) => data.decode(self).fn_data.constness, + EntryKind::Fn(data) => data.decode(self).constness, _ => hir::Constness::NotConst }; constness == hir::Constness::Const } pub fn is_extern_item(&self, id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> bool { - let item_doc = match self.maybe_entry(id) { - Some(doc) => doc, + let item = match self.maybe_entry(id) { + Some(item) => item.decode(self), None => return false, }; - let applicable = match self.item_family(item_doc) { - Family::ImmStatic | - Family::MutStatic | - Family::ForeignImmStatic | - Family::ForeignMutStatic => true, + let applicable = match item.kind { + EntryKind::ImmStatic | + EntryKind::MutStatic | + EntryKind::ForeignImmStatic | + EntryKind::ForeignMutStatic => true, - Family::Fn | Family::ForeignFn => { + EntryKind::Fn(_) | EntryKind::ForeignFn(_) => { self.get_generics(id, tcx).types.is_empty() } @@ -1006,83 +929,53 @@ impl<'a, 'tcx> CrateMetadata { if applicable { attr::contains_extern_indicator(tcx.sess.diagnostic(), - &self.get_attributes(item_doc)) + &self.get_attributes(&item)) } else { false } } pub fn is_foreign_item(&self, id: DefIndex) -> bool { - match self.item_family(self.entry(id)) { - Family::ForeignImmStatic | - Family::ForeignMutStatic | - Family::ForeignFn => true, + match self.entry(id).kind { + EntryKind::ForeignImmStatic | + EntryKind::ForeignMutStatic | + EntryKind::ForeignFn(_) => true, _ => false } } - fn doc_generics(&self, base_doc: rbml::Doc, tcx: TyCtxt<'a, 'tcx, 'tcx>) - -> &'tcx ty::Generics<'tcx> { - let generics = self.get(base_doc, item_tag::generics).typed(tcx).decode(); - tcx.alloc_generics(generics) - } - - fn doc_predicates(&self, base_doc: rbml::Doc, tcx: TyCtxt<'a, 'tcx, 'tcx>, tag: usize) - -> ty::GenericPredicates<'tcx> { - let mut dcx = self.get(base_doc, tag).typed(tcx); - - ty::GenericPredicates { - parent: dcx.decode(), - predicates: (0..dcx.decode::()).map(|_| { - // Handle shorthands first, if we have an usize > 0x80. - if dcx.opaque.data[dcx.opaque.position()] & 0x80 != 0 { - let pos = dcx.decode::(); - assert!(pos >= SHORTHAND_OFFSET); - let pos = pos - SHORTHAND_OFFSET; - - let data = self.data.as_slice(); - let doc = rbml::Doc { - data: data, - start: pos, - end: data.len(), - }; - DecodeContext::new(doc, Some(self)).typed(tcx).decode() - } else { - dcx.decode() - } - }).collect() - } - } - pub fn is_defaulted_trait(&self, trait_id: DefIndex) -> bool { - match self.entry_data(self.entry(trait_id)) { - EntryData::Trait(data) => data.has_default_impl, + match self.entry(trait_id).kind { + EntryKind::Trait(data) => data.decode(self).has_default_impl, _ => bug!() } } pub fn is_default_impl(&self, impl_id: DefIndex) -> bool { - self.item_family(self.entry(impl_id)) == Family::DefaultImpl + match self.entry(impl_id).kind { + EntryKind::DefaultImpl(_) => true, + _ => false + } } pub fn closure_kind(&self, closure_id: DefIndex) -> ty::ClosureKind { - match self.entry_data(self.entry(closure_id)) { - EntryData::Closure(data) => data.kind, + match self.entry(closure_id).kind { + EntryKind::Closure(data) => data.decode(self).kind, _ => bug!() } } pub fn closure_ty(&self, closure_id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> ty::ClosureTy<'tcx> { - match self.entry_typed_data(self.entry(closure_id), tcx) { - EntryTypedData::Closure(data) => data.ty, + match self.entry(closure_id).kind { + EntryKind::Closure(data) => data.decode(self).ty.decode((self, tcx)), _ => bug!() } } pub fn def_key(&self, id: DefIndex) -> hir_map::DefKey { debug!("def_key: id={:?}", id); - self.item_def_key(self.entry(id)) + self.entry(id).def_key.decode(self) } // Returns the path leading to the thing with this `id`. Note that @@ -1096,4 +989,140 @@ impl<'a, 'tcx> CrateMetadata { None } } + + /// Imports the codemap from an external crate into the codemap of the crate + /// currently being compiled (the "local crate"). + /// + /// The import algorithm works analogous to how AST items are inlined from an + /// external crate's metadata: + /// For every FileMap in the external codemap an 'inline' copy is created in the + /// local codemap. The correspondence relation between external and local + /// FileMaps is recorded in the `ImportedFileMap` objects returned from this + /// function. When an item from an external crate is later inlined into this + /// crate, this correspondence information is used to translate the span + /// information of the inlined item so that it refers the correct positions in + /// the local codemap (see `>`). + /// + /// The import algorithm in the function below will reuse FileMaps already + /// existing in the local codemap. For example, even if the FileMap of some + /// source file of libstd gets imported many times, there will only ever be + /// one FileMap object for the corresponding file in the local codemap. + /// + /// Note that imported FileMaps do not actually contain the source code of the + /// file they represent, just information about length, line breaks, and + /// multibyte characters. This information is enough to generate valid debuginfo + /// for items inlined from other crates. + pub fn imported_filemaps(&'a self, local_codemap: &codemap::CodeMap) + -> Ref<'a, Vec> { + { + let filemaps = self.codemap_import_info.borrow(); + if !filemaps.is_empty() { + return filemaps; + } + } + + let external_codemap = self.root.codemap.decode(self); + + let imported_filemaps = external_codemap.map(|filemap_to_import| { + // Try to find an existing FileMap that can be reused for the filemap to + // be imported. A FileMap is reusable if it is exactly the same, just + // positioned at a different offset within the codemap. + let reusable_filemap = { + local_codemap.files + .borrow() + .iter() + .find(|fm| are_equal_modulo_startpos(&fm, &filemap_to_import)) + .map(|rc| rc.clone()) + }; + + match reusable_filemap { + Some(fm) => { + cstore::ImportedFileMap { + original_start_pos: filemap_to_import.start_pos, + original_end_pos: filemap_to_import.end_pos, + translated_filemap: fm + } + } + None => { + // We can't reuse an existing FileMap, so allocate a new one + // containing the information we need. + let syntax_pos::FileMap { + name, + abs_path, + start_pos, + end_pos, + lines, + multibyte_chars, + .. + } = filemap_to_import; + + let source_length = (end_pos - start_pos).to_usize(); + + // Translate line-start positions and multibyte character + // position into frame of reference local to file. + // `CodeMap::new_imported_filemap()` will then translate those + // coordinates to their new global frame of reference when the + // offset of the FileMap is known. + let mut lines = lines.into_inner(); + for pos in &mut lines { + *pos = *pos - start_pos; + } + let mut multibyte_chars = multibyte_chars.into_inner(); + for mbc in &mut multibyte_chars { + mbc.pos = mbc.pos - start_pos; + } + + let local_version = local_codemap.new_imported_filemap(name, + abs_path, + source_length, + lines, + multibyte_chars); + cstore::ImportedFileMap { + original_start_pos: start_pos, + original_end_pos: end_pos, + translated_filemap: local_version + } + } + } + }).collect(); + + // This shouldn't borrow twice, but there is no way to downgrade RefMut to Ref. + *self.codemap_import_info.borrow_mut() = imported_filemaps; + self.codemap_import_info.borrow() + } +} + +fn are_equal_modulo_startpos(fm1: &syntax_pos::FileMap, fm2: &syntax_pos::FileMap) -> bool { + if fm1.name != fm2.name { + return false; + } + + let lines1 = fm1.lines.borrow(); + let lines2 = fm2.lines.borrow(); + + if lines1.len() != lines2.len() { + return false; + } + + for (&line1, &line2) in lines1.iter().zip(lines2.iter()) { + if (line1 - fm1.start_pos) != (line2 - fm2.start_pos) { + return false; + } + } + + let multibytes1 = fm1.multibyte_chars.borrow(); + let multibytes2 = fm2.multibyte_chars.borrow(); + + if multibytes1.len() != multibytes2.len() { + return false; + } + + for (mb1, mb2) in multibytes1.iter().zip(multibytes2.iter()) { + if (mb1.bytes != mb2.bytes) || + ((mb1.pos - fm1.start_pos) != (mb2.pos - fm2.start_pos)) { + return false; + } + } + + true } diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index e690e5198795..185aa9e3b921 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -8,19 +8,17 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Metadata encoding - -#![allow(unused_must_use)] // everything is just a MemWriter, can't fail - -use astencode::encode_inlined_item; -use common::*; use cstore; -use index::IndexData; +use index::Index; +use schema::*; -use rustc::middle::cstore::{InlinedItemRef, LinkMeta, LinkagePreference}; +use rustc::middle::cstore::{InlinedItemRef, LinkMeta}; +use rustc::middle::cstore::{LinkagePreference, NativeLibraryKind}; use rustc::hir::def; use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefIndex, DefId}; use rustc::middle::dependency_format::Linkage; +use rustc::middle::lang_items; +use rustc::mir; use rustc::traits::specialization_graph; use rustc::ty::{self, Ty, TyCtxt}; @@ -33,13 +31,12 @@ use std::hash::Hash; use std::intrinsics; use std::io::prelude::*; use std::io::Cursor; -use std::ops::{Deref, DerefMut}; use std::rc::Rc; use std::u32; use syntax::ast::{self, CRATE_NODE_ID}; use syntax::attr; use syntax; -use rbml; +use syntax_pos; use rustc::hir::{self, PatKind}; use rustc::hir::intravisit::Visitor; @@ -48,7 +45,7 @@ use rustc::hir::intravisit; use super::index_builder::{FromId, IndexBuilder, Untracked}; pub struct EncodeContext<'a, 'tcx: 'a> { - rbml_w: rbml::writer::Encoder<'a>, + opaque: opaque::Encoder<'a>, pub tcx: TyCtxt<'a, 'tcx, 'tcx>, reexports: &'a def::ExportMap, link_meta: &'a LinkMeta, @@ -60,19 +57,6 @@ pub struct EncodeContext<'a, 'tcx: 'a> { predicate_shorthands: FnvHashMap, usize>, } -impl<'a, 'tcx> Deref for EncodeContext<'a, 'tcx> { - type Target = rbml::writer::Encoder<'a>; - fn deref(&self) -> &Self::Target { - &self.rbml_w - } -} - -impl<'a, 'tcx> DerefMut for EncodeContext<'a, 'tcx> { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.rbml_w - } -} - macro_rules! encoder_methods { ($($name:ident($ty:ty);)*) => { $(fn $name(&mut self, value: $ty) -> Result<(), Self::Error> { @@ -109,27 +93,60 @@ impl<'a, 'tcx> Encoder for EncodeContext<'a, 'tcx> { } } +impl<'a, 'tcx, T> SpecializedEncoder> for EncodeContext<'a, 'tcx> { + fn specialized_encode(&mut self, lazy: &Lazy) -> Result<(), Self::Error> { + self.emit_usize(lazy.position) + } +} + +impl<'a, 'tcx, T> SpecializedEncoder> for EncodeContext<'a, 'tcx> { + fn specialized_encode(&mut self, seq: &LazySeq) -> Result<(), Self::Error> { + self.emit_usize(seq.len)?; + self.emit_usize(seq.position) + } +} + impl<'a, 'tcx> SpecializedEncoder> for EncodeContext<'a, 'tcx> { fn specialized_encode(&mut self, ty: &Ty<'tcx>) -> Result<(), Self::Error> { self.encode_with_shorthand(ty, &ty.sty, |ecx| &mut ecx.type_shorthands) } } +impl<'a, 'tcx> SpecializedEncoder> for EncodeContext<'a, 'tcx> { + fn specialized_encode(&mut self, predicates: &ty::GenericPredicates<'tcx>) + -> Result<(), Self::Error> { + predicates.parent.encode(self)?; + predicates.predicates.len().encode(self)?; + for predicate in &predicates.predicates { + self.encode_with_shorthand(predicate, predicate, |ecx| &mut ecx.predicate_shorthands)? + } + Ok(()) + } +} + impl<'a, 'tcx> EncodeContext<'a, 'tcx> { - fn seq(&mut self, iter: I, mut f: F) - where I: IntoIterator, - I::IntoIter: ExactSizeIterator, - F: FnMut(&mut Self, I::Item) -> T, - T: Encodable { - let iter = iter.into_iter(); - self.emit_seq(iter.len(), move |ecx| { - for (i, elem) in iter.enumerate() { - ecx.emit_seq_elt(i, |ecx| { - f(ecx, elem).encode(ecx) - })?; - } - Ok(()) - }).unwrap(); + pub fn position(&self) -> usize { + self.opaque.position() + } + + pub fn lazy(&mut self, value: &T) -> Lazy { + let pos = self.position(); + value.encode(self).unwrap(); + Lazy::with_position(pos) + } + + fn lazy_seq(&mut self, iter: I) -> LazySeq + where I: IntoIterator, T: Encodable { + let pos = self.position(); + let len = iter.into_iter().map(|value| value.encode(self).unwrap()).count(); + LazySeq::with_position_and_length(pos, len) + } + + fn lazy_seq_ref<'b, I, T>(&mut self, iter: I) -> LazySeq + where I: IntoIterator, T: 'b + Encodable { + let pos = self.position(); + let len = iter.into_iter().map(|value| value.encode(self).unwrap()).count(); + LazySeq::with_position_and_length(pos, len) } /// Encode the given value or a previously cached shorthand. @@ -143,9 +160,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { return self.emit_usize(shorthand); } - let start = self.mark_stable_position(); + let start = self.position(); variant.encode(self)?; - let len = self.mark_stable_position() - start; + let len = self.position() - start; // The shorthand encoding uses the same usize as the // discriminant, with an offset so they can't conflict. @@ -170,60 +187,19 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { /// For every DefId that we create a metadata item for, we include a /// serialized copy of its DefKey, which allows us to recreate a path. - fn encode_def_key(&mut self, def_id: DefId) { - self.start_tag(item_tag::def_key); - self.tcx.map.def_key(def_id).encode(self); - self.end_tag(); - } - - // Item info table encoding - fn encode_family(&mut self, f: Family) { - self.start_tag(item_tag::family); - f.encode(self).unwrap(); - self.end_tag(); - } - - fn encode_item_variances(&mut self, def_id: DefId) { - let v = self.tcx.item_variances(def_id); - self.start_tag(item_tag::variances); - v.encode(self); - self.end_tag(); - } - - fn encode_bounds_and_type_for_item(&mut self, def_id: DefId) { + fn encode_def_key(&mut self, def_id: DefId) -> Lazy { let tcx = self.tcx; - self.encode_bounds_and_type(&tcx.lookup_item_type(def_id), - &tcx.lookup_predicates(def_id)); + self.lazy(&tcx.map.def_key(def_id)) } - fn encode_bounds_and_type(&mut self, - scheme: &ty::TypeScheme<'tcx>, - predicates: &ty::GenericPredicates<'tcx>) { - self.encode_generics(&scheme.generics, &predicates); - self.encode_type(scheme.ty); + fn encode_item_variances(&mut self, def_id: DefId) -> LazySeq { + let tcx = self.tcx; + self.lazy_seq(tcx.item_variances(def_id).iter().cloned()) } - fn encode_type(&mut self, typ: Ty<'tcx>) { - self.start_tag(item_tag::ty); - typ.encode(self).unwrap(); - self.end_tag(); - } - - fn encode_variant(&mut self, variant: ty::VariantDef, - struct_ctor: Option) - -> EntryData { - self.start_tag(item_tag::children); - self.seq(&variant.fields, |_, f| { - assert!(f.did.is_local()); - f.did.index - }); - self.end_tag(); - - EntryData::Variant(VariantData { - kind: variant.kind, - disr: variant.disr_val.to_u64_unchecked(), - struct_ctor: struct_ctor - }) + fn encode_item_type(&mut self, def_id: DefId) -> Lazy> { + let tcx = self.tcx; + self.lazy(&tcx.lookup_item_type(def_id).ty) } /// Encode data for the given variant of the given ADT. The @@ -233,97 +209,104 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { /// e.g., the length of the various vectors). fn encode_enum_variant_info(&mut self, (enum_did, Untracked(index)): - (DefId, Untracked)) { + (DefId, Untracked)) -> Entry<'tcx> { let tcx = self.tcx; let def = tcx.lookup_adt_def(enum_did); let variant = &def.variants[index]; - let vid = variant.did; - self.encode_def_key(vid); - self.encode_family(Family::Variant); + let def_id = variant.did; + + let data = VariantData { + kind: variant.kind, + disr: variant.disr_val.to_u64_unchecked(), + struct_ctor: None + }; let enum_id = tcx.map.as_local_node_id(enum_did).unwrap(); let enum_vis = &tcx.map.expect_item(enum_id).vis; - self.encode_visibility(enum_vis); - let attrs = tcx.get_attrs(vid); - self.encode_attributes(&attrs); - self.encode_stability(vid); + Entry { + kind: EntryKind::Variant(self.lazy(&data)), + visibility: enum_vis.simplify(), + def_key: self.encode_def_key(def_id), + attributes: self.encode_attributes(&tcx.get_attrs(def_id)), + children: self.lazy_seq(variant.fields.iter().map(|f| { + assert!(f.did.is_local()); + f.did.index + })), + stability: self.encode_stability(def_id), + deprecation: self.encode_deprecation(def_id), - let data = self.encode_variant(variant, None); + ty: Some(self.encode_item_type(def_id)), + inherent_impls: LazySeq::empty(), + variances: LazySeq::empty(), + generics: Some(self.encode_generics(def_id)), + predicates: Some(self.encode_predicates(def_id)), - self.start_tag(item_tag::data); - data.encode(self).unwrap(); - self.end_tag(); - - self.start_tag(item_tag::typed_data); - EntryTypedData::Other.encode(self).unwrap(); - self.end_tag(); - - self.encode_bounds_and_type_for_item(vid); + ast: None, + mir: None + } } fn encode_info_for_mod(&mut self, FromId(id, (md, attrs, vis)): - FromId<(&hir::Mod, &[ast::Attribute], &hir::Visibility)>) { + FromId<(&hir::Mod, &[ast::Attribute], &hir::Visibility)>) + -> Entry<'tcx> { let tcx = self.tcx; - let def_id = tcx.map.local_def_id(id); - self.encode_def_key(def_id); - self.encode_family(Family::Mod); - self.encode_visibility(vis); - self.encode_stability(def_id); - self.encode_attributes(attrs); - debug!("(encoding info for module) encoding info for module ID {}", id); - // Encode info about all the module children. - self.start_tag(item_tag::children); - self.seq(&md.item_ids, |_, item_id| { - tcx.map.local_def_id(item_id.id).index - }); - self.end_tag(); - - // Encode the reexports of this module, if this module is public. - let reexports = match self.reexports.get(&id) { - Some(exports) if *vis == hir::Public => exports.clone(), - _ => vec![] + let data = ModData { + reexports: match self.reexports.get(&id) { + Some(exports) if *vis == hir::Public => { + self.lazy_seq_ref(exports) + } + _ => LazySeq::empty() + } }; - self.start_tag(item_tag::data); - EntryData::Mod(ModData { - reexports: reexports - }).encode(self).unwrap(); - self.end_tag(); + Entry { + kind: EntryKind::Mod(self.lazy(&data)), + visibility: vis.simplify(), + def_key: self.encode_def_key(def_id), + attributes: self.encode_attributes(attrs), + children: self.lazy_seq(md.item_ids.iter().map(|item_id| { + tcx.map.local_def_id(item_id.id).index + })), + stability: self.encode_stability(def_id), + deprecation: self.encode_deprecation(def_id), - self.start_tag(item_tag::typed_data); - EntryTypedData::Other.encode(self).unwrap(); - self.end_tag(); + ty: None, + inherent_impls: LazySeq::empty(), + variances: LazySeq::empty(), + generics: None, + predicates: None, + + ast: None, + mir: None + } } +} - fn encode_visibility(&mut self, visibility: T) { - let vis = if visibility.is_public() { +trait Visibility { + fn simplify(&self) -> ty::Visibility; +} + +impl Visibility for hir::Visibility { + fn simplify(&self) -> ty::Visibility { + if *self == hir::Public { ty::Visibility::Public } else { ty::Visibility::PrivateExternal - }; - self.start_tag(item_tag::visibility); - vis.encode(self).unwrap(); - self.end_tag(); + } } } -trait HasVisibility: Sized { - fn is_public(self) -> bool; -} - -impl<'a> HasVisibility for &'a hir::Visibility { - fn is_public(self) -> bool { - *self == hir::Public - } -} - -impl HasVisibility for ty::Visibility { - fn is_public(self) -> bool { - self == ty::Visibility::Public +impl Visibility for ty::Visibility { + fn simplify(&self) -> ty::Visibility { + if *self == ty::Visibility::Public { + ty::Visibility::Public + } else { + ty::Visibility::PrivateExternal + } } } @@ -350,312 +333,292 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { /// vectors). fn encode_field(&mut self, (adt_def_id, Untracked((variant_index, field_index))): - (DefId, Untracked<(usize, usize)>)) { + (DefId, Untracked<(usize, usize)>)) -> Entry<'tcx> { let tcx = self.tcx; - let def = tcx.lookup_adt_def(adt_def_id); - let variant = &def.variants[variant_index]; + let variant = &tcx.lookup_adt_def(adt_def_id).variants[variant_index]; let field = &variant.fields[field_index]; - let nm = field.name; - debug!("encode_field: encoding {} {:?}", nm, field.did); - - self.encode_family(Family::Field); - self.encode_visibility(field.vis); - self.encode_bounds_and_type_for_item(field.did); - self.encode_def_key(field.did); - + let def_id = field.did; let variant_id = tcx.map.as_local_node_id(variant.did).unwrap(); let variant_data = tcx.map.expect_variant_data(variant_id); - self.encode_attributes(&variant_data.fields()[field_index].attrs); - self.encode_stability(field.did); + + Entry { + kind: EntryKind::Field, + visibility: field.vis.simplify(), + def_key: self.encode_def_key(def_id), + attributes: self.encode_attributes(&variant_data.fields()[field_index].attrs), + children: LazySeq::empty(), + stability: self.encode_stability(def_id), + deprecation: self.encode_deprecation(def_id), + + ty: Some(self.encode_item_type(def_id)), + inherent_impls: LazySeq::empty(), + variances: LazySeq::empty(), + generics: Some(self.encode_generics(def_id)), + predicates: Some(self.encode_predicates(def_id)), + + ast: None, + mir: None + } } - fn encode_struct_ctor(&mut self, ctor_def_id: DefId) { - self.encode_def_key(ctor_def_id); - self.encode_family(Family::Struct); - self.encode_visibility(ty::Visibility::Public); - self.encode_bounds_and_type_for_item(ctor_def_id); + fn encode_struct_ctor(&mut self, (adt_def_id, def_id): (DefId, DefId)) + -> Entry<'tcx> { + let variant = self.tcx.lookup_adt_def(adt_def_id).struct_variant(); - self.encode_stability(ctor_def_id); + let data = VariantData { + kind: variant.kind, + disr: variant.disr_val.to_u64_unchecked(), + struct_ctor: Some(def_id.index) + }; + + Entry { + kind: EntryKind::Struct(self.lazy(&data)), + visibility: ty::Visibility::Public, + def_key: self.encode_def_key(def_id), + attributes: LazySeq::empty(), + children: LazySeq::empty(), + stability: self.encode_stability(def_id), + deprecation: self.encode_deprecation(def_id), + + ty: Some(self.encode_item_type(def_id)), + inherent_impls: LazySeq::empty(), + variances: LazySeq::empty(), + generics: Some(self.encode_generics(def_id)), + predicates: Some(self.encode_predicates(def_id)), + + ast: None, + mir: None + } } - fn encode_generics(&mut self, - generics: &ty::Generics<'tcx>, - predicates: &ty::GenericPredicates<'tcx>) - { - self.start_tag(item_tag::generics); - generics.encode(self).unwrap(); - self.end_tag(); - self.encode_predicates(predicates, item_tag::predicates); + fn encode_generics(&mut self, def_id: DefId) -> Lazy> { + let tcx = self.tcx; + self.lazy(tcx.lookup_generics(def_id)) } - fn encode_predicates(&mut self, - predicates: &ty::GenericPredicates<'tcx>, - tag: usize) { - self.start_tag(tag); - predicates.parent.encode(self).unwrap(); - self.seq(&predicates.predicates, |ecx, predicate| { - ecx.encode_with_shorthand(predicate, predicate, - |ecx| &mut ecx.predicate_shorthands).unwrap() - }); - self.end_tag(); + fn encode_predicates(&mut self, def_id: DefId) -> Lazy> { + let tcx = self.tcx; + self.lazy(&tcx.lookup_predicates(def_id)) } - fn encode_info_for_trait_item(&mut self, def_id: DefId) { + fn encode_info_for_trait_item(&mut self, def_id: DefId) -> Entry<'tcx> { let tcx = self.tcx; let node_id = tcx.map.as_local_node_id(def_id).unwrap(); let ast_item = tcx.map.expect_trait_item(node_id); let trait_item = tcx.impl_or_trait_item(def_id); - let (family, has_default, typed_data) = match trait_item { + + let container = |has_body| if has_body { + AssociatedContainer::TraitWithDefault + } else { + AssociatedContainer::TraitRequired + }; + + let kind = match trait_item { ty::ConstTraitItem(ref associated_const) => { - self.encode_bounds_and_type_for_item(def_id); - - let trait_def_id = trait_item.container().id(); - encode_inlined_item(self, - InlinedItemRef::TraitItem(trait_def_id, ast_item)); - - (Family::AssociatedConst, - associated_const.has_value, - EntryTypedData::Other) + EntryKind::AssociatedConst(container(associated_const.has_value)) } ty::MethodTraitItem(ref method_ty) => { - self.encode_bounds_and_type_for_item(def_id); - - (Family::Method, - method_ty.has_body, - EntryTypedData::Method(MethodTypedData { - explicit_self: method_ty.explicit_self - })) + let fn_data = if let hir::MethodTraitItem(ref sig, _) = ast_item.node { + FnData { + constness: hir::Constness::NotConst, + arg_names: self.encode_fn_arg_names(&sig.decl) + } + } else { + bug!() + }; + let data = MethodData { + fn_data: fn_data, + container: container(method_ty.has_body), + explicit_self: self.lazy(&method_ty.explicit_self) + }; + EntryKind::Method(self.lazy(&data)) } - ty::TypeTraitItem(ref associated_type) => { - if let Some(ty) = associated_type.ty { - self.encode_type(ty); + ty::TypeTraitItem(_) => { + EntryKind::AssociatedType(container(false)) + } + }; + + Entry { + kind: kind, + visibility: trait_item.vis().simplify(), + def_key: self.encode_def_key(def_id), + attributes: self.encode_attributes(&ast_item.attrs), + children: LazySeq::empty(), + stability: self.encode_stability(def_id), + deprecation: self.encode_deprecation(def_id), + + ty: match trait_item { + ty::ConstTraitItem(_) | + ty::MethodTraitItem(_) => { + Some(self.encode_item_type(def_id)) } + ty::TypeTraitItem(ref associated_type) => { + associated_type.ty.map(|ty| self.lazy(&ty)) + } + }, + inherent_impls: LazySeq::empty(), + variances: LazySeq::empty(), + generics: Some(self.encode_generics(def_id)), + predicates: Some(self.encode_predicates(def_id)), - (Family::AssociatedType, false, EntryTypedData::Other) - } - }; - - self.encode_def_key(def_id); - self.encode_family(family); - self.encode_visibility(trait_item.vis()); - - self.encode_stability(def_id); - self.encode_attributes(&ast_item.attrs); - if let hir::MethodTraitItem(ref sig, _) = ast_item.node { - self.encode_fn_arg_names(&sig.decl); - }; - - self.start_tag(item_tag::data); - EntryData::TraitAssociated(TraitAssociatedData { - has_default: has_default - }).encode(self).unwrap(); - self.end_tag(); - - self.start_tag(item_tag::typed_data); - typed_data.encode(self).unwrap(); - self.end_tag(); - - self.encode_mir(def_id); + ast: if let ty::ConstTraitItem(_) = trait_item { + let trait_def_id = trait_item.container().id(); + Some(self.encode_inlined_item(InlinedItemRef::TraitItem(trait_def_id, ast_item))) + } else { + None + }, + mir: self.encode_mir(def_id) + } } - fn encode_info_for_impl_item(&mut self, def_id: DefId) { + fn encode_info_for_impl_item(&mut self, def_id: DefId) -> Entry<'tcx> { let node_id = self.tcx.map.as_local_node_id(def_id).unwrap(); let ast_item = self.tcx.map.expect_impl_item(node_id); let impl_item = self.tcx.impl_or_trait_item(def_id); let impl_def_id = impl_item.container().id(); - let (family, typed_data) = match impl_item { + + let container = match ast_item.defaultness { + hir::Defaultness::Default => AssociatedContainer::ImplDefault, + hir::Defaultness::Final => AssociatedContainer::ImplFinal + }; + + let kind = match impl_item { ty::ConstTraitItem(_) => { - self.encode_bounds_and_type_for_item(def_id); - - encode_inlined_item(self, - InlinedItemRef::ImplItem(impl_def_id, ast_item)); - self.encode_mir(def_id); - - (Family::AssociatedConst, EntryTypedData::Other) + EntryKind::AssociatedConst(container) } - ty::MethodTraitItem(ref method_type) => { - self.encode_bounds_and_type_for_item(def_id); - - (Family::Method, - EntryTypedData::Method(MethodTypedData { - explicit_self: method_type.explicit_self - })) + ty::MethodTraitItem(ref method_ty) => { + let fn_data = if let hir::ImplItemKind::Method(ref sig, _) = ast_item.node { + FnData { + constness: sig.constness, + arg_names: self.encode_fn_arg_names(&sig.decl) + } + } else { + bug!() + }; + let data = MethodData { + fn_data: fn_data, + container: container, + explicit_self: self.lazy(&method_ty.explicit_self) + }; + EntryKind::Method(self.lazy(&data)) } - ty::TypeTraitItem(ref associated_type) => { - if let Some(ty) = associated_type.ty { - self.encode_type(ty); - } - - (Family::AssociatedType, EntryTypedData::Other) + ty::TypeTraitItem(_) => { + EntryKind::AssociatedType(container) } }; - self.encode_def_key(def_id); - self.encode_family(family); - self.encode_visibility(impl_item.vis()); - self.encode_attributes(&ast_item.attrs); - self.encode_stability(def_id); - - let constness = if let hir::ImplItemKind::Method(ref sig, _) = ast_item.node { - if sig.constness == hir::Constness::Const { - encode_inlined_item( - self, - InlinedItemRef::ImplItem(impl_def_id, ast_item)); - } - + let (ast, mir) = if let ty::ConstTraitItem(_) = impl_item { + (true, true) + } else if let hir::ImplItemKind::Method(ref sig, _) = ast_item.node { let generics = self.tcx.lookup_generics(def_id); let types = generics.parent_types as usize + generics.types.len(); let needs_inline = types > 0 || attr::requests_inline(&ast_item.attrs); - if needs_inline || sig.constness == hir::Constness::Const { - self.encode_mir(def_id); - } - self.encode_fn_arg_names(&sig.decl); - sig.constness + let is_const_fn = sig.constness == hir::Constness::Const; + (is_const_fn, needs_inline || is_const_fn) } else { - hir::Constness::NotConst + (false, false) }; - self.start_tag(item_tag::data); - EntryData::ImplAssociated(ImplAssociatedData { - defaultness: ast_item.defaultness, - constness:constness - }).encode(self).unwrap(); - self.end_tag(); + Entry { + kind: kind, + visibility: impl_item.vis().simplify(), + def_key: self.encode_def_key(def_id), + attributes: self.encode_attributes(&ast_item.attrs), + children: LazySeq::empty(), + stability: self.encode_stability(def_id), + deprecation: self.encode_deprecation(def_id), - self.start_tag(item_tag::typed_data); - typed_data.encode(self).unwrap(); - self.end_tag(); + ty: match impl_item { + ty::ConstTraitItem(_) | + ty::MethodTraitItem(_) => { + Some(self.encode_item_type(def_id)) + } + ty::TypeTraitItem(ref associated_type) => { + associated_type.ty.map(|ty| self.lazy(&ty)) + } + }, + inherent_impls: LazySeq::empty(), + variances: LazySeq::empty(), + generics: Some(self.encode_generics(def_id)), + predicates: Some(self.encode_predicates(def_id)), + + ast: if ast { + Some(self.encode_inlined_item(InlinedItemRef::ImplItem(impl_def_id, ast_item))) + } else { + None + }, + mir: if mir { + self.encode_mir(def_id) + } else { + None + } + } } - fn encode_fn_arg_names(&mut self, - decl: &hir::FnDecl) { - self.start_tag(item_tag::fn_arg_names); - - self.seq(&decl.inputs, |_, arg| { + fn encode_fn_arg_names(&mut self, decl: &hir::FnDecl) -> LazySeq { + self.lazy_seq(decl.inputs.iter().map(|arg| { if let PatKind::Binding(_, ref path1, _) = arg.pat.node { path1.node } else { syntax::parse::token::intern("") } - }); - - self.end_tag(); + })) } - fn encode_mir(&mut self, def_id: DefId) { - if let Some(mir) = self.mir_map.map.get(&def_id) { - self.start_tag(item_tag::mir as usize); - mir.encode(self); - self.end_tag(); - } + fn encode_mir(&mut self, def_id: DefId) -> Option>> { + self.mir_map.map.get(&def_id).map(|mir| self.lazy(mir)) } // Encodes the inherent implementations of a structure, enumeration, or trait. - fn encode_inherent_implementations(&mut self, def_id: DefId) { - self.start_tag(item_tag::inherent_impls); + fn encode_inherent_implementations(&mut self, def_id: DefId) -> LazySeq { match self.tcx.inherent_impls.borrow().get(&def_id) { - None => <[DefId]>::encode(&[], self).unwrap(), - Some(implementations) => implementations.encode(self).unwrap() + None => LazySeq::empty(), + Some(implementations) => { + self.lazy_seq(implementations.iter().map(|&def_id| { + assert!(def_id.is_local()); + def_id.index + })) + } } - self.end_tag(); } - fn encode_stability(&mut self, def_id: DefId) { - self.tcx.lookup_stability(def_id).map(|stab| { - self.start_tag(item_tag::stability); - stab.encode(self).unwrap(); - self.end_tag(); - }); - self.tcx.lookup_deprecation(def_id).map(|depr| { - self.start_tag(item_tag::deprecation); - depr.encode(self).unwrap(); - self.end_tag(); - }); + fn encode_stability(&mut self, def_id: DefId) -> Option> { + self.tcx.lookup_stability(def_id).map(|stab| self.lazy(stab)) + } + + fn encode_deprecation(&mut self, def_id: DefId) -> Option> { + self.tcx.lookup_deprecation(def_id).map(|depr| self.lazy(&depr)) } fn encode_info_for_item(&mut self, - (def_id, item): (DefId, &hir::Item)) { + (def_id, item): (DefId, &hir::Item)) -> Entry<'tcx> { let tcx = self.tcx; debug!("encoding info for item at {}", tcx.sess.codemap().span_to_string(item.span)); - let (family, data, typed_data) = match item.node { - hir::ItemStatic(_, m, _) => { - self.encode_bounds_and_type_for_item(def_id); + let kind = match item.node { + hir::ItemStatic(_, hir::MutMutable, _) => EntryKind::MutStatic, + hir::ItemStatic(_, hir::MutImmutable, _) => EntryKind::ImmStatic, + hir::ItemConst(..) => EntryKind::Const, + hir::ItemFn(ref decl, _, constness, ..) => { + let data = FnData { + constness: constness, + arg_names: self.encode_fn_arg_names(&decl) + }; - if m == hir::MutMutable { - (Family::MutStatic, EntryData::Other, EntryTypedData::Other) - } else { - (Family::ImmStatic, EntryData::Other, EntryTypedData::Other) - } - } - hir::ItemConst(..) => { - self.encode_bounds_and_type_for_item(def_id); - encode_inlined_item(self, InlinedItemRef::Item(def_id, item)); - self.encode_mir(def_id); - - (Family::Const, EntryData::Other, EntryTypedData::Other) - } - hir::ItemFn(ref decl, _, constness, _, ref generics, _) => { - let tps_len = generics.ty_params.len(); - self.encode_bounds_and_type_for_item(def_id); - let needs_inline = tps_len > 0 || attr::requests_inline(&item.attrs); - if constness == hir::Constness::Const { - encode_inlined_item(self, InlinedItemRef::Item(def_id, item)); - } - if needs_inline || constness == hir::Constness::Const { - self.encode_mir(def_id); - } - self.encode_fn_arg_names(&decl); - - (Family::Fn, EntryData::Fn(FnData { - constness: constness - }), EntryTypedData::Other) + EntryKind::Fn(self.lazy(&data)) } hir::ItemMod(ref m) => { - self.encode_info_for_mod(FromId(item.id, (m, &item.attrs, &item.vis))); - return; - } - hir::ItemForeignMod(ref fm) => { - // Encode all the items in self module. - self.start_tag(item_tag::children); - self.seq(&fm.items, |_, foreign_item| { - tcx.map.local_def_id(foreign_item.id).index - }); - self.end_tag(); - - (Family::ForeignMod, EntryData::Other, EntryTypedData::Other) - } - hir::ItemTy(..) => { - self.encode_bounds_and_type_for_item(def_id); - - (Family::Type, EntryData::Other, EntryTypedData::Other) - } - hir::ItemEnum(ref enum_definition, _) => { - self.encode_item_variances(def_id); - self.encode_bounds_and_type_for_item(def_id); - - self.start_tag(item_tag::children); - self.seq(&enum_definition.variants, |_, v| { - tcx.map.local_def_id(v.node.data.id()).index - }); - self.end_tag(); - - // Encode inherent implementations for self enumeration. - self.encode_inherent_implementations(def_id); - - (Family::Enum, EntryData::Other, EntryTypedData::Other) + return self.encode_info_for_mod(FromId(item.id, (m, &item.attrs, &item.vis))); } + hir::ItemForeignMod(_) => EntryKind::ForeignMod, + hir::ItemTy(..) => EntryKind::Type, + hir::ItemEnum(..) => EntryKind::Enum, hir::ItemStruct(ref struct_def, _) => { - let def = tcx.lookup_adt_def(def_id); - let variant = def.struct_variant(); - - self.encode_bounds_and_type_for_item(def_id); - - self.encode_item_variances(def_id); + let variant = tcx.lookup_adt_def(def_id).struct_variant(); /* Encode def_ids for each field and method for methods, write all the stuff get_trait_method @@ -665,38 +628,32 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } else { None }; - let data = self.encode_variant(variant, struct_ctor); - - // Encode inherent implementations for self structure. - self.encode_inherent_implementations(def_id); - - (Family::Struct, data, EntryTypedData::Other) + EntryKind::Struct(self.lazy(&VariantData { + kind: variant.kind, + disr: variant.disr_val.to_u64_unchecked(), + struct_ctor: struct_ctor + })) } hir::ItemUnion(..) => { - self.encode_bounds_and_type_for_item(def_id); + let variant = tcx.lookup_adt_def(def_id).struct_variant(); - self.encode_item_variances(def_id); - - /* Encode def_ids for each field and method - for methods, write all the stuff get_trait_method - needs to know*/ - let def = self.tcx.lookup_adt_def(def_id); - let data = self.encode_variant(def.struct_variant(), None); - - // Encode inherent implementations for self union. - self.encode_inherent_implementations(def_id); - - (Family::Union, data, EntryTypedData::Other) + EntryKind::Union(self.lazy(&VariantData { + kind: variant.kind, + disr: variant.disr_val.to_u64_unchecked(), + struct_ctor: None + })) } hir::ItemDefaultImpl(..) => { - (Family::DefaultImpl, EntryData::Other, - EntryTypedData::Impl(ImplTypedData { - trait_ref: tcx.impl_trait_ref(def_id) - })) + let data = ImplData { + polarity: hir::ImplPolarity::Positive, + parent_impl: None, + coerce_unsized_kind: None, + trait_ref: tcx.impl_trait_ref(def_id).map(|trait_ref| self.lazy(&trait_ref)) + }; + + EntryKind::DefaultImpl(self.lazy(&data)) } hir::ItemImpl(_, polarity, ..) => { - self.encode_bounds_and_type_for_item(def_id); - let trait_ref = tcx.impl_trait_ref(def_id); let parent = if let Some(trait_ref) = trait_ref { let trait_def = tcx.lookup_trait_def(trait_ref.def_id); @@ -710,71 +667,146 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { None }; - self.start_tag(item_tag::children); - self.seq(&tcx.impl_or_trait_items(def_id)[..], |_, &def_id| { - assert!(def_id.is_local()); - def_id.index - }); - self.end_tag(); - - (Family::Impl, - EntryData::Impl(ImplData { + let data = ImplData { polarity: polarity, parent_impl: parent, coerce_unsized_kind: tcx.custom_coerce_unsized_kinds.borrow() - .get(&def_id).cloned() - }), - EntryTypedData::Impl(ImplTypedData { - trait_ref: trait_ref - })) + .get(&def_id).cloned(), + trait_ref: trait_ref.map(|trait_ref| self.lazy(&trait_ref)) + }; + + EntryKind::Impl(self.lazy(&data)) } hir::ItemTrait(..) => { - self.encode_item_variances(def_id); let trait_def = tcx.lookup_trait_def(def_id); - let trait_predicates = tcx.lookup_predicates(def_id); - - self.encode_generics(&trait_def.generics, &trait_predicates); - self.encode_predicates(&tcx.lookup_super_predicates(def_id), - item_tag::super_predicates); - - self.start_tag(item_tag::children); - self.seq(&tcx.impl_or_trait_items(def_id)[..], |_, &def_id| { - assert!(def_id.is_local()); - def_id.index - }); - self.end_tag(); - - // Encode inherent implementations for self trait. - self.encode_inherent_implementations(def_id); - - (Family::Trait, - EntryData::Trait(TraitData { + let data = TraitData { unsafety: trait_def.unsafety, paren_sugar: trait_def.paren_sugar, - has_default_impl: tcx.trait_has_default_impl(def_id) - }), - EntryTypedData::Trait(TraitTypedData { - trait_ref: trait_def.trait_ref - })) + has_default_impl: tcx.trait_has_default_impl(def_id), + trait_ref: self.lazy(&trait_def.trait_ref), + super_predicates: self.lazy(&tcx.lookup_super_predicates(def_id)) + }; + + EntryKind::Trait(self.lazy(&data)) } hir::ItemExternCrate(_) | hir::ItemUse(_) => { bug!("cannot encode info for item {:?}", item) } }; - self.encode_family(family); - self.encode_def_key(def_id); - self.encode_visibility(&item.vis); - self.encode_attributes(&item.attrs); - self.encode_stability(def_id); + Entry { + kind: kind, + visibility: item.vis.simplify(), + def_key: self.encode_def_key(def_id), + attributes: self.encode_attributes(&item.attrs), + children: match item.node { + hir::ItemForeignMod(ref fm) => { + self.lazy_seq(fm.items.iter().map(|foreign_item| { + tcx.map.local_def_id(foreign_item.id).index + })) + } + hir::ItemEnum(..) => { + let def = self.tcx.lookup_adt_def(def_id); + self.lazy_seq(def.variants.iter().map(|v| { + assert!(v.did.is_local()); + v.did.index + })) + } + hir::ItemStruct(..) | + hir::ItemUnion(..) => { + let def = self.tcx.lookup_adt_def(def_id); + self.lazy_seq(def.struct_variant().fields.iter().map(|f| { + assert!(f.did.is_local()); + f.did.index + })) + } + hir::ItemImpl(..) | + hir::ItemTrait(..) => { + self.lazy_seq(tcx.impl_or_trait_items(def_id).iter().map(|&def_id| { + assert!(def_id.is_local()); + def_id.index + })) + } + _ => LazySeq::empty() + }, + stability: self.encode_stability(def_id), + deprecation: self.encode_deprecation(def_id), - self.start_tag(item_tag::data); - data.encode(self).unwrap(); - self.end_tag(); + ty: match item.node { + hir::ItemStatic(..) | + hir::ItemConst(..) | + hir::ItemFn(..) | + hir::ItemTy(..) | + hir::ItemEnum(..) | + hir::ItemStruct(..) | + hir::ItemUnion(..) | + hir::ItemImpl(..) => { + Some(self.encode_item_type(def_id)) + } + _ => None + }, + inherent_impls: self.encode_inherent_implementations(def_id), + variances: match item.node { + hir::ItemEnum(..) | + hir::ItemStruct(..) | + hir::ItemUnion(..) | + hir::ItemTrait(..) => { + self.encode_item_variances(def_id) + } + _ => LazySeq::empty() + }, + generics: match item.node { + hir::ItemStatic(..) | + hir::ItemConst(..) | + hir::ItemFn(..) | + hir::ItemTy(..) | + hir::ItemEnum(..) | + hir::ItemStruct(..) | + hir::ItemUnion(..) | + hir::ItemImpl(..) | + hir::ItemTrait(..) => { + Some(self.encode_generics(def_id)) + } + _ => None + }, + predicates: match item.node { + hir::ItemStatic(..) | + hir::ItemConst(..) | + hir::ItemFn(..) | + hir::ItemTy(..) | + hir::ItemEnum(..) | + hir::ItemStruct(..) | + hir::ItemUnion(..) | + hir::ItemImpl(..) | + hir::ItemTrait(..) => { + Some(self.encode_predicates(def_id)) + } + _ => None + }, - self.start_tag(item_tag::typed_data); - typed_data.encode(self).unwrap(); - self.end_tag(); + ast: match item.node { + hir::ItemConst(..) | + hir::ItemFn(_, _, hir::Constness::Const, ..) => { + Some(self.encode_inlined_item(InlinedItemRef::Item(def_id, item))) + } + _ => None + }, + mir: match item.node { + hir::ItemConst(..) => { + self.encode_mir(def_id) + } + hir::ItemFn(_, _, constness, _, ref generics, _) => { + let tps_len = generics.ty_params.len(); + let needs_inline = tps_len > 0 || attr::requests_inline(&item.attrs); + if needs_inline || constness == hir::Constness::Const { + self.encode_mir(def_id) + } else { + None + } + } + _ => None + } + } } } @@ -822,7 +854,7 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { let ctor_def_id = self.tcx.map.local_def_id(struct_def.id()); self.record(ctor_def_id, EncodeContext::encode_struct_ctor, - ctor_def_id); + (def_id, ctor_def_id)); } } } @@ -849,35 +881,42 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { impl<'a, 'tcx> EncodeContext<'a, 'tcx> { fn encode_info_for_foreign_item(&mut self, - (def_id, nitem): (DefId, &hir::ForeignItem)) { + (def_id, nitem): (DefId, &hir::ForeignItem)) + -> Entry<'tcx> { let tcx = self.tcx; debug!("writing foreign item {}", tcx.node_path_str(nitem.id)); - self.encode_def_key(def_id); - self.encode_visibility(&nitem.vis); - self.encode_bounds_and_type_for_item(def_id); - let family = match nitem.node { + let kind = match nitem.node { hir::ForeignItemFn(ref fndecl, _) => { - self.encode_fn_arg_names(&fndecl); - - Family::ForeignFn + let data = FnData { + constness: hir::Constness::NotConst, + arg_names: self.encode_fn_arg_names(&fndecl) + }; + EntryKind::ForeignFn(self.lazy(&data)) } - hir::ForeignItemStatic(_, true) => Family::ForeignMutStatic, - hir::ForeignItemStatic(_, false) => Family::ForeignImmStatic + hir::ForeignItemStatic(_, true) => EntryKind::ForeignMutStatic, + hir::ForeignItemStatic(_, false) => EntryKind::ForeignImmStatic }; - self.encode_family(family); - self.start_tag(item_tag::data); - EntryData::Other.encode(self).unwrap(); - self.end_tag(); + Entry { + kind: kind, + visibility: nitem.vis.simplify(), + def_key: self.encode_def_key(def_id), + attributes: self.encode_attributes(&nitem.attrs), + children: LazySeq::empty(), + stability: self.encode_stability(def_id), + deprecation: self.encode_deprecation(def_id), - self.start_tag(item_tag::typed_data); - EntryTypedData::Other.encode(self).unwrap(); - self.end_tag(); + ty: Some(self.encode_item_type(def_id)), + inherent_impls: LazySeq::empty(), + variances: LazySeq::empty(), + generics: Some(self.encode_generics(def_id)), + predicates: Some(self.encode_predicates(def_id)), - self.encode_attributes(&nitem.attrs); - self.encode_stability(def_id); + ast: None, + mir: None + } } } @@ -938,68 +977,73 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { } impl<'a, 'tcx> EncodeContext<'a, 'tcx> { - fn encode_info_for_anon_ty(&mut self, def_id: DefId) { - self.encode_def_key(def_id); - self.encode_bounds_and_type_for_item(def_id); + fn encode_info_for_anon_ty(&mut self, def_id: DefId) -> Entry<'tcx> { + Entry { + kind: EntryKind::Type, + visibility: ty::Visibility::Public, + def_key: self.encode_def_key(def_id), + attributes: LazySeq::empty(), + children: LazySeq::empty(), + stability: None, + deprecation: None, + + ty: Some(self.encode_item_type(def_id)), + inherent_impls: LazySeq::empty(), + variances: LazySeq::empty(), + generics: Some(self.encode_generics(def_id)), + predicates: Some(self.encode_predicates(def_id)), + + ast: None, + mir: None + } } - fn encode_info_for_closure(&mut self, def_id: DefId) { + fn encode_info_for_closure(&mut self, def_id: DefId) -> Entry<'tcx> { let tcx = self.tcx; - self.encode_def_key(def_id); - self.encode_family(Family::Closure); - self.start_tag(item_tag::data); - EntryData::Closure(ClosureData { - kind: tcx.closure_kind(def_id) - }).encode(self).unwrap(); - self.end_tag(); - - self.start_tag(item_tag::typed_data); - EntryTypedData::Closure(ClosureTypedData { - ty: tcx.tables.borrow().closure_tys[&def_id].clone() - }).encode(self).unwrap(); - self.end_tag(); - - assert!(self.mir_map.map.contains_key(&def_id)); - self.encode_mir(def_id); - } - - fn encode_info_for_items(&mut self) -> IndexData { - let krate = self.tcx.map.krate(); - - // FIXME(eddyb) Avoid wrapping the items in a doc. - self.start_tag(0).unwrap(); - - let items = { - let mut index = IndexBuilder::new(self); - index.record(DefId::local(CRATE_DEF_INDEX), - EncodeContext::encode_info_for_mod, - FromId(CRATE_NODE_ID, (&krate.module, &krate.attrs, &hir::Public))); - let mut visitor = EncodeVisitor { - index: index, - }; - krate.visit_all_items(&mut visitor); - visitor.index.into_items() + let data = ClosureData { + kind: tcx.closure_kind(def_id), + ty: self.lazy(&tcx.tables.borrow().closure_tys[&def_id]) }; - self.end_tag(); + Entry { + kind: EntryKind::Closure(self.lazy(&data)), + visibility: ty::Visibility::Public, + def_key: self.encode_def_key(def_id), + attributes: self.encode_attributes(&tcx.get_attrs(def_id)), + children: LazySeq::empty(), + stability: None, + deprecation: None, - items + ty: None, + inherent_impls: LazySeq::empty(), + variances: LazySeq::empty(), + generics: None, + predicates: None, + + ast: None, + mir: self.encode_mir(def_id) + } } - fn encode_item_index(&mut self, index: IndexData) { - self.start_tag(root_tag::index); - index.write_index(&mut self.opaque.cursor); - self.end_tag(); + fn encode_info_for_items(&mut self) -> Index { + let krate = self.tcx.map.krate(); + let mut index = IndexBuilder::new(self); + index.record(DefId::local(CRATE_DEF_INDEX), + EncodeContext::encode_info_for_mod, + FromId(CRATE_NODE_ID, (&krate.module, &krate.attrs, &hir::Public))); + let mut visitor = EncodeVisitor { + index: index, + }; + krate.visit_all_items(&mut visitor); + visitor.index.into_items() } - fn encode_attributes(&mut self, attrs: &[ast::Attribute]) { - self.start_tag(item_tag::attributes); - attrs.encode(self).unwrap(); - self.end_tag(); + fn encode_attributes(&mut self, attrs: &[ast::Attribute]) -> LazySeq { + self.lazy_seq_ref(attrs) } - fn encode_crate_deps(&mut self) { + fn encode_crate_deps(&mut self) -> LazySeq { fn get_ordered_deps(cstore: &cstore::CStore) -> Vec<(CrateNum, Rc)> { // Pull the cnums and name,vers,hash out of cstore @@ -1025,96 +1069,71 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { // the assumption that they are numbered 1 to n. // FIXME (#2166): This is not nearly enough to support correct versioning // but is enough to get transitive crate dependencies working. - self.start_tag(root_tag::crate_deps); let deps = get_ordered_deps(self.cstore); - self.seq(&deps, |_, &(_, ref dep)| { - (dep.name(), dep.hash(), dep.explicitly_linked.get()) - }); - self.end_tag(); + self.lazy_seq(deps.iter().map(|&(_, ref dep)| { + CrateDep { + name: syntax::parse::token::intern(dep.name()), + hash: dep.hash(), + explicitly_linked: dep.explicitly_linked.get() + } + })) } - fn encode_lang_items(&mut self) { + fn encode_lang_items(&mut self) + -> (LazySeq<(DefIndex, usize)>, LazySeq) { let tcx = self.tcx; - let lang_items = || { - tcx.lang_items.items().iter().enumerate().filter_map(|(i, &opt_def_id)| { - if let Some(def_id) = opt_def_id { - if def_id.is_local() { - return Some((def_id.index, i)); - } + let lang_items = tcx.lang_items.items().iter(); + (self.lazy_seq(lang_items.enumerate().filter_map(|(i, &opt_def_id)| { + if let Some(def_id) = opt_def_id { + if def_id.is_local() { + return Some((def_id.index, i)); } - None - }) - }; - - let count = lang_items().count(); - let mut lang_items = lang_items(); - - self.start_tag(root_tag::lang_items); - self.seq(0..count, |_, _| lang_items.next().unwrap()); - self.end_tag(); - - self.start_tag(root_tag::lang_items_missing); - tcx.lang_items.missing.encode(self).unwrap(); - self.end_tag(); + } + None + })), self.lazy_seq_ref(&tcx.lang_items.missing)) } - fn encode_native_libraries(&mut self) { + fn encode_native_libraries(&mut self) -> LazySeq<(NativeLibraryKind, String)> { let used_libraries = self.tcx.sess.cstore.used_libraries(); - let libs = || { - used_libraries.iter().filter_map(|&(ref lib, kind)| { - match kind { - cstore::NativeStatic => None, // these libraries are not propagated - cstore::NativeFramework | cstore::NativeUnknown => { - Some((kind, lib)) - } + self.lazy_seq(used_libraries.into_iter().filter_map(|(lib, kind)| { + match kind { + cstore::NativeStatic => None, // these libraries are not propagated + cstore::NativeFramework | cstore::NativeUnknown => { + Some((kind, lib)) } - }) - }; - - let count = libs().count(); - let mut libs = libs(); - - self.start_tag(root_tag::native_libraries); - self.seq(0..count, |_, _| libs.next().unwrap()); - self.end_tag(); + } + })) } - fn encode_codemap(&mut self) { + fn encode_codemap(&mut self) -> LazySeq { let codemap = self.tcx.sess.codemap(); let all_filemaps = codemap.files.borrow(); - let filemaps = || { + self.lazy_seq_ref(all_filemaps.iter().filter(|filemap| { // No need to export empty filemaps, as they can't contain spans // that need translation. // Also no need to re-export imported filemaps, as any downstream // crate will import them from their original source. - all_filemaps.iter().filter(|filemap| { - !filemap.lines.borrow().is_empty() && !filemap.is_imported() - }) - }; - - let count = filemaps().count(); - let mut filemaps = filemaps(); - - self.start_tag(root_tag::codemap); - self.seq(0..count, |_, _| filemaps.next().unwrap()); - self.end_tag(); + !filemap.lines.borrow().is_empty() && !filemap.is_imported() + }).map(|filemap| &**filemap)) } /// Serialize the text of the exported macros - fn encode_macro_defs(&mut self) { + fn encode_macro_defs(&mut self) -> LazySeq { let tcx = self.tcx; - self.start_tag(root_tag::macro_defs); - self.seq(&tcx.map.krate().exported_macros, |_, def| { - let body = ::syntax::print::pprust::tts_to_string(&def.body); - (def.name, &def.attrs, def.span, body) - }); - self.end_tag(); + self.lazy_seq(tcx.map.krate().exported_macros.iter().map(|def| { + MacroDef { + name: def.name, + attrs: def.attrs.to_vec(), + span: def.span, + body: ::syntax::print::pprust::tts_to_string(&def.body) + } + })) } } struct ImplVisitor<'a, 'tcx:'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, - impls: FnvHashMap> + impls: FnvHashMap> } impl<'a, 'tcx, 'v> Visitor<'v> for ImplVisitor<'a, 'tcx> { @@ -1124,7 +1143,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ImplVisitor<'a, 'tcx> { if let Some(trait_ref) = self.tcx.impl_trait_ref(impl_id) { self.impls.entry(trait_ref.def_id) .or_insert(vec![]) - .push(impl_id); + .push(impl_id.index); } } } @@ -1132,22 +1151,21 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ImplVisitor<'a, 'tcx> { impl<'a, 'tcx> EncodeContext<'a, 'tcx> { /// Encodes an index, mapping each trait to its (local) implementations. - fn encode_impls(&mut self) { + fn encode_impls(&mut self) -> LazySeq { let mut visitor = ImplVisitor { tcx: self.tcx, impls: FnvHashMap() }; self.tcx.map.krate().visit_all_items(&mut visitor); - self.start_tag(root_tag::impls); - for (trait_def_id, trait_impls) in visitor.impls { - // FIXME(eddyb) Avoid wrapping the entries in docs. - self.start_tag(0); - (trait_def_id.krate.as_u32(), trait_def_id.index).encode(self).unwrap(); - trait_impls.encode(self).unwrap(); - self.end_tag(); - } - self.end_tag(); + let all_impls: Vec<_> = visitor.impls.into_iter().map(|(trait_def_id, impls)| { + TraitImpls { + trait_id: (trait_def_id.krate.as_u32(), trait_def_id.index), + impls: self.lazy_seq(impls) + } + }).collect(); + + self.lazy_seq(all_impls) } // Encodes all reachable symbols in this crate into the metadata. @@ -1156,20 +1174,16 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { // middle::reachable module but filters out items that either don't have a // symbol associated with them (they weren't translated) or if they're an FFI // definition (as that's not defined in this crate). - fn encode_reachable(&mut self) { - self.start_tag(root_tag::reachable_ids); - + fn encode_reachable(&mut self) -> LazySeq { let reachable = self.reachable; - self.seq(reachable, |ecx, &id| ecx.tcx.map.local_def_id(id).index); - - self.end_tag(); + let tcx = self.tcx; + self.lazy_seq(reachable.iter().map(|&id| tcx.map.local_def_id(id).index)) } - fn encode_dylib_dependency_formats(&mut self) { - self.start_tag(root_tag::dylib_dependency_formats); + fn encode_dylib_dependency_formats(&mut self) -> LazySeq> { match self.tcx.sess.dependency_formats.borrow().get(&config::CrateTypeDylib) { Some(arr) => { - self.seq(arr, |_, slot| { + self.lazy_seq(arr.iter().map(|slot| { match *slot { Linkage::NotLinked | Linkage::IncludedFromDylib => None, @@ -1177,16 +1191,140 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { Linkage::Dynamic => Some(LinkagePreference::RequireDynamic), Linkage::Static => Some(LinkagePreference::RequireStatic), } - }); - } - None => { - <[Option]>::encode(&[], self).unwrap(); + })) } + None => LazySeq::empty() } - self.end_tag(); + } + + fn encode_crate_root(&mut self) -> Lazy { + let mut i = self.position(); + let crate_deps = self.encode_crate_deps(); + let dylib_dependency_formats = self.encode_dylib_dependency_formats(); + let dep_bytes = self.position() - i; + + // Encode the language items. + i = self.position(); + let (lang_items, lang_items_missing) = self.encode_lang_items(); + let lang_item_bytes = self.position() - i; + + // Encode the native libraries used + i = self.position(); + let native_libraries = self.encode_native_libraries(); + let native_lib_bytes = self.position() - i; + + // Encode codemap + i = self.position(); + let codemap = self.encode_codemap(); + let codemap_bytes = self.position() - i; + + // Encode macro definitions + i = self.position(); + let macro_defs = self.encode_macro_defs(); + let macro_defs_bytes = self.position() - i; + + // Encode the def IDs of impls, for coherence checking. + i = self.position(); + let impls = self.encode_impls(); + let impl_bytes = self.position() - i; + + // Encode reachability info. + i = self.position(); + let reachable_ids = self.encode_reachable(); + let reachable_bytes = self.position() - i; + + // Encode and index the items. + i = self.position(); + let items = self.encode_info_for_items(); + let item_bytes = self.position() - i; + + i = self.position(); + let index = items.write_index(&mut self.opaque.cursor); + let index_bytes = self.position() - i; + + let tcx = self.tcx; + let link_meta = self.link_meta; + let is_rustc_macro = tcx.sess.crate_types.borrow().contains(&CrateTypeRustcMacro); + let root = self.lazy(&CrateRoot { + rustc_version: RUSTC_VERSION.to_string(), + name: link_meta.crate_name.clone(), + triple: tcx.sess.opts.target_triple.clone(), + hash: link_meta.crate_hash, + disambiguator: tcx.sess.local_crate_disambiguator().to_string(), + panic_strategy: tcx.sess.opts.cg.panic.clone(), + plugin_registrar_fn: tcx.sess.plugin_registrar_fn.get().map(|id| { + tcx.map.local_def_id(id).index + }), + macro_derive_registrar: if is_rustc_macro { + let id = tcx.sess.derive_registrar_fn.get().unwrap(); + Some(tcx.map.local_def_id(id).index) + } else { + None + }, + + index: index, + crate_deps: crate_deps, + dylib_dependency_formats: dylib_dependency_formats, + native_libraries: native_libraries, + lang_items: lang_items, + lang_items_missing: lang_items_missing, + impls: impls, + reachable_ids: reachable_ids, + macro_defs: macro_defs, + codemap: codemap + }); + + let total_bytes = self.position(); + + if self.tcx.sess.meta_stats() { + let mut zero_bytes = 0; + for e in self.opaque.cursor.get_ref() { + if *e == 0 { + zero_bytes += 1; + } + } + + println!("metadata stats:"); + println!(" dep bytes: {}", dep_bytes); + println!(" lang item bytes: {}", lang_item_bytes); + println!(" native bytes: {}", native_lib_bytes); + println!(" codemap bytes: {}", codemap_bytes); + println!(" macro def bytes: {}", macro_defs_bytes); + println!(" impl bytes: {}", impl_bytes); + println!(" reachable bytes: {}", reachable_bytes); + println!(" item bytes: {}", item_bytes); + println!(" index bytes: {}", index_bytes); + println!(" zero bytes: {}", zero_bytes); + println!(" total bytes: {}", total_bytes); + } + + root } } +// NOTE(eddyb) The following comment was preserved for posterity, even +// though it's no longer relevant as EBML (which uses nested & tagged +// "documents") was replaced with a scheme that can't go out of bounds. +// +// And here we run into yet another obscure archive bug: in which metadata +// loaded from archives may have trailing garbage bytes. Awhile back one of +// our tests was failing sporadically on the OSX 64-bit builders (both nopt +// and opt) by having ebml generate an out-of-bounds panic when looking at +// metadata. +// +// Upon investigation it turned out that the metadata file inside of an rlib +// (and ar archive) was being corrupted. Some compilations would generate a +// metadata file which would end in a few extra bytes, while other +// compilations would not have these extra bytes appended to the end. These +// extra bytes were interpreted by ebml as an extra tag, so they ended up +// being interpreted causing the out-of-bounds. +// +// The root cause of why these extra bytes were appearing was never +// discovered, and in the meantime the solution we're employing is to insert +// the length of the metadata to the start of the metadata. Later on this +// will allow us to slice the metadata to the precise length that we just +// generated regardless of trailing bytes that end up in it. + pub fn encode_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, cstore: &cstore::CStore, reexports: &def::ExportMap, @@ -1194,13 +1332,13 @@ pub fn encode_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, reachable: &NodeSet, mir_map: &MirMap<'tcx>) -> Vec { let mut cursor = Cursor::new(vec![]); - cursor.write_all(&[0, 0, 0, 0]).unwrap(); - cursor.write_all(metadata_encoding_version).unwrap(); - // Will be filed with the length after encoding the crate. + cursor.write_all(METADATA_HEADER).unwrap(); + + // Will be filed with the root position after encoding everything. cursor.write_all(&[0, 0, 0, 0]).unwrap(); - encode_metadata_inner(&mut EncodeContext { - rbml_w: rbml::writer::Encoder::new(&mut cursor), + let root = EncodeContext { + opaque: opaque::Encoder::new(&mut cursor), tcx: tcx, reexports: reexports, link_meta: link_meta, @@ -1209,138 +1347,16 @@ pub fn encode_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, mir_map: mir_map, type_shorthands: Default::default(), predicate_shorthands: Default::default() - }); - - // RBML compacts the encoded bytes whenever appropriate, - // so there are some garbages left after the end of the data. - let meta_len = cursor.position() as usize; - cursor.get_mut().truncate(meta_len); - - // And here we run into yet another obscure archive bug: in which metadata - // loaded from archives may have trailing garbage bytes. Awhile back one of - // our tests was failing sporadically on the OSX 64-bit builders (both nopt - // and opt) by having rbml generate an out-of-bounds panic when looking at - // metadata. - // - // Upon investigation it turned out that the metadata file inside of an rlib - // (and ar archive) was being corrupted. Some compilations would generate a - // metadata file which would end in a few extra bytes, while other - // compilations would not have these extra bytes appended to the end. These - // extra bytes were interpreted by rbml as an extra tag, so they ended up - // being interpreted causing the out-of-bounds. - // - // The root cause of why these extra bytes were appearing was never - // discovered, and in the meantime the solution we're employing is to insert - // the length of the metadata to the start of the metadata. Later on this - // will allow us to slice the metadata to the precise length that we just - // generated regardless of trailing bytes that end up in it. - // - // We also need to store the metadata encoding version here, because - // rlibs don't have it. To get older versions of rustc to ignore - // this metadata, there are 4 zero bytes at the start, which are - // treated as a length of 0 by old compilers. - - let meta_start = 8 + ::common::metadata_encoding_version.len(); - let len = meta_len - meta_start; + }.encode_crate_root(); let mut result = cursor.into_inner(); - result[meta_start - 4] = (len >> 24) as u8; - result[meta_start - 3] = (len >> 16) as u8; - result[meta_start - 2] = (len >> 8) as u8; - result[meta_start - 1] = (len >> 0) as u8; + + // Encode the root position. + let header = METADATA_HEADER.len(); + let pos = root.position; + result[header + 0] = (pos >> 24) as u8; + result[header + 1] = (pos >> 16) as u8; + result[header + 2] = (pos >> 8) as u8; + result[header + 3] = (pos >> 0) as u8; + result } - -fn encode_metadata_inner(ecx: &mut EncodeContext) { - ecx.wr_tagged_str(root_tag::rustc_version, &rustc_version()); - - let tcx = ecx.tcx; - let link_meta = ecx.link_meta; - - ecx.start_tag(root_tag::crate_info); - let is_rustc_macro = tcx.sess.crate_types.borrow().contains(&CrateTypeRustcMacro); - CrateInfo { - name: link_meta.crate_name.clone(), - triple: tcx.sess.opts.target_triple.clone(), - hash: link_meta.crate_hash, - disambiguator: tcx.sess.local_crate_disambiguator().to_string(), - panic_strategy: tcx.sess.opts.cg.panic.clone(), - plugin_registrar_fn: tcx.sess.plugin_registrar_fn.get().map(|id| { - tcx.map.local_def_id(id).index - }), - macro_derive_registrar: if is_rustc_macro { - let id = tcx.sess.derive_registrar_fn.get().unwrap(); - Some(tcx.map.local_def_id(id).index) - } else { - None - } - }.encode(ecx).unwrap(); - ecx.end_tag(); - - let mut i = ecx.position(); - ecx.encode_crate_deps(); - ecx.encode_dylib_dependency_formats(); - let dep_bytes = ecx.position() - i; - - // Encode the language items. - i = ecx.position(); - ecx.encode_lang_items(); - let lang_item_bytes = ecx.position() - i; - - // Encode the native libraries used - i = ecx.position(); - ecx.encode_native_libraries(); - let native_lib_bytes = ecx.position() - i; - - // Encode codemap - i = ecx.position(); - ecx.encode_codemap(); - let codemap_bytes = ecx.position() - i; - - // Encode macro definitions - i = ecx.position(); - ecx.encode_macro_defs(); - let macro_defs_bytes = ecx.position() - i; - - // Encode the def IDs of impls, for coherence checking. - i = ecx.position(); - ecx.encode_impls(); - let impl_bytes = ecx.position() - i; - - // Encode reachability info. - i = ecx.position(); - ecx.encode_reachable(); - let reachable_bytes = ecx.position() - i; - - // Encode and index the items. - i = ecx.position(); - let items = ecx.encode_info_for_items(); - let item_bytes = ecx.position() - i; - - i = ecx.position(); - ecx.encode_item_index(items); - let index_bytes = ecx.position() - i; - - let total_bytes = ecx.position(); - - if ecx.tcx.sess.meta_stats() { - let mut zero_bytes = 0; - for e in ecx.opaque.cursor.get_ref() { - if *e == 0 { - zero_bytes += 1; - } - } - - println!("metadata stats:"); - println!(" dep bytes: {}", dep_bytes); - println!(" lang item bytes: {}", lang_item_bytes); - println!(" native bytes: {}", native_lib_bytes); - println!(" codemap bytes: {}", codemap_bytes); - println!(" macro def bytes: {}", macro_defs_bytes); - println!(" impl bytes: {}", impl_bytes); - println!(" reachable bytes: {}", reachable_bytes); - println!(" item bytes: {}", item_bytes); - println!(" index bytes: {}", index_bytes); - println!(" zero bytes: {}", zero_bytes); - println!(" total bytes: {}", total_bytes); - } -} diff --git a/src/librustc_metadata/index.rs b/src/librustc_metadata/index.rs index 2c16411c37bd..ef83251f51e8 100644 --- a/src/librustc_metadata/index.rs +++ b/src/librustc_metadata/index.rs @@ -8,65 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use schema::*; + use rustc::hir::def_id::{DefId, DefIndex}; -use rbml; use std::io::{Cursor, Write}; use std::slice; use std::u32; -/// As part of the metadata, we generate an index that stores, for -/// each DefIndex, the position of the corresponding RBML document (if -/// any). This is just a big `[u32]` slice, where an entry of -/// `u32::MAX` indicates that there is no RBML document. This little -/// struct just stores the offsets within the metadata of the start -/// and end of this slice. These are actually part of an RBML -/// document, but for looking things up in the metadata, we just -/// discard the RBML positioning and jump directly to the data. -pub struct Index { - data_start: usize, - data_end: usize, -} - -impl Index { - /// Given the RBML doc representing the index, save the offests - /// for later. - pub fn from_rbml(index: rbml::Doc) -> Index { - Index { data_start: index.start, data_end: index.end } - } - - /// Given the metadata, extract out the offset of a particular - /// DefIndex (if any). - #[inline(never)] - pub fn lookup_item(&self, bytes: &[u8], def_index: DefIndex) -> Option { - let words = bytes_to_words(&bytes[self.data_start..self.data_end]); - let index = def_index.as_usize(); - - debug!("lookup_item: index={:?} words.len={:?}", - index, words.len()); - - let position = u32::from_le(words[index]); - if position == u32::MAX { - debug!("lookup_item: position=u32::MAX"); - None - } else { - debug!("lookup_item: position={:?}", position); - Some(position) - } - } - - pub fn iter_enumerated<'a>(&self, bytes: &'a [u8]) - -> impl Iterator + 'a { - let words = bytes_to_words(&bytes[self.data_start..self.data_end]); - words.iter().enumerate().filter_map(|(index, &position)| { - if position == u32::MAX { - None - } else { - Some((DefIndex::new(index), u32::from_le(position))) - } - }) - } -} - /// While we are generating the metadata, we also track the position /// of each DefIndex. It is not required that all definitions appear /// in the metadata, nor that they are serialized in order, and @@ -74,27 +22,27 @@ impl Index { /// `u32::MAX`. Whenever an index is visited, we fill in the /// appropriate spot by calling `record_position`. We should never /// visit the same index twice. -pub struct IndexData { +pub struct Index { positions: Vec, } -impl IndexData { - pub fn new(max_index: usize) -> IndexData { - IndexData { +impl Index { + pub fn new(max_index: usize) -> Index { + Index { positions: vec![u32::MAX; max_index] } } - pub fn record(&mut self, def_id: DefId, position: usize) { + pub fn record(&mut self, def_id: DefId, entry: Lazy) { assert!(def_id.is_local()); - self.record_index(def_id.index, position); + self.record_index(def_id.index, entry); } - pub fn record_index(&mut self, item: DefIndex, position: usize) { + pub fn record_index(&mut self, item: DefIndex, entry: Lazy) { let item = item.as_usize(); - assert!(position < (u32::MAX as usize)); - let position = position as u32; + assert!(entry.position < (u32::MAX as usize)); + let position = entry.position as u32; assert!(self.positions[item] == u32::MAX, "recorded position for item {:?} twice, first at {:?} and now at {:?}", @@ -103,16 +51,52 @@ impl IndexData { self.positions[item] = position.to_le(); } - pub fn write_index(&self, buf: &mut Cursor>) { + pub fn write_index(&self, buf: &mut Cursor>) -> LazySeq { + let pos = buf.position(); buf.write_all(words_to_bytes(&self.positions)).unwrap(); + LazySeq::with_position_and_length(pos as usize, self.positions.len()) + } +} + +impl<'tcx> LazySeq { + /// Given the metadata, extract out the offset of a particular + /// DefIndex (if any). + #[inline(never)] + pub fn lookup(&self, bytes: &[u8], def_index: DefIndex) -> Option>> { + let words = &bytes_to_words(&bytes[self.position..])[..self.len]; + let index = def_index.as_usize(); + + debug!("Index::lookup: index={:?} words.len={:?}", + index, words.len()); + + let position = u32::from_le(words[index]); + if position == u32::MAX { + debug!("Index::lookup: position=u32::MAX"); + None + } else { + debug!("Index::lookup: position={:?}", position); + Some(Lazy::with_position(position as usize)) + } + } + + pub fn iter_enumerated<'a>(&self, bytes: &'a [u8]) + -> impl Iterator>)> + 'a { + let words = &bytes_to_words(&bytes[self.position..])[..self.len]; + words.iter().enumerate().filter_map(|(index, &position)| { + if position == u32::MAX { + None + } else { + let position = u32::from_le(position) as usize; + Some((DefIndex::new(index), Lazy::with_position(position))) + } + }) } } fn bytes_to_words(b: &[u8]) -> &[u32] { - assert!(b.len() % 4 == 0); - unsafe { slice::from_raw_parts(b.as_ptr() as *const u32, b.len()/4) } + unsafe { slice::from_raw_parts(b.as_ptr() as *const u32, b.len() / 4) } } fn words_to_bytes(w: &[u32]) -> &[u8] { - unsafe { slice::from_raw_parts(w.as_ptr() as *const u8, w.len()*4) } + unsafe { slice::from_raw_parts(w.as_ptr() as *const u8, w.len() * 4) } } diff --git a/src/librustc_metadata/index_builder.rs b/src/librustc_metadata/index_builder.rs index 372577e21f11..aeb6f63252c6 100644 --- a/src/librustc_metadata/index_builder.rs +++ b/src/librustc_metadata/index_builder.rs @@ -56,7 +56,9 @@ //! easily control precisely what data is given to that fn. use encoder::EncodeContext; -use index::IndexData; +use index::Index; +use schema::*; + use rustc::dep_graph::DepNode; use rustc::hir; use rustc::hir::def_id::DefId; @@ -68,7 +70,7 @@ use std::ops::{Deref, DerefMut}; /// Builder that can encode new items, adding them into the index. /// Item encoding cannot be nested. pub struct IndexBuilder<'a, 'b: 'a, 'tcx: 'b> { - items: IndexData, + items: Index, pub ecx: &'a mut EncodeContext<'b, 'tcx>, } @@ -88,16 +90,16 @@ impl<'a, 'b, 'tcx> DerefMut for IndexBuilder<'a, 'b, 'tcx> { impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { pub fn new(ecx: &'a mut EncodeContext<'b, 'tcx>) -> Self { IndexBuilder { - items: IndexData::new(ecx.tcx.map.num_local_def_ids()), + items: Index::new(ecx.tcx.map.num_local_def_ids()), ecx: ecx, } } /// Emit the data for a def-id to the metadata. The function to /// emit the data is `op`, and it will be given `data` as - /// arguments. This `record` function will start/end an RBML tag - /// and record the current offset for use in the index, calling - /// `op` to generate the data in the RBML tag. + /// arguments. This `record` function will call `op` to generate + /// the `Entry` (which may point to other encoded information) + /// and will then record the `Lazy` for use in the index. /// /// In addition, it will setup a dep-graph task to track what data /// `op` accesses to generate the metadata, which is later used by @@ -112,21 +114,17 @@ impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> { /// content system. pub fn record(&mut self, id: DefId, - op: fn(&mut EncodeContext<'b, 'tcx>, DATA), + op: fn(&mut EncodeContext<'b, 'tcx>, DATA) -> Entry<'tcx>, data: DATA) where DATA: DepGraphRead { - let position = self.ecx.mark_stable_position(); - self.items.record(id, position); let _task = self.tcx.dep_graph.in_task(DepNode::MetaData(id)); - // FIXME(eddyb) Avoid wrapping the entries in docs. - self.ecx.start_tag(0).unwrap(); data.read(self.tcx); - op(&mut self.ecx, data); - self.ecx.end_tag().unwrap(); + let entry = op(&mut self.ecx, data); + self.items.record(id, self.ecx.lazy(&entry)); } - pub fn into_items(self) -> IndexData { + pub fn into_items(self) -> Index { self.items } } diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs index b46c5be9f8a8..4fc5a46762d1 100644 --- a/src/librustc_metadata/lib.rs +++ b/src/librustc_metadata/lib.rs @@ -29,11 +29,9 @@ #![feature(rustc_private)] #![feature(specialization)] #![feature(staged_api)] -#![cfg_attr(test, feature(test))] #[macro_use] extern crate log; #[macro_use] extern crate syntax; -#[macro_use] #[no_link] extern crate rustc_bitflags; extern crate syntax_pos; extern crate flate; extern crate serialize as rustc_serialize; // used by deriving @@ -48,24 +46,15 @@ extern crate rustc_llvm; extern crate rustc_macro; extern crate rustc_const_math; -#[cfg(test)] -extern crate test; - -mod rbml { - pub mod writer; - pub mod reader; - pub use self::reader::Doc; -} - mod diagnostics; mod astencode; -mod common; mod index_builder; mod index; mod encoder; mod decoder; mod csearch; +mod schema; pub mod creader; pub mod cstore; diff --git a/src/librustc_metadata/loader.rs b/src/librustc_metadata/loader.rs index 883004b8486f..fc94cec916aa 100644 --- a/src/librustc_metadata/loader.rs +++ b/src/librustc_metadata/loader.rs @@ -212,8 +212,8 @@ //! no means all of the necessary details. Take a look at the rest of //! metadata::loader or metadata::creader for all the juicy details! -use cstore::{MetadataBlob, MetadataVec, MetadataArchive}; -use common::{metadata_encoding_version, rustc_version}; +use cstore::MetadataBlob; +use schema::{METADATA_HEADER, RUSTC_VERSION}; use rustc::hir::svh::Svh; use rustc::session::Session; @@ -382,7 +382,7 @@ impl<'a> Context<'a> { } if !self.rejected_via_version.is_empty() { err.help(&format!("please recompile that crate using this compiler ({})", - rustc_version())); + RUSTC_VERSION)); let mismatches = self.rejected_via_version.iter(); for (i, &CrateMismatch { ref path, ref got }) in mismatches.enumerate() { err.note(&format!("crate `{}` path #{}: {} compiled by {:?}", @@ -510,8 +510,7 @@ impl<'a> Context<'a> { if let Some((ref p, _)) = lib.rlib { err.note(&format!("path: {}", p.display())); } - let crate_info = lib.metadata.get_crate_info(); - note_crate_name(&mut err, &crate_info.name); + note_crate_name(&mut err, &lib.metadata.get_root().name); } err.emit(); None @@ -597,38 +596,37 @@ impl<'a> Context<'a> { } fn crate_matches(&mut self, metadata: &MetadataBlob, libpath: &Path) -> Option { - let crate_rustc_version = metadata.crate_rustc_version(); - if crate_rustc_version != Some(rustc_version()) { - let message = crate_rustc_version.unwrap_or(format!("an unknown compiler")); - info!("Rejecting via version: expected {} got {}", rustc_version(), message); + let root = metadata.get_root(); + if root.rustc_version != RUSTC_VERSION { + info!("Rejecting via version: expected {} got {}", + RUSTC_VERSION, root.rustc_version); self.rejected_via_version.push(CrateMismatch { path: libpath.to_path_buf(), - got: message + got: root.rustc_version }); return None; } - let crate_info = metadata.get_crate_info(); if self.should_match_name { - if self.crate_name != crate_info.name { + if self.crate_name != root.name { info!("Rejecting via crate name"); return None; } } - if crate_info.triple != self.triple { + if root.triple != self.triple { info!("Rejecting via crate triple: expected {} got {}", - self.triple, crate_info.triple); + self.triple, root.triple); self.rejected_via_triple.push(CrateMismatch { path: libpath.to_path_buf(), - got: crate_info.triple + got: root.triple }); return None; } if let Some(myhash) = self.hash { - if *myhash != crate_info.hash { + if *myhash != root.hash { info!("Rejecting via hash: expected {} got {}", - *myhash, crate_info.hash); + *myhash, root.hash); self.rejected_via_hash.push(CrateMismatch { path: libpath.to_path_buf(), got: myhash.to_string() @@ -637,7 +635,7 @@ impl<'a> Context<'a> { } } - Some(crate_info.hash) + Some(root.hash) } @@ -758,11 +756,7 @@ impl ArchiveMetadata { fn verify_decompressed_encoding_version(blob: &MetadataBlob, filename: &Path) -> Result<(), String> { - let data = blob.as_slice_raw(); - if data.len() < 4+metadata_encoding_version.len() || - !<[u8]>::eq(&data[..4], &[0, 0, 0, 0]) || - &data[4..4+metadata_encoding_version.len()] != metadata_encoding_version - { + if !blob.is_compatible() { Err((format!("incompatible metadata version found: '{}'", filename.display()))) } else { @@ -797,7 +791,7 @@ fn get_metadata_section_imp(target: &Target, flavor: CrateFlavor, filename: &Pat filename.display())); } }; - return match ArchiveMetadata::new(archive).map(|ar| MetadataArchive(ar)) { + return match ArchiveMetadata::new(archive).map(|ar| MetadataBlob::Archive(ar)) { None => Err(format!("failed to read rlib metadata: '{}'", filename.display())), Some(blob) => { @@ -832,12 +826,12 @@ fn get_metadata_section_imp(target: &Target, flavor: CrateFlavor, filename: &Pat let cbuf = llvm::LLVMGetSectionContents(si.llsi); let csz = llvm::LLVMGetSectionSize(si.llsi) as usize; let cvbuf: *const u8 = cbuf as *const u8; - let vlen = metadata_encoding_version.len(); + let vlen = METADATA_HEADER.len(); debug!("checking {} bytes of metadata-version stamp", vlen); let minsz = cmp::min(vlen, csz); let buf0 = slice::from_raw_parts(cvbuf, minsz); - let version_ok = buf0 == metadata_encoding_version; + let version_ok = buf0 == METADATA_HEADER; if !version_ok { return Err((format!("incompatible metadata version found: '{}'", filename.display()))); @@ -849,7 +843,7 @@ fn get_metadata_section_imp(target: &Target, flavor: CrateFlavor, filename: &Pat let bytes = slice::from_raw_parts(cvbuf1, csz - vlen); match flate::inflate_bytes(bytes) { Ok(inflated) => { - let blob = MetadataVec(inflated); + let blob = MetadataBlob::Inflated(inflated); verify_decompressed_encoding_version(&blob, filename)?; return Ok(blob); } diff --git a/src/librustc_metadata/rbml/reader.rs b/src/librustc_metadata/rbml/reader.rs deleted file mode 100644 index c4cfc32d6330..000000000000 --- a/src/librustc_metadata/rbml/reader.rs +++ /dev/null @@ -1,411 +0,0 @@ -// Copyright 2012-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. - -//! Really Bad Markup Language (rbml) is an internal serialization format of rustc. -//! This is not intended to be used by users. -//! -//! Originally based on the Extensible Binary Markup Language -//! (ebml; http://www.matroska.org/technical/specs/rfc/index.html), -//! it is now a separate format tuned for the rust object metadata. -//! -//! # Encoding -//! -//! RBML document consists of the tag, length and data. -//! The encoded data can contain multiple RBML documents concatenated. -//! -//! **Tags** are a hint for the following data. -//! Tags are a number from 0x000 to 0xfff, where 0xf0 through 0xff is reserved. -//! Tags less than 0xf0 are encoded in one literal byte. -//! Tags greater than 0xff are encoded in two big-endian bytes, -//! where the tag number is ORed with 0xf000. (E.g. tag 0x123 = `f1 23`) -//! -//! **Lengths** encode the length of the following data. -//! It is a variable-length unsigned isize, and one of the following forms: -//! -//! - `80` through `fe` for lengths up to 0x7e; -//! - `40 ff` through `7f ff` for lengths up to 0x3fff; -//! - `20 40 00` through `3f ff ff` for lengths up to 0x1fffff; -//! - `10 20 00 00` through `1f ff ff ff` for lengths up to 0xfffffff. -//! -//! The "overlong" form is allowed so that the length can be encoded -//! without the prior knowledge of the encoded data. -//! For example, the length 0 can be represented either by `80`, `40 00`, -//! `20 00 00` or `10 00 00 00`. -//! The encoder tries to minimize the length if possible. -//! Also, some predefined tags listed below are so commonly used that -//! their lengths are omitted ("implicit length"). -//! -//! **Data** can be either binary bytes or zero or more nested RBML documents. -//! Nested documents cannot overflow, and should be entirely contained -//! within a parent document. - -#[cfg(test)] -use test::Bencher; - -use std::fmt; -use std::str; - -macro_rules! try_or { - ($e:expr, $r:expr) => ( - match $e { - Ok(x) => x, - Err(_) => return $r - } - ) -} - -#[derive(Clone, Copy)] -pub struct Doc<'a> { - pub data: &'a [u8], - pub start: usize, - pub end: usize, -} - -impl<'doc> Doc<'doc> { - pub fn new(data: &'doc [u8]) -> Doc<'doc> { - Doc { - data: data, - start: 0, - end: data.len(), - } - } - - pub fn at(data: &'doc [u8], start: usize) -> Doc<'doc> { - let elt_tag = tag_at(data, start).unwrap(); - let elt_size = tag_len_at(data, elt_tag.next).unwrap(); - let end = elt_size.next + elt_size.val; - Doc { - data: data, - start: elt_size.next, - end: end, - } - } - - pub fn maybe_child(&self, tag: usize) -> Option> { - let mut pos = self.start; - while pos < self.end { - let elt_tag = try_or!(tag_at(self.data, pos), None); - let elt_size = try_or!(tag_len_at(self.data, elt_tag.next), None); - pos = elt_size.next + elt_size.val; - if elt_tag.val == tag { - return Some(Doc { - data: self.data, - start: elt_size.next, - end: pos, - }); - } - } - None - } - - pub fn child(&self, tag: usize) -> Doc<'doc> { - match self.maybe_child(tag) { - Some(d) => d, - None => { - bug!("failed to find child with tag {:?}", tag); - } - } - } - - pub fn children_of(&self, tag: usize) -> DocsIterator<'doc> { - DocsIterator { d: self.child(tag) } - } -} - -#[derive(Debug)] -pub enum Error { - IntTooBig(usize), - InvalidTag(usize) -} - -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - // FIXME: this should be a more useful display form - fmt::Debug::fmt(self, f) - } -} - -#[derive(Copy, Clone)] -struct Res { - val: usize, - next: usize, -} - -fn tag_at(data: &[u8], start: usize) -> Result { - let v = data[start] as usize; - if v < 0xf0 { - Ok(Res { - val: v, - next: start + 1, - }) - } else if v > 0xf0 { - Ok(Res { - val: ((v & 0xf) << 8) | data[start + 1] as usize, - next: start + 2, - }) - } else { - // every tag starting with byte 0xf0 is an overlong form, which is prohibited. - Err(Error::InvalidTag(v)) - } -} - -#[inline(never)] -fn vuint_at_slow(data: &[u8], start: usize) -> Result { - let a = data[start]; - if a & 0x80 != 0 { - return Ok(Res { - val: (a & 0x7f) as usize, - next: start + 1, - }); - } - if a & 0x40 != 0 { - return Ok(Res { - val: ((a & 0x3f) as usize) << 8 | (data[start + 1] as usize), - next: start + 2, - }); - } - if a & 0x20 != 0 { - return Ok(Res { - val: ((a & 0x1f) as usize) << 16 | (data[start + 1] as usize) << 8 | - (data[start + 2] as usize), - next: start + 3, - }); - } - if a & 0x10 != 0 { - return Ok(Res { - val: ((a & 0x0f) as usize) << 24 | (data[start + 1] as usize) << 16 | - (data[start + 2] as usize) << 8 | - (data[start + 3] as usize), - next: start + 4, - }); - } - Err(Error::IntTooBig(a as usize)) -} - -fn vuint_at(data: &[u8], start: usize) -> Result { - if data.len() - start < 4 { - return vuint_at_slow(data, start); - } - - // Lookup table for parsing EBML Element IDs as per - // http://ebml.sourceforge.net/specs/ The Element IDs are parsed by - // reading a big endian u32 positioned at data[start]. Using the four - // most significant bits of the u32 we lookup in the table below how - // the element ID should be derived from it. - // - // The table stores tuples (shift, mask) where shift is the number the - // u32 should be right shifted with and mask is the value the right - // shifted value should be masked with. If for example the most - // significant bit is set this means it's a class A ID and the u32 - // should be right shifted with 24 and masked with 0x7f. Therefore we - // store (24, 0x7f) at index 0x8 - 0xF (four bit numbers where the most - // significant bit is set). - // - // By storing the number of shifts and masks in a table instead of - // checking in order if the most significant bit is set, the second - // most significant bit is set etc. we can replace up to three - // "and+branch" with a single table lookup which gives us a measured - // speedup of around 2x on x86_64. - static SHIFT_MASK_TABLE: [(usize, u32); 16] = [(0, 0x0), - (0, 0x0fffffff), - (8, 0x1fffff), - (8, 0x1fffff), - (16, 0x3fff), - (16, 0x3fff), - (16, 0x3fff), - (16, 0x3fff), - (24, 0x7f), - (24, 0x7f), - (24, 0x7f), - (24, 0x7f), - (24, 0x7f), - (24, 0x7f), - (24, 0x7f), - (24, 0x7f)]; - - unsafe { - let ptr = data.as_ptr().offset(start as isize) as *const u32; - let val = u32::from_be(*ptr); - - let i = (val >> 28) as usize; - let (shift, mask) = SHIFT_MASK_TABLE[i]; - Ok(Res { - val: ((val >> shift) & mask) as usize, - next: start + ((32 - shift) >> 3), - }) - } -} - -fn tag_len_at(data: &[u8], next: usize) -> Result { - vuint_at(data, next) -} - -pub struct DocsIterator<'a> { - d: Doc<'a>, -} - -impl<'a> Iterator for DocsIterator<'a> { - type Item = Doc<'a>; - - fn next(&mut self) -> Option> { - if self.d.start >= self.d.end { - return None; - } - - let elt_tag = try_or!(tag_at(self.d.data, self.d.start), { - self.d.start = self.d.end; - None - }); - let elt_size = try_or!(tag_len_at(self.d.data, elt_tag.next), { - self.d.start = self.d.end; - None - }); - - let end = elt_size.next + elt_size.val; - let doc = Doc { - data: self.d.data, - start: elt_size.next, - end: end, - }; - - self.d.start = end; - return Some(doc); - } -} - -#[test] -fn test_vuint_at() { - let data = &[ - 0x80, - 0xff, - 0x40, 0x00, - 0x7f, 0xff, - 0x20, 0x00, 0x00, - 0x3f, 0xff, 0xff, - 0x10, 0x00, 0x00, 0x00, - 0x1f, 0xff, 0xff, 0xff - ]; - - let mut res: Res; - - // Class A - res = vuint_at(data, 0).unwrap(); - assert_eq!(res.val, 0); - assert_eq!(res.next, 1); - res = vuint_at(data, res.next).unwrap(); - assert_eq!(res.val, (1 << 7) - 1); - assert_eq!(res.next, 2); - - // Class B - res = vuint_at(data, res.next).unwrap(); - assert_eq!(res.val, 0); - assert_eq!(res.next, 4); - res = vuint_at(data, res.next).unwrap(); - assert_eq!(res.val, (1 << 14) - 1); - assert_eq!(res.next, 6); - - // Class C - res = vuint_at(data, res.next).unwrap(); - assert_eq!(res.val, 0); - assert_eq!(res.next, 9); - res = vuint_at(data, res.next).unwrap(); - assert_eq!(res.val, (1 << 21) - 1); - assert_eq!(res.next, 12); - - // Class D - res = vuint_at(data, res.next).unwrap(); - assert_eq!(res.val, 0); - assert_eq!(res.next, 16); - res = vuint_at(data, res.next).unwrap(); - assert_eq!(res.val, (1 << 28) - 1); - assert_eq!(res.next, 20); -} - -#[bench] -pub fn vuint_at_A_aligned(b: &mut Bencher) { - let data = (0..4 * 100) - .map(|i| { - match i % 2 { - 0 => 0x80, - _ => i as u8, - } - }) - .collect::>(); - let mut sum = 0; - b.iter(|| { - let mut i = 0; - while i < data.len() { - sum += vuint_at(&data, i).unwrap().val; - i += 4; - } - }); -} - -#[bench] -pub fn vuint_at_A_unaligned(b: &mut Bencher) { - let data = (0..4 * 100 + 1) - .map(|i| { - match i % 2 { - 1 => 0x80, - _ => i as u8, - } - }) - .collect::>(); - let mut sum = 0; - b.iter(|| { - let mut i = 1; - while i < data.len() { - sum += vuint_at(&data, i).unwrap().val; - i += 4; - } - }); -} - -#[bench] -pub fn vuint_at_D_aligned(b: &mut Bencher) { - let data = (0..4 * 100) - .map(|i| { - match i % 4 { - 0 => 0x10, - 3 => i as u8, - _ => 0, - } - }) - .collect::>(); - let mut sum = 0; - b.iter(|| { - let mut i = 0; - while i < data.len() { - sum += vuint_at(&data, i).unwrap().val; - i += 4; - } - }); -} - -#[bench] -pub fn vuint_at_D_unaligned(b: &mut Bencher) { - let data = (0..4 * 100 + 1) - .map(|i| { - match i % 4 { - 1 => 0x10, - 0 => i as u8, - _ => 0, - } - }) - .collect::>(); - let mut sum = 0; - b.iter(|| { - let mut i = 1; - while i < data.len() { - sum += vuint_at(&data, i).unwrap().val; - i += 4; - } - }); -} diff --git a/src/librustc_metadata/rbml/writer.rs b/src/librustc_metadata/rbml/writer.rs deleted file mode 100644 index 46b63cb13403..000000000000 --- a/src/librustc_metadata/rbml/writer.rs +++ /dev/null @@ -1,134 +0,0 @@ -// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use std::io::prelude::*; -use std::io::{self, SeekFrom, Cursor}; - -use rustc_serialize::opaque; - -pub type EncodeResult = io::Result<()>; - -// rbml writing -pub struct Encoder<'a> { - pub opaque: opaque::Encoder<'a>, - size_positions: Vec, - relax_limit: usize, // do not move encoded bytes before this position -} - -const NUM_TAGS: usize = 0x1000; - -fn write_tag(w: &mut W, n: usize) -> EncodeResult { - if n < 0xf0 { - w.write_all(&[n as u8]) - } else if 0x100 <= n && n < NUM_TAGS { - w.write_all(&[0xf0 | (n >> 8) as u8, n as u8]) - } else { - Err(io::Error::new(io::ErrorKind::Other, &format!("invalid tag: {}", n)[..])) - } -} - -fn write_sized_vuint(w: &mut W, n: usize, size: usize) -> EncodeResult { - match size { - 1 => w.write_all(&[0x80 | (n as u8)]), - 2 => w.write_all(&[0x40 | ((n >> 8) as u8), n as u8]), - 3 => w.write_all(&[0x20 | ((n >> 16) as u8), (n >> 8) as u8, n as u8]), - 4 => w.write_all(&[0x10 | ((n >> 24) as u8), (n >> 16) as u8, (n >> 8) as u8, n as u8]), - _ => Err(io::Error::new(io::ErrorKind::Other, &format!("isize too big: {}", n)[..])), - } -} - -pub fn write_vuint(w: &mut W, n: usize) -> EncodeResult { - if n < 0x7f { - return write_sized_vuint(w, n, 1); - } - if n < 0x4000 { - return write_sized_vuint(w, n, 2); - } - if n < 0x200000 { - return write_sized_vuint(w, n, 3); - } - if n < 0x10000000 { - return write_sized_vuint(w, n, 4); - } - Err(io::Error::new(io::ErrorKind::Other, &format!("isize too big: {}", n)[..])) -} - -impl<'a> Encoder<'a> { - pub fn new(cursor: &'a mut Cursor>) -> Encoder<'a> { - Encoder { - opaque: opaque::Encoder::new(cursor), - size_positions: vec![], - relax_limit: 0, - } - } - - pub fn start_tag(&mut self, tag_id: usize) -> EncodeResult { - debug!("Start tag {:?}", tag_id); - - // Write the enum ID: - write_tag(&mut self.opaque.cursor, tag_id)?; - - // Write a placeholder four-byte size. - let cur_pos = self.position(); - self.size_positions.push(cur_pos); - self.opaque.cursor.write_all(&[0, 0, 0, 0]) - } - - pub fn end_tag(&mut self) -> EncodeResult { - let last_size_pos = self.size_positions.pop().unwrap(); - let cur_pos = self.position(); - self.opaque.cursor.seek(SeekFrom::Start(last_size_pos as u64))?; - let size = cur_pos - last_size_pos - 4; - - // relax the size encoding for small tags (bigger tags are costly to move). - // we should never try to move the stable positions, however. - const RELAX_MAX_SIZE: usize = 0x100; - if size <= RELAX_MAX_SIZE && last_size_pos >= self.relax_limit { - // we can't alter the buffer in place, so have a temporary buffer - let mut buf = [0u8; RELAX_MAX_SIZE]; - { - let data = &self.opaque.cursor.get_ref()[last_size_pos + 4..cur_pos]; - buf[..size].copy_from_slice(data); - } - - // overwrite the size and data and continue - write_vuint(&mut self.opaque.cursor, size)?; - self.opaque.cursor.write_all(&buf[..size])?; - } else { - // overwrite the size with an overlong encoding and skip past the data - write_sized_vuint(&mut self.opaque.cursor, size, 4)?; - self.opaque.cursor.seek(SeekFrom::Start(cur_pos as u64))?; - } - - debug!("End tag (size = {:?})", size); - Ok(()) - } - - pub fn wr_tagged_str(&mut self, tag_id: usize, v: &str) -> EncodeResult { - write_tag(&mut self.opaque.cursor, tag_id)?; - write_vuint(&mut self.opaque.cursor, v.len())?; - self.opaque.cursor.write_all(v.as_bytes()) - } - - pub fn position(&mut self) -> usize { - self.opaque.position() as usize - } - - /// Returns the current position while marking it stable, i.e. - /// generated bytes so far wouldn't be affected by relaxation. - pub fn mark_stable_position(&mut self) -> usize { - let pos = self.position(); - if self.relax_limit < pos { - self.relax_limit = pos; - } - let meta_start = 8 + ::common::metadata_encoding_version.len(); - pos - meta_start - } -} diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs new file mode 100644 index 000000000000..b4ea2b19bf08 --- /dev/null +++ b/src/librustc_metadata/schema.rs @@ -0,0 +1,299 @@ +// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use astencode; +use index; + +use rustc::hir; +use rustc::hir::def; +use rustc::hir::def_id::{DefIndex, DefId}; +use rustc::middle::cstore::{LinkagePreference, NativeLibraryKind}; +use rustc::middle::lang_items; +use rustc::mir; +use rustc::ty::{self, Ty}; +use rustc::session::config::PanicStrategy; + +use rustc_serialize as serialize; +use syntax::{ast, attr}; +use syntax_pos::{self, Span}; + +use std::marker::PhantomData; + +pub const RUSTC_VERSION: &'static str = concat!("rustc ", env!("CFG_VERSION")); + +/// Metadata encoding version. +/// NB: increment this if you change the format of metadata such that +/// the rustc version can't be found to compare with `RUSTC_VERSION`. +pub const METADATA_VERSION: u8 = 3; + +/// Metadata header which includes `METADATA_VERSION`. +/// To get older versions of rustc to ignore this metadata, +/// there are 4 zero bytes at the start, which are treated +/// as a length of 0 by old compilers. +/// +/// This header is followed by the position of the `CrateRoot`. +pub const METADATA_HEADER: &'static [u8; 12] = &[ + 0, 0, 0, 0, + b'r', b'u', b's', b't', + 0, 0, 0, METADATA_VERSION +]; + +/// The shorthand encoding uses an enum's variant index `usize` +/// and is offset by this value so it never matches a real variant. +/// This offset is also chosen so that the first byte is never < 0x80. +pub const SHORTHAND_OFFSET: usize = 0x80; + +/// A value of type T referred to by its absolute position +/// in the metadata, and which can be decoded lazily. +#[must_use] +pub struct Lazy { + pub position: usize, + _marker: PhantomData +} + +impl Lazy { + pub fn with_position(position: usize) -> Lazy { + Lazy { + position: position, + _marker: PhantomData + } + } +} + +impl Copy for Lazy {} +impl Clone for Lazy { + fn clone(&self) -> Self { *self } +} + +impl serialize::UseSpecializedEncodable for Lazy {} +impl serialize::UseSpecializedDecodable for Lazy {} + +/// A sequence of type T referred to by its absolute position +/// in the metadata and length, and which can be decoded lazily. +/// +/// Unlike `Lazy>`, the length is encoded next to the +/// position, not at the position, which means that the length +/// doesn't need to be known before encoding all the elements. +#[must_use] +pub struct LazySeq { + pub len: usize, + pub position: usize, + _marker: PhantomData +} + +impl LazySeq { + pub fn empty() -> LazySeq { + LazySeq::with_position_and_length(0, 0) + } + + pub fn with_position_and_length(position: usize, len: usize) -> LazySeq { + LazySeq { + len: len, + position: position, + _marker: PhantomData + } + } +} + +impl Copy for LazySeq {} +impl Clone for LazySeq { + fn clone(&self) -> Self { *self } +} + +impl serialize::UseSpecializedEncodable for LazySeq {} +impl serialize::UseSpecializedDecodable for LazySeq {} + +#[derive(RustcEncodable, RustcDecodable)] +pub struct CrateRoot { + pub rustc_version: String, + pub name: String, + pub triple: String, + pub hash: hir::svh::Svh, + pub disambiguator: String, + pub panic_strategy: PanicStrategy, + pub plugin_registrar_fn: Option, + pub macro_derive_registrar: Option, + + pub index: LazySeq, + pub crate_deps: LazySeq, + pub dylib_dependency_formats: LazySeq>, + pub native_libraries: LazySeq<(NativeLibraryKind, String)>, + pub lang_items: LazySeq<(DefIndex, usize)>, + pub lang_items_missing: LazySeq, + pub impls: LazySeq, + pub reachable_ids: LazySeq, + pub macro_defs: LazySeq, + pub codemap: LazySeq +} + +#[derive(RustcEncodable, RustcDecodable)] +pub struct CrateDep { + pub name: ast::Name, + pub hash: hir::svh::Svh, + pub explicitly_linked: bool +} + +#[derive(RustcEncodable, RustcDecodable)] +pub struct TraitImpls { + pub trait_id: (u32, DefIndex), + pub impls: LazySeq +} + +#[derive(RustcEncodable, RustcDecodable)] +pub struct MacroDef { + pub name: ast::Name, + pub attrs: Vec, + pub span: Span, + pub body: String +} + +#[derive(RustcEncodable, RustcDecodable)] +pub struct Entry<'tcx> { + pub kind: EntryKind<'tcx>, + pub visibility: ty::Visibility, + pub def_key: Lazy, + pub attributes: LazySeq, + pub children: LazySeq, + pub stability: Option>, + pub deprecation: Option>, + + pub ty: Option>>, + pub inherent_impls: LazySeq, + pub variances: LazySeq, + pub generics: Option>>, + pub predicates: Option>>, + + pub ast: Option>>, + pub mir: Option>> +} + +#[derive(Copy, Clone, RustcEncodable, RustcDecodable)] +pub enum EntryKind<'tcx> { + Const, + ImmStatic, + MutStatic, + ForeignImmStatic, + ForeignMutStatic, + ForeignMod, + Type, + Enum, + Field, + Variant(Lazy), + Struct(Lazy), + Union(Lazy), + Fn(Lazy), + ForeignFn(Lazy), + Mod(Lazy), + Closure(Lazy>), + Trait(Lazy>), + Impl(Lazy>), + DefaultImpl(Lazy>), + Method(Lazy>), + AssociatedType(AssociatedContainer), + AssociatedConst(AssociatedContainer) +} + +#[derive(RustcEncodable, RustcDecodable)] +pub struct ModData { + pub reexports: LazySeq +} + +#[derive(RustcEncodable, RustcDecodable)] +pub struct FnData { + pub constness: hir::Constness, + pub arg_names: LazySeq +} + +#[derive(RustcEncodable, RustcDecodable)] +pub struct VariantData { + pub kind: ty::VariantKind, + pub disr: u64, + + /// If this is a struct's only variant, this + /// is the index of the "struct ctor" item. + pub struct_ctor: Option +} + +#[derive(RustcEncodable, RustcDecodable)] +pub struct TraitData<'tcx> { + pub unsafety: hir::Unsafety, + pub paren_sugar: bool, + pub has_default_impl: bool, + pub trait_ref: Lazy>, + pub super_predicates: Lazy> +} + +#[derive(RustcEncodable, RustcDecodable)] +pub struct ImplData<'tcx> { + pub polarity: hir::ImplPolarity, + pub parent_impl: Option, + pub coerce_unsized_kind: Option, + pub trait_ref: Option>> +} + +/// Describes whether the container of an associated item +/// is a trait or an impl and whether, in a trait, it has +/// a default, or an in impl, whether it's marked "default". +#[derive(Copy, Clone, RustcEncodable, RustcDecodable)] +pub enum AssociatedContainer { + TraitRequired, + TraitWithDefault, + ImplDefault, + ImplFinal +} + +impl AssociatedContainer { + pub fn with_def_id(&self, def_id: DefId) -> ty::ImplOrTraitItemContainer { + match *self { + AssociatedContainer::TraitRequired | + AssociatedContainer::TraitWithDefault => { + ty::TraitContainer(def_id) + } + + AssociatedContainer::ImplDefault | + AssociatedContainer::ImplFinal => { + ty::ImplContainer(def_id) + } + } + } + + pub fn has_body(&self) -> bool { + match *self { + AssociatedContainer::TraitRequired => false, + + AssociatedContainer::TraitWithDefault | + AssociatedContainer::ImplDefault | + AssociatedContainer::ImplFinal => true + } + } + + pub fn defaultness(&self) -> hir::Defaultness { + match *self { + AssociatedContainer::TraitRequired | + AssociatedContainer::TraitWithDefault | + AssociatedContainer::ImplDefault => hir::Defaultness::Default, + + AssociatedContainer::ImplFinal => hir::Defaultness::Final + } + } +} + +#[derive(RustcEncodable, RustcDecodable)] +pub struct MethodData<'tcx> { + pub fn_data: FnData, + pub container: AssociatedContainer, + pub explicit_self: Lazy> +} + +#[derive(RustcEncodable, RustcDecodable)] +pub struct ClosureData<'tcx> { + pub kind: ty::ClosureKind, + pub ty: Lazy> +} diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index d67dcbb4baf0..e5d4d4a9dae2 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -674,6 +674,13 @@ fn convert_associated_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, defaultness: hir::Defaultness, ty: Option>) { + let predicates = ty::GenericPredicates { + parent: Some(container.id()), + predicates: vec![] + }; + ccx.tcx.predicates.borrow_mut().insert(ccx.tcx.map.local_def_id(id), + predicates); + let associated_type = Rc::new(ty::AssociatedType { name: name, vis: ty::Visibility::from_hir(vis, id, ccx.tcx), @@ -831,6 +838,9 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { // Convert all the associated types. for impl_item in impl_items { if let hir::ImplItemKind::Type(ref ty) = impl_item.node { + let type_def_id = ccx.tcx.map.local_def_id(impl_item.id); + generics_of_def_id(ccx, type_def_id); + if opt_trait_ref.is_none() { span_err!(tcx.sess, impl_item.span, E0202, "associated types are not allowed in inherent impls"); @@ -898,6 +908,9 @@ fn convert_item(ccx: &CrateCtxt, it: &hir::Item) { // Convert all the associated types. for trait_item in trait_items { if let hir::TypeTraitItem(_, ref opt_ty) = trait_item.node { + let type_def_id = ccx.tcx.map.local_def_id(trait_item.id); + generics_of_def_id(ccx, type_def_id); + let typ = opt_ty.as_ref().map({ |ty| ccx.icx(&trait_predicates).to_ty(&ExplicitRscope, &ty) }); diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 9f208b7bed70..0ae059509bd1 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1168,7 +1168,7 @@ impl<'a, 'tcx> Clean for (DefId, &'a ty::PolyFnSig<'tcx>) { Argument { type_: t.clean(cx), id: ast::CRATE_NODE_ID, - name: names.next().unwrap_or("".to_string()), + name: names.next().map_or("".to_string(), |name| name.to_string()), } }).collect(), }, diff --git a/src/rustc/Cargo.lock b/src/rustc/Cargo.lock index d8a02badceed..69e3eab22e91 100644 --- a/src/rustc/Cargo.lock +++ b/src/rustc/Cargo.lock @@ -219,7 +219,6 @@ dependencies = [ "log 0.0.0", "rustc 0.0.0", "rustc_back 0.0.0", - "rustc_bitflags 0.0.0", "rustc_const_math 0.0.0", "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", diff --git a/src/test/run-pass-fulldeps/issue-11881.rs b/src/test/run-pass-fulldeps/issue-11881.rs index 8369d08db36d..914e3dd49324 100644 --- a/src/test/run-pass-fulldeps/issue-11881.rs +++ b/src/test/run-pass-fulldeps/issue-11881.rs @@ -34,14 +34,14 @@ struct Bar { enum WireProtocol { JSON, - RBML, + Opaque, // ... } fn encode_json(val: &T, wr: &mut Cursor>) { write!(wr, "{}", json::as_json(val)); } -fn encode_rbml(val: &T, wr: &mut Cursor>) { +fn encode_opaque(val: &T, wr: &mut Cursor>) { let mut encoder = opaque::Encoder::new(wr); val.encode(&mut encoder); } @@ -52,6 +52,6 @@ pub fn main() { let proto = WireProtocol::JSON; match proto { WireProtocol::JSON => encode_json(&target, &mut wr), - WireProtocol::RBML => encode_rbml(&target, &mut wr) + WireProtocol::Opaque => encode_opaque(&target, &mut wr) } } From dc26a23301d8c435fae647174bd2906babbdb2f9 Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Sat, 17 Sep 2016 10:33:47 +0300 Subject: [PATCH 429/443] rustc_metadata: reduce Lazy{,Seq} overhead by using a relative encoding. --- src/librustc_metadata/decoder.rs | 47 +++++++++++++++++--- src/librustc_metadata/encoder.rs | 73 +++++++++++++++++++++++++------- src/librustc_metadata/schema.rs | 54 +++++++++++++++++++++-- 3 files changed, 148 insertions(+), 26 deletions(-) diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 7a4d3ed657a1..973ef6030a3e 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -52,8 +52,11 @@ pub struct DecodeContext<'a, 'tcx: 'a> { cdata: Option<&'a CrateMetadata>, from_id_range: IdRange, to_id_range: IdRange, + // Cache the last used filemap for translating spans as an optimization. last_filemap_index: usize, + + lazy_state: LazyState } /// Abstract over the various ways one can create metadata decoders. @@ -73,7 +76,8 @@ pub trait Metadata<'a, 'tcx>: Copy { tcx: self.tcx(), from_id_range: id_range, to_id_range: id_range, - last_filemap_index: 0 + last_filemap_index: 0, + lazy_state: LazyState::NoNode } } } @@ -114,13 +118,16 @@ impl<'a, 'tcx> Metadata<'a, 'tcx> for (&'a CrateMetadata, TyCtxt<'a, 'tcx, 'tcx> impl<'a, 'tcx: 'a, T: Decodable> Lazy { pub fn decode>(self, meta: M) -> T { - T::decode(&mut meta.decoder(self.position)).unwrap() + let mut dcx = meta.decoder(self.position); + dcx.lazy_state = LazyState::NodeStart(self.position); + T::decode(&mut dcx).unwrap() } } impl<'a, 'tcx: 'a, T: Decodable> LazySeq { pub fn decode>(self, meta: M) -> impl Iterator + 'a { let mut dcx = meta.decoder(self.position); + dcx.lazy_state = LazyState::NodeStart(self.position); (0..self.len).map(move |_| { T::decode(&mut dcx).unwrap() }) @@ -137,12 +144,33 @@ impl<'a, 'tcx> DecodeContext<'a, 'tcx> { } fn with_position R, R>(&mut self, pos: usize, f: F) -> R { - let new = opaque::Decoder::new(self.opaque.data, pos); - let old = mem::replace(&mut self.opaque, new); + let new_opaque = opaque::Decoder::new(self.opaque.data, pos); + let old_opaque = mem::replace(&mut self.opaque, new_opaque); + let old_state = mem::replace(&mut self.lazy_state, LazyState::NoNode); let r = f(self); - self.opaque = old; + self.opaque = old_opaque; + self.lazy_state = old_state; r } + + fn read_lazy_distance(&mut self, min_size: usize) + -> Result::Error> { + let distance = self.read_usize()?; + let position = match self.lazy_state { + LazyState::NoNode => { + bug!("read_lazy_distance: outside of a metadata node") + } + LazyState::NodeStart(start) => { + assert!(distance + min_size <= start); + start - distance - min_size + } + LazyState::Previous(last_min_end) => { + last_min_end + distance + } + }; + self.lazy_state = LazyState::Previous(position + min_size); + Ok(position) + } } macro_rules! decoder_methods { @@ -185,14 +213,19 @@ impl<'doc, 'tcx> Decoder for DecodeContext<'doc, 'tcx> { impl<'a, 'tcx, T> SpecializedDecoder> for DecodeContext<'a, 'tcx> { fn specialized_decode(&mut self) -> Result, Self::Error> { - Ok(Lazy::with_position(self.read_usize()?)) + Ok(Lazy::with_position(self.read_lazy_distance(Lazy::::min_size())?)) } } impl<'a, 'tcx, T> SpecializedDecoder> for DecodeContext<'a, 'tcx> { fn specialized_decode(&mut self) -> Result, Self::Error> { let len = self.read_usize()?; - Ok(LazySeq::with_position_and_length(self.read_usize()?, len)) + let position = if len == 0 { + 0 + } else { + self.read_lazy_distance(LazySeq::::min_size(len))? + }; + Ok(LazySeq::with_position_and_length(position, len)) } } diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 185aa9e3b921..0f067270b80f 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -53,6 +53,7 @@ pub struct EncodeContext<'a, 'tcx: 'a> { reachable: &'a NodeSet, mir_map: &'a MirMap<'tcx>, + lazy_state: LazyState, type_shorthands: FnvHashMap, usize>, predicate_shorthands: FnvHashMap, usize>, } @@ -95,14 +96,17 @@ impl<'a, 'tcx> Encoder for EncodeContext<'a, 'tcx> { impl<'a, 'tcx, T> SpecializedEncoder> for EncodeContext<'a, 'tcx> { fn specialized_encode(&mut self, lazy: &Lazy) -> Result<(), Self::Error> { - self.emit_usize(lazy.position) + self.emit_lazy_distance(lazy.position, Lazy::::min_size()) } } impl<'a, 'tcx, T> SpecializedEncoder> for EncodeContext<'a, 'tcx> { fn specialized_encode(&mut self, seq: &LazySeq) -> Result<(), Self::Error> { self.emit_usize(seq.len)?; - self.emit_usize(seq.position) + if seq.len == 0 { + return Ok(()); + } + self.emit_lazy_distance(seq.position, LazySeq::::min_size(seq.len)) } } @@ -129,24 +133,62 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.opaque.position() } - pub fn lazy(&mut self, value: &T) -> Lazy { + fn emit_node R, R>(&mut self, f: F) -> R { + assert_eq!(self.lazy_state, LazyState::NoNode); let pos = self.position(); - value.encode(self).unwrap(); - Lazy::with_position(pos) + self.lazy_state = LazyState::NodeStart(pos); + let r = f(self, pos); + self.lazy_state = LazyState::NoNode; + r + } + + fn emit_lazy_distance(&mut self, position: usize, min_size: usize) + -> Result<(), ::Error> { + let min_end = position + min_size; + let distance = match self.lazy_state { + LazyState::NoNode => { + bug!("emit_lazy_distance: outside of a metadata node") + } + LazyState::NodeStart(start) => { + assert!(min_end <= start); + start - min_end + } + LazyState::Previous(last_min_end) => { + assert!(last_min_end <= position); + position - last_min_end + } + }; + self.lazy_state = LazyState::Previous(min_end); + self.emit_usize(distance) + } + + pub fn lazy(&mut self, value: &T) -> Lazy { + self.emit_node(|ecx, pos| { + value.encode(ecx).unwrap(); + + assert!(pos + Lazy::::min_size() <= ecx.position()); + Lazy::with_position(pos) + }) } fn lazy_seq(&mut self, iter: I) -> LazySeq where I: IntoIterator, T: Encodable { - let pos = self.position(); - let len = iter.into_iter().map(|value| value.encode(self).unwrap()).count(); - LazySeq::with_position_and_length(pos, len) + self.emit_node(|ecx, pos| { + let len = iter.into_iter().map(|value| value.encode(ecx).unwrap()).count(); + + assert!(pos + LazySeq::::min_size(len) <= ecx.position()); + LazySeq::with_position_and_length(pos, len) + }) } fn lazy_seq_ref<'b, I, T>(&mut self, iter: I) -> LazySeq where I: IntoIterator, T: 'b + Encodable { - let pos = self.position(); - let len = iter.into_iter().map(|value| value.encode(self).unwrap()).count(); - LazySeq::with_position_and_length(pos, len) + self.emit_node(|ecx, pos| { + let len = iter.into_iter().map(|value| value.encode(ecx).unwrap()).count(); + + assert!(pos + LazySeq::::min_size(len) <= ecx.position()); + LazySeq::with_position_and_length(pos, len) + }) } /// Encode the given value or a previously cached shorthand. @@ -1262,16 +1304,16 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { None }, - index: index, crate_deps: crate_deps, dylib_dependency_formats: dylib_dependency_formats, - native_libraries: native_libraries, lang_items: lang_items, lang_items_missing: lang_items_missing, + native_libraries: native_libraries, + codemap: codemap, + macro_defs: macro_defs, impls: impls, reachable_ids: reachable_ids, - macro_defs: macro_defs, - codemap: codemap + index: index, }); let total_bytes = self.position(); @@ -1345,6 +1387,7 @@ pub fn encode_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, cstore: cstore, reachable: reachable, mir_map: mir_map, + lazy_state: LazyState::NoNode, type_shorthands: Default::default(), predicate_shorthands: Default::default() }.encode_crate_root(); diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index b4ea2b19bf08..956577ed8fb8 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -52,6 +52,19 @@ pub const SHORTHAND_OFFSET: usize = 0x80; /// A value of type T referred to by its absolute position /// in the metadata, and which can be decoded lazily. +/// +/// Metadata is effective a tree, encoded in post-order, +/// and with the root's position written next to the header. +/// That means every single `Lazy` points to some previous +/// location in the metadata and is part of a larger node. +/// +/// The first `Lazy` in a node is encoded as the backwards +/// distance from the position where the containing node +/// starts and where the `Lazy` points to, while the rest +/// use the forward distance from the previous `Lazy`. +/// Distances start at 1, as 0-byte nodes are invalid. +/// Also invalid are nodes being referred in a different +/// order than they were encoded in. #[must_use] pub struct Lazy { pub position: usize, @@ -65,6 +78,12 @@ impl Lazy { _marker: PhantomData } } + + /// Returns the minimum encoded size of a value of type `T`. + // FIXME(eddyb) Give better estimates for certain types. + pub fn min_size() -> usize { + 1 + } } impl Copy for Lazy {} @@ -77,10 +96,16 @@ impl serialize::UseSpecializedDecodable for Lazy {} /// A sequence of type T referred to by its absolute position /// in the metadata and length, and which can be decoded lazily. +/// The sequence is a single node for the purposes of `Lazy`. /// /// Unlike `Lazy>`, the length is encoded next to the /// position, not at the position, which means that the length /// doesn't need to be known before encoding all the elements. +/// +/// If the length is 0, no position is encoded, but otherwise, +/// the encoding is that of `Lazy`, with the distinction that +/// the minimal distance the length of the sequence, i.e. +/// it's assumed there's no 0-byte element in the sequence. #[must_use] pub struct LazySeq { pub len: usize, @@ -100,6 +125,11 @@ impl LazySeq { _marker: PhantomData } } + + /// Returns the minimum encoded size of `length` values of type `T`. + pub fn min_size(length: usize) -> usize { + length + } } impl Copy for LazySeq {} @@ -110,6 +140,22 @@ impl Clone for LazySeq { impl serialize::UseSpecializedEncodable for LazySeq {} impl serialize::UseSpecializedDecodable for LazySeq {} +/// Encoding / decoding state for `Lazy` and `LazySeq`. +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub enum LazyState { + /// Outside of a metadata node. + NoNode, + + /// Inside a metadata node, and before any `Lazy` or `LazySeq`. + /// The position is that of the node itself. + NodeStart(usize), + + /// Inside a metadata node, with a previous `Lazy` or `LazySeq`. + /// The position is a conservative estimate of where that + /// previous `Lazy` / `LazySeq` would end (see their comments). + Previous(usize) +} + #[derive(RustcEncodable, RustcDecodable)] pub struct CrateRoot { pub rustc_version: String, @@ -121,16 +167,16 @@ pub struct CrateRoot { pub plugin_registrar_fn: Option, pub macro_derive_registrar: Option, - pub index: LazySeq, pub crate_deps: LazySeq, pub dylib_dependency_formats: LazySeq>, - pub native_libraries: LazySeq<(NativeLibraryKind, String)>, pub lang_items: LazySeq<(DefIndex, usize)>, pub lang_items_missing: LazySeq, + pub native_libraries: LazySeq<(NativeLibraryKind, String)>, + pub codemap: LazySeq, + pub macro_defs: LazySeq, pub impls: LazySeq, pub reachable_ids: LazySeq, - pub macro_defs: LazySeq, - pub codemap: LazySeq + pub index: LazySeq, } #[derive(RustcEncodable, RustcDecodable)] From dadbaa48ac5a86810aea17accd2f85194dc8cfd3 Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Sat, 17 Sep 2016 13:34:55 +0300 Subject: [PATCH 430/443] rustc_metadata: move opt_item_name to TyCtxt::item_name. --- src/librustc/hir/map/definitions.rs | 26 +++++++++++++- src/librustc/middle/cstore.rs | 4 +-- src/librustc/ty/item_path.rs | 3 +- src/librustc/ty/mod.rs | 21 ++++++++--- src/librustc_metadata/csearch.rs | 10 ------ src/librustc_metadata/decoder.rs | 39 +++------------------ src/librustc_resolve/build_reduced_graph.rs | 3 +- 7 files changed, 51 insertions(+), 55 deletions(-) diff --git a/src/librustc/hir/map/definitions.rs b/src/librustc/hir/map/definitions.rs index c0c28939ab27..af751e51d931 100644 --- a/src/librustc/hir/map/definitions.rs +++ b/src/librustc/hir/map/definitions.rs @@ -14,7 +14,7 @@ use rustc_data_structures::fnv::FnvHashMap; use std::fmt::Write; use std::hash::{Hash, Hasher, SipHasher}; use syntax::{ast, visit}; -use syntax::parse::token::InternedString; +use syntax::parse::token::{self, InternedString}; use ty::TyCtxt; use util::nodemap::NodeMap; @@ -326,6 +326,30 @@ impl Definitions { } impl DefPathData { + pub fn get_opt_name(&self) -> Option { + use self::DefPathData::*; + match *self { + TypeNs(ref name) | + ValueNs(ref name) | + Module(ref name) | + MacroDef(ref name) | + TypeParam(ref name) | + LifetimeDef(ref name) | + EnumVariant(ref name) | + Binding(ref name) | + Field(ref name) => Some(token::intern(name)), + + Impl | + CrateRoot | + InlinedRoot(_) | + Misc | + ClosureExpr | + StructCtor | + Initializer | + ImplTrait => None + } + } + pub fn as_interned_str(&self) -> InternedString { use self::DefPathData::*; match *self { diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 658825d417e4..2ebf7ba6d53d 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -132,7 +132,6 @@ pub trait CrateStore<'tcx> { fn item_type<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> Ty<'tcx>; fn visible_parent_map<'a>(&'a self) -> ::std::cell::RefMut<'a, DefIdMap>; - fn opt_item_name(&self, def: DefId) -> Option; fn item_predicates<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> ty::GenericPredicates<'tcx>; fn item_super_predicates<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) @@ -293,7 +292,6 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { fn visible_parent_map<'a>(&'a self) -> ::std::cell::RefMut<'a, DefIdMap> { bug!("visible_parent_map") } - fn opt_item_name(&self, def: DefId) -> Option { bug!("opt_item_name") } fn item_predicates<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> ty::GenericPredicates<'tcx> { bug!("item_predicates") } fn item_super_predicates<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) @@ -424,4 +422,4 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { pub trait MacroLoader { fn load_crate(&mut self, extern_crate: &ast::Item, allows_macros: bool) -> Vec; -} \ No newline at end of file +} diff --git a/src/librustc/ty/item_path.rs b/src/librustc/ty/item_path.rs index 5f121b568c3a..ca12dde73b84 100644 --- a/src/librustc/ty/item_path.rs +++ b/src/librustc/ty/item_path.rs @@ -138,7 +138,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } } - cur_path.push(self.sess.cstore.opt_item_name(cur_def).unwrap_or_else(|| + cur_path.push(self.sess.cstore.def_key(cur_def) + .disambiguated_data.data.get_opt_name().unwrap_or_else(|| token::intern(""))); match visible_parent_map.get(&cur_def) { Some(&def) => cur_def = def, diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 8a9b2846ac66..d7076ddf0445 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -21,7 +21,7 @@ use dep_graph::{self, DepNode}; use hir::map as ast_map; use middle; use hir::def::{Def, PathResolution, ExportMap}; -use hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; +use hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE}; use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem}; use middle::region::{CodeExtent, ROOT_CODE_EXTENT}; use traits; @@ -43,7 +43,7 @@ use std::slice; use std::vec::IntoIter; use syntax::ast::{self, Name, NodeId}; use syntax::attr; -use syntax::parse::token::InternedString; +use syntax::parse::token::{self, InternedString}; use syntax_pos::{DUMMY_SP, Span}; use rustc_const_math::ConstInt; @@ -2390,10 +2390,21 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn item_name(self, id: DefId) -> ast::Name { if let Some(id) = self.map.as_local_node_id(id) { self.map.name(id) + } else if id.index == CRATE_DEF_INDEX { + token::intern(&self.sess.cstore.original_crate_name(id.krate)) } else { - self.sess.cstore.opt_item_name(id).unwrap_or_else(|| { - bug!("item_name: no name for {:?}", self.def_path(id)); - }) + let def_key = self.sess.cstore.def_key(id); + // The name of a StructCtor is that of its struct parent. + if let ast_map::DefPathData::StructCtor = def_key.disambiguated_data.data { + self.item_name(DefId { + krate: id.krate, + index: def_key.parent.unwrap() + }) + } else { + def_key.disambiguated_data.data.get_opt_name().unwrap_or_else(|| { + bug!("item_name: no name for {:?}", self.def_path(id)); + }) + } } } diff --git a/src/librustc_metadata/csearch.rs b/src/librustc_metadata/csearch.rs index f508c5dc9cfb..7013720224a6 100644 --- a/src/librustc_metadata/csearch.rs +++ b/src/librustc_metadata/csearch.rs @@ -127,16 +127,6 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { self.get_crate_data(did.krate).get_fn_arg_names(did.index) } - fn opt_item_name(&self, def: DefId) -> Option { - self.dep_graph.read(DepNode::MetaData(def)); - let cdata = self.get_crate_data(def.krate); - if def.index == CRATE_DEF_INDEX { - Some(token::intern(&cdata.name())) - } else { - cdata.maybe_get_item_name(def.index) - } - } - fn inherent_implementations_for_type(&self, def_id: DefId) -> Vec { self.dep_graph.read(DepNode::MetaData(def_id)); diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index 973ef6030a3e..d98e8d62c2d1 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -43,7 +43,6 @@ use rustc_serialize::{Decodable, Decoder, SpecializedDecoder, opaque}; use syntax::attr; use syntax::ast::{self, NodeId}; use syntax::codemap; -use syntax::parse::token; use syntax_pos::{self, Span, BytePos, Pos}; pub struct DecodeContext<'a, 'tcx: 'a> { @@ -469,32 +468,6 @@ impl<'tcx> EntryKind<'tcx> { } } -fn def_key_name(def_key: &hir_map::DefKey) -> Option { - match def_key.disambiguated_data.data { - DefPathData::TypeNs(ref name) | - DefPathData::ValueNs(ref name) | - DefPathData::Module(ref name) | - DefPathData::MacroDef(ref name) | - DefPathData::TypeParam(ref name) | - DefPathData::LifetimeDef(ref name) | - DefPathData::EnumVariant(ref name) | - DefPathData::Field(ref name) | - DefPathData::Binding(ref name) => { - Some(token::intern(name)) - } - - DefPathData::InlinedRoot(_) => bug!("unexpected DefPathData"), - - DefPathData::CrateRoot | - DefPathData::Misc | - DefPathData::Impl | - DefPathData::ClosureExpr | - DefPathData::StructCtor | - DefPathData::Initializer | - DefPathData::ImplTrait => None - } -} - impl<'a, 'tcx> CrateMetadata { fn maybe_entry(&self, item_id: DefIndex) -> Option>> { self.root.index.lookup(self.blob.raw_bytes(), item_id) @@ -518,7 +491,8 @@ impl<'a, 'tcx> CrateMetadata { } fn item_name(&self, item: &Entry<'tcx>) -> ast::Name { - def_key_name(&item.def_key.decode(self)).expect("no name in item_name") + item.def_key.decode(self).disambiguated_data.data.get_opt_name() + .expect("no name in item_name") } pub fn get_def(&self, index: DefIndex) -> Option { @@ -708,7 +682,8 @@ impl<'a, 'tcx> CrateMetadata { _ => {} } - if let Some(name) = def_key_name(&child.def_key.decode(self)) { + let def_key = child.def_key.decode(self); + if let Some(name) = def_key.disambiguated_data.data.get_opt_name() { callback(def::Export { def_id: self.local_def_id(child_index), name: name @@ -724,10 +699,6 @@ impl<'a, 'tcx> CrateMetadata { } } - pub fn maybe_get_item_name(&self, id: DefIndex) -> Option { - def_key_name(&self.entry(id).def_key.decode(self)) - } - pub fn maybe_get_item_ast(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefIndex) -> Option<&'tcx InlinedItem> { debug!("Looking up item: {:?}", id); @@ -757,7 +728,7 @@ impl<'a, 'tcx> CrateMetadata { let parent_and_name = || { let def_key = item.def_key.decode(self); (self.local_def_id(def_key.parent.unwrap()), - def_key_name(&def_key).unwrap()) + def_key.disambiguated_data.data.get_opt_name().unwrap()) }; Some(match item.kind { diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 1714398f2fed..3c5e9e6cd3a9 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -436,7 +436,8 @@ impl<'b> Resolver<'b> { let trait_item_def_ids = self.session.cstore.impl_or_trait_items(def_id); for &trait_item_def in &trait_item_def_ids { let trait_item_name = - self.session.cstore.opt_item_name(trait_item_def) + self.session.cstore.def_key(trait_item_def) + .disambiguated_data.data.get_opt_name() .expect("opt_item_name returned None for trait"); debug!("(building reduced graph for external crate) ... adding trait item \ From f2283a7be0afb00ff4d6bb1e179a75811286d2cd Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Sat, 17 Sep 2016 14:25:19 +0300 Subject: [PATCH 431/443] rustc_metadata: fix for the new `?` ambiguity around collect. --- src/librustc_metadata/decoder.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index d98e8d62c2d1..e718a107bbe2 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -366,7 +366,7 @@ impl<'a, 'tcx> SpecializedDecoder> for DecodeContext } else { ty::Predicate::decode(self) } - }).collect()? + }).collect::, _>>()? }) } } From b01d4891e2935cf24242e44b50dfa37efc28d28c Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Sat, 17 Sep 2016 19:06:21 +0300 Subject: [PATCH 432/443] rustc: don't recurse through nested items in decoded HIR fragments. --- src/librustc/hir/map/collector.rs | 10 +++++++++- src/librustc/hir/map/def_collector.rs | 9 --------- src/test/run-pass/auxiliary/issue-17718-aux.rs | 3 +-- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/src/librustc/hir/map/collector.rs b/src/librustc/hir/map/collector.rs index 6c6de8e89024..3d9031a136e2 100644 --- a/src/librustc/hir/map/collector.rs +++ b/src/librustc/hir/map/collector.rs @@ -27,6 +27,10 @@ pub struct NodeCollector<'ast> { pub map: Vec>, /// The parent of this node pub parent_node: NodeId, + /// If true, completely ignore nested items. We set this when loading + /// HIR from metadata, since in that case we only want the HIR for + /// one specific item (and not the ones nested inside of it). + pub ignore_nested_items: bool } impl<'ast> NodeCollector<'ast> { @@ -35,6 +39,7 @@ impl<'ast> NodeCollector<'ast> { krate: krate, map: vec![], parent_node: CRATE_NODE_ID, + ignore_nested_items: false }; collector.insert_entry(CRATE_NODE_ID, RootCrate); @@ -52,6 +57,7 @@ impl<'ast> NodeCollector<'ast> { krate: krate, map: map, parent_node: parent_node, + ignore_nested_items: true }; assert_eq!(parent_def_path.krate, parent_def_id.krate); @@ -88,7 +94,9 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> { /// their outer items. fn visit_nested_item(&mut self, item: ItemId) { debug!("visit_nested_item: {:?}", item); - self.visit_item(self.krate.item(item.id)) + if !self.ignore_nested_items { + self.visit_item(self.krate.item(item.id)) + } } fn visit_item(&mut self, i: &'ast Item) { diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs index 29fb19fd4215..ea1f8aac7a55 100644 --- a/src/librustc/hir/map/def_collector.rs +++ b/src/librustc/hir/map/def_collector.rs @@ -285,15 +285,6 @@ impl<'ast> visit::Visitor for DefCollector<'ast> { // We walk the HIR rather than the AST when reading items from metadata. impl<'ast> intravisit::Visitor<'ast> for DefCollector<'ast> { - /// Because we want to track parent items and so forth, enable - /// deep walking so that we walk nested items in the context of - /// their outer items. - fn visit_nested_item(&mut self, item_id: hir::ItemId) { - debug!("visit_nested_item: {:?}", item_id); - let item = self.hir_crate.unwrap().item(item_id.id); - self.visit_item(item) - } - fn visit_item(&mut self, i: &'ast hir::Item) { debug!("visit_item: {:?}", i); diff --git a/src/test/run-pass/auxiliary/issue-17718-aux.rs b/src/test/run-pass/auxiliary/issue-17718-aux.rs index 373fc0421754..cf7fdd7f983f 100644 --- a/src/test/run-pass/auxiliary/issue-17718-aux.rs +++ b/src/test/run-pass/auxiliary/issue-17718-aux.rs @@ -14,11 +14,10 @@ use std::sync::atomic; pub const C1: usize = 1; pub const C2: atomic::AtomicUsize = atomic::AtomicUsize::new(0); -pub const C3: fn() = foo; +pub const C3: fn() = { fn foo() {} foo }; pub const C4: usize = C1 * C1 + C1 / C1; pub const C5: &'static usize = &C4; pub static S1: usize = 3; pub static S2: atomic::AtomicUsize = atomic::AtomicUsize::new(0); -fn foo() {} From 221d1a97e505d00fc1664c5b2d9041f8b78aa933 Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Sat, 17 Sep 2016 23:31:03 +0300 Subject: [PATCH 433/443] serialize: allow specifying the default behavior for specializations. --- src/librustc/hir/def_id.rs | 16 +++++++++++++--- src/librustc/ty/mod.rs | 4 ++-- src/libserialize/serialize.rs | 36 ++++++++++++++++++----------------- src/libsyntax/ast.rs | 14 ++++++++++++-- src/libsyntax_pos/lib.rs | 14 +++++++++++--- 5 files changed, 57 insertions(+), 27 deletions(-) diff --git a/src/librustc/hir/def_id.rs b/src/librustc/hir/def_id.rs index f36fcfd51873..399243551d65 100644 --- a/src/librustc/hir/def_id.rs +++ b/src/librustc/hir/def_id.rs @@ -11,12 +11,12 @@ use ty; use rustc_data_structures::indexed_vec::Idx; -use serialize; +use serialize::{self, Encoder, Decoder}; use std::fmt; use std::u32; -#[derive(Clone, Copy, Eq, Ord, PartialOrd, PartialEq, RustcEncodable, Hash, Debug)] +#[derive(Clone, Copy, Eq, Ord, PartialOrd, PartialEq, Hash, Debug)] pub struct CrateNum(u32); impl Idx for CrateNum { @@ -59,7 +59,17 @@ impl fmt::Display for CrateNum { } } -impl serialize::UseSpecializedDecodable for CrateNum {} +impl serialize::UseSpecializedEncodable for CrateNum { + fn default_encode(&self, s: &mut S) -> Result<(), S::Error> { + s.emit_u32(self.0) + } +} + +impl serialize::UseSpecializedDecodable for CrateNum { + fn default_decode(d: &mut D) -> Result { + d.read_u32().map(CrateNum) + } +} /// A DefIndex is an index into the hir-map for a crate, identifying a /// particular definition. It should really be considered an interned diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index d7076ddf0445..9eb87fa2ed43 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1470,8 +1470,8 @@ impl<'tcx, 'container> Hash for AdtDefData<'tcx, 'container> { } } -impl<'tcx> Encodable for AdtDef<'tcx> { - fn encode(&self, s: &mut S) -> Result<(), S::Error> { +impl<'tcx> serialize::UseSpecializedEncodable for AdtDef<'tcx> { + fn default_encode(&self, s: &mut S) -> Result<(), S::Error> { self.did.encode(s) } } diff --git a/src/libserialize/serialize.rs b/src/libserialize/serialize.rs index 88f6c12e9804..6650a981884d 100644 --- a/src/libserialize/serialize.rs +++ b/src/libserialize/serialize.rs @@ -691,42 +691,39 @@ impl SpecializationError for E { /// Implement this trait on encoders, with `T` being the type /// you want to encode (employing `UseSpecializedEncodable`), /// using a strategy specific to the encoder. -/// Can also be implemented alongside `UseSpecializedEncodable` -/// to provide a default `specialized_encode` for encoders -/// which do not implement `SpecializedEncoder` themselves. -pub trait SpecializedEncoder: Encoder { +pub trait SpecializedEncoder: Encoder { /// Encode the value in a manner specific to this encoder state. - /// Defaults to returning an error (see `SpecializationError`). fn specialized_encode(&mut self, value: &T) -> Result<(), Self::Error>; } -impl SpecializedEncoder for E { - default fn specialized_encode(&mut self, _: &T) -> Result<(), E::Error> { - Err(E::Error::not_found::("SpecializedEncoder", "specialized_encode")) +impl SpecializedEncoder for E { + default fn specialized_encode(&mut self, value: &T) -> Result<(), E::Error> { + value.default_encode(self) } } /// Implement this trait on decoders, with `T` being the type /// you want to decode (employing `UseSpecializedDecodable`), /// using a strategy specific to the decoder. -/// Can also be implemented alongside `UseSpecializedDecodable` -/// to provide a default `specialized_decode` for decoders -/// which do not implement `SpecializedDecoder` themselves. -pub trait SpecializedDecoder: Decoder { +pub trait SpecializedDecoder: Decoder { /// Decode a value in a manner specific to this decoder state. - /// Defaults to returning an error (see `SpecializationError`). fn specialized_decode(&mut self) -> Result; } -impl SpecializedDecoder for D { +impl SpecializedDecoder for D { default fn specialized_decode(&mut self) -> Result { - Err(D::Error::not_found::("SpecializedDecoder", "specialized_decode")) + T::default_decode(self) } } /// Implement this trait on your type to get an `Encodable` /// implementation which goes through `SpecializedEncoder`. -pub trait UseSpecializedEncodable {} +pub trait UseSpecializedEncodable { + /// Defaults to returning an error (see `SpecializationError`). + fn default_encode(&self, _: &mut E) -> Result<(), E::Error> { + Err(E::Error::not_found::("SpecializedEncoder", "specialized_encode")) + } +} impl Encodable for T { default fn encode(&self, e: &mut E) -> Result<(), E::Error> { @@ -736,7 +733,12 @@ impl Encodable for T { /// Implement this trait on your type to get an `Decodable` /// implementation which goes through `SpecializedDecoder`. -pub trait UseSpecializedDecodable: Sized {} +pub trait UseSpecializedDecodable: Sized { + /// Defaults to returning an error (see `SpecializationError`). + fn default_decode(_: &mut D) -> Result { + Err(D::Error::not_found::("SpecializedDecoder", "specialized_decode")) + } +} impl Decodable for T { default fn decode(d: &mut D) -> Result { diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 70e614f9c9a9..c18b36161dfc 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -300,7 +300,7 @@ pub struct ParenthesizedParameterData { pub output: Option>, } -#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, RustcEncodable, Hash, Debug)] +#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash, Debug)] pub struct NodeId(u32); impl NodeId { @@ -328,7 +328,17 @@ impl fmt::Display for NodeId { } } -impl serialize::UseSpecializedDecodable for NodeId {} +impl serialize::UseSpecializedEncodable for NodeId { + fn default_encode(&self, s: &mut S) -> Result<(), S::Error> { + s.emit_u32(self.0) + } +} + +impl serialize::UseSpecializedDecodable for NodeId { + fn default_decode(d: &mut D) -> Result { + d.read_u32().map(NodeId) + } +} /// Node id used to represent the root of the crate. pub const CRATE_NODE_ID: NodeId = NodeId(0); diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index fb59f4111067..8c8b4173fe58 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -138,8 +138,8 @@ pub struct SpanLabel { pub label: Option, } -impl Encodable for Span { - fn encode(&self, s: &mut S) -> Result<(), S::Error> { +impl serialize::UseSpecializedEncodable for Span { + fn default_encode(&self, s: &mut S) -> Result<(), S::Error> { s.emit_struct("Span", 2, |s| { s.emit_struct_field("lo", 0, |s| { self.lo.encode(s) @@ -152,7 +152,15 @@ impl Encodable for Span { } } -impl serialize::UseSpecializedDecodable for Span {} +impl serialize::UseSpecializedDecodable for Span { + fn default_decode(d: &mut D) -> Result { + d.read_struct("Span", 2, |d| { + let lo = d.read_struct_field("lo", 0, Decodable::decode)?; + let hi = d.read_struct_field("hi", 1, Decodable::decode)?; + Ok(mk_sp(lo, hi)) + }) + } +} fn default_span_debug(span: Span, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "Span {{ lo: {:?}, hi: {:?}, expn_id: {:?} }}", From a23b8cafeceb0560c58332cd9a0deb2357778ad1 Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Sun, 18 Sep 2016 11:12:29 +0300 Subject: [PATCH 434/443] rustc: don't hash the --extern crate name, but the original one, in DefPath. --- src/librustc/hir/map/definitions.rs | 8 ++------ src/librustc/ty/context.rs | 8 ++++++++ src/librustc/ty/item_path.rs | 6 +----- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/librustc/hir/map/definitions.rs b/src/librustc/hir/map/definitions.rs index af751e51d931..f404f60cc9ce 100644 --- a/src/librustc/hir/map/definitions.rs +++ b/src/librustc/hir/map/definitions.rs @@ -115,11 +115,7 @@ impl DefPath { pub fn to_string(&self, tcx: TyCtxt) -> String { let mut s = String::with_capacity(self.data.len() * 16); - if self.krate == LOCAL_CRATE { - s.push_str(&tcx.crate_name(self.krate)); - } else { - s.push_str(&tcx.sess.cstore.original_crate_name(self.krate)); - } + s.push_str(&tcx.original_crate_name(self.krate)); s.push_str("/"); s.push_str(&tcx.crate_disambiguator(self.krate)); @@ -141,7 +137,7 @@ impl DefPath { } pub fn deterministic_hash_to(&self, tcx: TyCtxt, state: &mut H) { - tcx.crate_name(self.krate).hash(state); + tcx.original_crate_name(self.krate).hash(state); tcx.crate_disambiguator(self.krate).hash(state); self.data.hash(state); } diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 0faf6750abd9..d5e5f4402bb8 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -513,6 +513,14 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } } + pub fn original_crate_name(self, cnum: CrateNum) -> token::InternedString { + if cnum == LOCAL_CRATE { + self.crate_name.clone() + } else { + self.sess.cstore.original_crate_name(cnum) + } + } + pub fn crate_disambiguator(self, cnum: CrateNum) -> token::InternedString { if cnum == LOCAL_CRATE { self.sess.local_crate_disambiguator() diff --git a/src/librustc/ty/item_path.rs b/src/librustc/ty/item_path.rs index ca12dde73b84..fdf5185eb69e 100644 --- a/src/librustc/ty/item_path.rs +++ b/src/librustc/ty/item_path.rs @@ -101,11 +101,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { RootMode::Absolute => { // In absolute mode, just write the crate name // unconditionally. - if cnum == LOCAL_CRATE { - buffer.push(&self.crate_name(cnum)); - } else { - buffer.push(&self.sess.cstore.original_crate_name(cnum)); - } + buffer.push(&self.original_crate_name(cnum)); } } } From 564f2ee33c479c74f68fd9ae33b179de0b8537c9 Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Sun, 18 Sep 2016 14:05:49 +0300 Subject: [PATCH 435/443] rustc_metadata: don't die with --test because CFG_VERSION is missing. --- src/librustc_metadata/schema.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index 956577ed8fb8..f4d1e8e17f84 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -26,8 +26,12 @@ use syntax_pos::{self, Span}; use std::marker::PhantomData; +#[cfg(not(test))] pub const RUSTC_VERSION: &'static str = concat!("rustc ", env!("CFG_VERSION")); +#[cfg(test)] +pub const RUSTC_VERSION: &'static str = "rustc 0.0.0-unit-test"; + /// Metadata encoding version. /// NB: increment this if you change the format of metadata such that /// the rustc version can't be found to compare with `RUSTC_VERSION`. From 521d3ea19323c4c3ba18effbfee58c10b2aaf28b Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Mon, 19 Sep 2016 03:45:38 +0300 Subject: [PATCH 436/443] rustc_resolve: bring back "struct called like a function" cross-crate. --- src/librustc/middle/cstore.rs | 4 +++- src/librustc_metadata/csearch.rs | 6 ++++++ src/librustc_metadata/decoder.rs | 9 +++++++++ src/librustc_resolve/build_reduced_graph.rs | 6 +++++- src/test/compile-fail/auxiliary/issue_19452_aux.rs | 13 +++++++++++++ src/test/compile-fail/issue-19452.rs | 7 +++++++ 6 files changed, 43 insertions(+), 2 deletions(-) create mode 100644 src/test/compile-fail/auxiliary/issue_19452_aux.rs diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 2ebf7ba6d53d..e57e116cea74 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -200,6 +200,7 @@ pub trait CrateStore<'tcx> { -> Option; fn def_key(&self, def: DefId) -> hir_map::DefKey; fn relative_def_path(&self, def: DefId) -> Option; + fn variant_kind(&self, def_id: DefId) -> Option; fn struct_ctor_def_id(&self, struct_def_id: DefId) -> Option; fn struct_field_names(&self, def: DefId) -> Vec; fn item_children(&self, did: DefId) -> Vec; @@ -283,7 +284,7 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { fn stability(&self, def: DefId) -> Option { bug!("stability") } fn deprecation(&self, def: DefId) -> Option { bug!("deprecation") } fn visibility(&self, def: DefId) -> ty::Visibility { bug!("visibility") } - fn closure_kind(&self, def_id: DefId) -> ty::ClosureKind { bug!("closure_kind") } + fn closure_kind(&self, def_id: DefId) -> ty::ClosureKind { bug!("closure_kind") } fn closure_ty<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> ty::ClosureTy<'tcx> { bug!("closure_ty") } fn item_variances(&self, def: DefId) -> Vec { bug!("item_variances") } @@ -376,6 +377,7 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { fn relative_def_path(&self, def: DefId) -> Option { bug!("relative_def_path") } + fn variant_kind(&self, def_id: DefId) -> Option { bug!("variant_kind") } fn struct_ctor_def_id(&self, struct_def_id: DefId) -> Option { bug!("struct_ctor_def_id") } fn struct_field_names(&self, def: DefId) -> Vec { bug!("struct_field_names") } diff --git a/src/librustc_metadata/csearch.rs b/src/librustc_metadata/csearch.rs index 7013720224a6..1f25136ffe1a 100644 --- a/src/librustc_metadata/csearch.rs +++ b/src/librustc_metadata/csearch.rs @@ -342,6 +342,12 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { self.get_crate_data(def.krate).def_path(def.index) } + fn variant_kind(&self, def_id: DefId) -> Option + { + self.dep_graph.read(DepNode::MetaData(def_id)); + self.get_crate_data(def_id.krate).get_variant_kind(def_id.index) + } + fn struct_ctor_def_id(&self, struct_def_id: DefId) -> Option { self.dep_graph.read(DepNode::MetaData(struct_def_id)); diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index e718a107bbe2..3e4a2542b270 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -787,6 +787,15 @@ impl<'a, 'tcx> CrateMetadata { self.entry(id).variances.decode(self).collect() } + pub fn get_variant_kind(&self, node_id: DefIndex) -> Option { + match self.entry(node_id).kind { + EntryKind::Struct(data) | + EntryKind::Union(data) | + EntryKind::Variant(data) => Some(data.decode(self).kind), + _ => None + } + } + pub fn get_struct_ctor_def_id(&self, node_id: DefIndex) -> Option { match self.entry(node_id).kind { EntryKind::Struct(data) => { diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 3c5e9e6cd3a9..c9591c31831a 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -411,12 +411,16 @@ impl<'b> Resolver<'b> { let module = self.new_module(parent_link, Some(def), None); let _ = self.try_define(parent, name, TypeNS, (module, DUMMY_SP, vis)); } - Def::Variant(..) => { + Def::Variant(variant_id) => { debug!("(building reduced graph for external crate) building variant {}", name); // Variants are always treated as importable to allow them to be glob used. // All variants are defined in both type and value namespaces as future-proofing. let _ = self.try_define(parent, name, TypeNS, (def, DUMMY_SP, vis)); let _ = self.try_define(parent, name, ValueNS, (def, DUMMY_SP, vis)); + if self.session.cstore.variant_kind(variant_id) == Some(ty::VariantKind::Struct) { + // Not adding fields for variants as they are not accessed with a self receiver + self.structs.insert(variant_id, Vec::new()); + } } Def::Fn(..) | Def::Static(..) | diff --git a/src/test/compile-fail/auxiliary/issue_19452_aux.rs b/src/test/compile-fail/auxiliary/issue_19452_aux.rs new file mode 100644 index 000000000000..205566e4b1f5 --- /dev/null +++ b/src/test/compile-fail/auxiliary/issue_19452_aux.rs @@ -0,0 +1,13 @@ +// 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. + +pub enum Homura { + Madoka { age: u32 } +} diff --git a/src/test/compile-fail/issue-19452.rs b/src/test/compile-fail/issue-19452.rs index 15d5d2b80c31..34872b7c8c50 100644 --- a/src/test/compile-fail/issue-19452.rs +++ b/src/test/compile-fail/issue-19452.rs @@ -8,6 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// aux-build:issue_19452_aux.rs +extern crate issue_19452_aux; + enum Homura { Madoka { age: u32 } } @@ -16,4 +19,8 @@ fn main() { let homura = Homura::Madoka; //~^ ERROR uses it like a function //~| struct called like a function + + let homura = issue_19452_aux::Homura::Madoka; + //~^ ERROR uses it like a function + //~| struct called like a function } From ade79d760905ab589851ca9e9ab3bb583e4da7c4 Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Mon, 19 Sep 2016 12:47:47 +0300 Subject: [PATCH 437/443] rustc_trans: simplify vtable and symbol handling. --- src/librustc/traits/mod.rs | 84 ++++++++- src/librustc/traits/specialize/mod.rs | 39 +++- src/librustc_trans/back/symbol_names.rs | 44 ++--- src/librustc_trans/callee.rs | 29 ++- src/librustc_trans/closure.rs | 8 +- src/librustc_trans/collector.rs | 80 +++------ src/librustc_trans/common.rs | 38 ---- src/librustc_trans/meth.rs | 230 +++--------------------- 8 files changed, 198 insertions(+), 354 deletions(-) diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index a96cf1111e1d..7ba10d9c0a58 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -40,7 +40,7 @@ pub use self::select::{EvaluationCache, SelectionContext, SelectionCache}; pub use self::select::{MethodMatchResult, MethodMatched, MethodAmbiguous, MethodDidNotMatch}; pub use self::select::{MethodMatchedData}; // intentionally don't export variants pub use self::specialize::{OverlapError, specialization_graph, specializes, translate_substs}; -pub use self::specialize::{SpecializesCache}; +pub use self::specialize::{SpecializesCache, find_method}; pub use self::util::elaborate_predicates; pub use self::util::supertraits; pub use self::util::Supertraits; @@ -527,6 +527,88 @@ pub fn fully_normalize<'a, 'gcx, 'tcx, T>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, Ok(resolved_value) } +/// Normalizes the predicates and checks whether they hold. If this +/// returns false, then either normalize encountered an error or one +/// of the predicates did not hold. Used when creating vtables to +/// check for unsatisfiable methods. +pub fn normalize_and_test_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + predicates: Vec>) + -> bool +{ + debug!("normalize_and_test_predicates(predicates={:?})", + predicates); + + tcx.infer_ctxt(None, None, Reveal::All).enter(|infcx| { + let mut selcx = SelectionContext::new(&infcx); + let mut fulfill_cx = FulfillmentContext::new(); + let cause = ObligationCause::dummy(); + let Normalized { value: predicates, obligations } = + normalize(&mut selcx, cause.clone(), &predicates); + for obligation in obligations { + fulfill_cx.register_predicate_obligation(&infcx, obligation); + } + for predicate in predicates { + let obligation = Obligation::new(cause.clone(), predicate); + fulfill_cx.register_predicate_obligation(&infcx, obligation); + } + + fulfill_cx.select_all_or_error(&infcx).is_ok() + }) +} + +/// Given a trait `trait_ref`, iterates the vtable entries +/// that come from `trait_ref`, including its supertraits. +#[inline] // FIXME(#35870) Avoid closures being unexported due to impl Trait. +pub fn get_vtable_methods<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + trait_ref: ty::PolyTraitRef<'tcx>) + -> impl Iterator)>> + 'a +{ + debug!("get_vtable_methods({:?})", trait_ref); + + supertraits(tcx, trait_ref).flat_map(move |trait_ref| { + tcx.populate_implementations_for_trait_if_necessary(trait_ref.def_id()); + + let trait_item_def_ids = tcx.impl_or_trait_items(trait_ref.def_id()); + let trait_methods = (0..trait_item_def_ids.len()).filter_map(move |i| { + match tcx.impl_or_trait_item(trait_item_def_ids[i]) { + ty::MethodTraitItem(m) => Some(m), + _ => None + } + }); + + // Now list each method's DefId and Substs (for within its trait). + // If the method can never be called from this object, produce None. + trait_methods.map(move |trait_method| { + debug!("get_vtable_methods: trait_method={:?}", trait_method); + + // Some methods cannot be called on an object; skip those. + if !tcx.is_vtable_safe_method(trait_ref.def_id(), &trait_method) { + debug!("get_vtable_methods: not vtable safe"); + return None; + } + + // the method may have some early-bound lifetimes, add + // regions for those + let substs = Substs::for_item(tcx, trait_method.def_id, + |_, _| tcx.mk_region(ty::ReErased), + |def, _| trait_ref.substs().type_for_def(def)); + + // It's possible that the method relies on where clauses that + // do not hold for this particular set of type parameters. + // Note that this method could then never be called, so we + // do not want to try and trans it, in that case (see #23435). + let predicates = trait_method.predicates.instantiate_own(tcx, substs); + if !normalize_and_test_predicates(tcx, predicates.predicates) { + debug!("get_vtable_methods: predicates do not hold"); + return None; + } + + Some((trait_method.def_id, substs)) + }) + }) +} + impl<'tcx,O> Obligation<'tcx,O> { pub fn new(cause: ObligationCause<'tcx>, trait_ref: O) diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs index 2f63526bf6c2..e37425901c8c 100644 --- a/src/librustc/traits/specialize/mod.rs +++ b/src/librustc/traits/specialize/mod.rs @@ -26,9 +26,11 @@ use infer::{InferCtxt, TypeOrigin}; use middle::region; use ty::subst::{Subst, Substs}; use traits::{self, Reveal, ObligationCause, Normalized}; -use ty::{self, TyCtxt}; +use ty::{self, TyCtxt, TypeFoldable}; use syntax_pos::DUMMY_SP; +use syntax::ast; + pub mod specialization_graph; /// Information pertinent to an overlapping impl error. @@ -103,6 +105,41 @@ pub fn translate_substs<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, source_substs.rebase_onto(infcx.tcx, source_impl, target_substs) } +/// Given a selected impl described by `impl_data`, returns the +/// definition and substitions for the method with the name `name`, +/// and trait method substitutions `substs`, in that impl, a less +/// specialized impl, or the trait default, whichever applies. +pub fn find_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + name: ast::Name, + substs: &'tcx Substs<'tcx>, + impl_data: &super::VtableImplData<'tcx, ()>) + -> (DefId, &'tcx Substs<'tcx>) +{ + assert!(!substs.needs_infer()); + + let trait_def_id = tcx.trait_id_of_impl(impl_data.impl_def_id).unwrap(); + let trait_def = tcx.lookup_trait_def(trait_def_id); + + match trait_def.ancestors(impl_data.impl_def_id).fn_defs(tcx, name).next() { + Some(node_item) => { + let substs = tcx.infer_ctxt(None, None, Reveal::All).enter(|infcx| { + let substs = substs.rebase_onto(tcx, trait_def_id, impl_data.substs); + let substs = translate_substs(&infcx, impl_data.impl_def_id, + substs, node_item.node); + tcx.lift(&substs).unwrap_or_else(|| { + bug!("find_method: translate_substs \ + returned {:?} which contains inference types/regions", + substs); + }) + }); + (node_item.item.def_id, substs) + } + None => { + bug!("method {:?} not found in {:?}", name, impl_data.impl_def_id) + } + } +} + /// Is impl1 a specialization of impl2? /// /// Specialization is determined by the sets of types to which the impls apply; diff --git a/src/librustc_trans/back/symbol_names.rs b/src/librustc_trans/back/symbol_names.rs index 500e9edebf3f..0a668db06908 100644 --- a/src/librustc_trans/back/symbol_names.rs +++ b/src/librustc_trans/back/symbol_names.rs @@ -97,7 +97,7 @@ //! virtually impossible. Thus, symbol hash generation exclusively relies on //! DefPaths which are much more robust in the face of changes to the code base. -use common::{CrateContext, SharedCrateContext, gensym_name}; +use common::SharedCrateContext; use monomorphize::Instance; use util::sha2::{Digest, Sha256}; @@ -152,16 +152,17 @@ fn get_symbol_hash<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, let mut hash_state = scx.symbol_hasher().borrow_mut(); record_time(&tcx.sess.perf_stats.symbol_hash_time, || { hash_state.reset(); + let mut hasher = Sha256Hasher(&mut hash_state); - let mut hasher = ty::util::TypeIdHasher::new(tcx, Sha256Hasher(&mut hash_state)); // the main symbol name is not necessarily unique; hash in the // compiler's internal def-path, guaranteeing each symbol has a // truly unique path - hasher.hash(def_path.to_string(tcx)); + def_path.deterministic_hash_to(tcx, &mut hasher); // Include the main item-type. Note that, in this case, the // assertions about `needs_subst` may not hold, but this item-type // ought to be the same for every reference anyway. + let mut hasher = ty::util::TypeIdHasher::new(tcx, hasher); assert!(!item_type.has_erasable_regions()); hasher.visit_ty(item_type); @@ -172,18 +173,15 @@ fn get_symbol_hash<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, substs.visit_with(&mut hasher); } }); - fn truncated_hash_result(symbol_hasher: &mut Sha256) -> String { - let output = symbol_hasher.result_bytes(); - // 64 bits should be enough to avoid collisions. - output[.. 8].to_hex() - } - format!("h{}", truncated_hash_result(&mut hash_state)) + // 64 bits should be enough to avoid collisions. + let output = hash_state.result_bytes(); + format!("h{}", output[..8].to_hex()) } impl<'a, 'tcx> Instance<'tcx> { pub fn symbol_name(self, scx: &SharedCrateContext<'a, 'tcx>) -> String { - let Instance { def: def_id, ref substs } = self; + let Instance { def: def_id, substs } = self; debug!("symbol_name(def_id={:?}, substs={:?})", def_id, substs); @@ -278,7 +276,7 @@ impl<'a, 'tcx> Instance<'tcx> { scx.tcx().push_item_path(&mut buffer, def_id); }); - mangle(buffer.names.into_iter(), Some(&hash[..])) + mangle(buffer.names.into_iter(), &hash) } } @@ -307,23 +305,7 @@ pub fn exported_name_from_type_and_prefix<'a, 'tcx>(scx: &SharedCrateContext<'a, }; let hash = get_symbol_hash(scx, &empty_def_path, t, None); let path = [token::intern_and_get_ident(prefix)]; - mangle(path.iter().cloned(), Some(&hash[..])) -} - -/// Only symbols that are invisible outside their compilation unit should use a -/// name generated by this function. -pub fn internal_name_from_type_and_suffix<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - t: Ty<'tcx>, - suffix: &str) - -> String { - let path = [token::intern(&t.to_string()).as_str(), - gensym_name(suffix).as_str()]; - let def_path = DefPath { - data: vec![], - krate: LOCAL_CRATE, - }; - let hash = get_symbol_hash(ccx.shared(), &def_path, t, None); - mangle(path.iter().cloned(), Some(&hash[..])) + mangle(path.iter().cloned(), &hash) } // Name sanitation. LLVM will happily accept identifiers with weird names, but @@ -376,7 +358,7 @@ pub fn sanitize(s: &str) -> String { return result; } -pub fn mangle>(path: PI, hash: Option<&str>) -> String { +fn mangle>(path: PI, hash: &str) -> String { // Follow C++ namespace-mangling style, see // http://en.wikipedia.org/wiki/Name_mangling for more info. // @@ -403,9 +385,7 @@ pub fn mangle>(path: PI, hash: Option<&str>) - push(&mut n, &data); } - if let Some(s) = hash { - push(&mut n, s) - } + push(&mut n, hash); n.push('E'); // End name-sequence. n diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs index 9785ee245579..8822287a0e75 100644 --- a/src/librustc_trans/callee.rs +++ b/src/librustc_trans/callee.rs @@ -17,7 +17,6 @@ pub use self::CalleeData::*; use arena::TypedArena; -use back::symbol_names; use llvm::{self, ValueRef, get_params}; use rustc::hir::def_id::DefId; use rustc::ty::subst::Substs; @@ -133,26 +132,25 @@ impl<'tcx> Callee<'tcx> { let trait_ref = tcx.normalize_associated_type(&ty::Binder(trait_ref)); match common::fulfill_obligation(ccx.shared(), DUMMY_SP, trait_ref) { traits::VtableImpl(vtable_impl) => { - let impl_did = vtable_impl.impl_def_id; - let mname = tcx.item_name(def_id); - // create a concatenated set of substitutions which includes - // those from the impl and those from the method: - let mth = meth::get_impl_method(tcx, substs, impl_did, vtable_impl.substs, mname); + let name = tcx.item_name(def_id); + let (def_id, substs) = traits::find_method(tcx, name, substs, &vtable_impl); // Translate the function, bypassing Callee::def. // That is because default methods have the same ID as the // trait method used to look up the impl method that ended // up here, so calling Callee::def would infinitely recurse. - let (llfn, ty) = get_fn(ccx, mth.method.def_id, mth.substs); + let (llfn, ty) = get_fn(ccx, def_id, substs); Callee::ptr(llfn, ty) } traits::VtableClosure(vtable_closure) => { // The substitutions should have no type parameters remaining // after passing through fulfill_obligation let trait_closure_kind = tcx.lang_items.fn_trait_kind(trait_id).unwrap(); + let instance = Instance::new(def_id, substs); let llfn = closure::trans_closure_method(ccx, vtable_closure.closure_def_id, vtable_closure.substs, + instance, trait_closure_kind); let method_ty = def_ty(ccx.shared(), def_id, substs); @@ -160,7 +158,10 @@ impl<'tcx> Callee<'tcx> { } traits::VtableFnPointer(vtable_fn_pointer) => { let trait_closure_kind = tcx.lang_items.fn_trait_kind(trait_id).unwrap(); - let llfn = trans_fn_pointer_shim(ccx, trait_closure_kind, vtable_fn_pointer.fn_ty); + let instance = Instance::new(def_id, substs); + let llfn = trans_fn_pointer_shim(ccx, instance, + trait_closure_kind, + vtable_fn_pointer.fn_ty); let method_ty = def_ty(ccx.shared(), def_id, substs); Callee::ptr(llfn, method_ty) @@ -217,9 +218,7 @@ impl<'tcx> Callee<'tcx> { pub fn reify<'a>(self, ccx: &CrateContext<'a, 'tcx>) -> ValueRef { match self.data { Fn(llfn) => llfn, - Virtual(idx) => { - meth::trans_object_shim(ccx, self.ty, idx) - } + Virtual(_) => meth::trans_object_shim(ccx, self), NamedTupleConstructor(disr) => match self.ty.sty { ty::TyFnDef(def_id, substs, _) => { let instance = Instance::new(def_id, substs); @@ -264,8 +263,9 @@ fn def_ty<'a, 'tcx>(shared: &SharedCrateContext<'a, 'tcx>, /// ``` /// /// but for the bare function type given. -pub fn trans_fn_pointer_shim<'a, 'tcx>( +fn trans_fn_pointer_shim<'a, 'tcx>( ccx: &'a CrateContext<'a, 'tcx>, + method_instance: Instance<'tcx>, closure_kind: ty::ClosureKind, bare_fn_ty: Ty<'tcx>) -> ValueRef @@ -345,10 +345,7 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>( debug!("tuple_fn_ty: {:?}", tuple_fn_ty); // - let function_name = - symbol_names::internal_name_from_type_and_suffix(ccx, - bare_fn_ty, - "fn_pointer_shim"); + let function_name = method_instance.symbol_name(ccx.shared()); let llfn = declare::define_internal_fn(ccx, &function_name, tuple_fn_ty); attributes::set_frame_pointer_elimination(ccx, llfn); // diff --git a/src/librustc_trans/closure.rs b/src/librustc_trans/closure.rs index 83882c27e8e7..c0692e8085fc 100644 --- a/src/librustc_trans/closure.rs +++ b/src/librustc_trans/closure.rs @@ -9,7 +9,6 @@ // except according to those terms. use arena::TypedArena; -use back::symbol_names; use llvm::{self, ValueRef, get_params}; use rustc::hir::def_id::DefId; use abi::{Abi, FnType}; @@ -152,6 +151,7 @@ pub fn trans_closure_body_via_mir<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, pub fn trans_closure_method<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>, closure_def_id: DefId, substs: ty::ClosureSubsts<'tcx>, + method_instance: Instance<'tcx>, trait_closure_kind: ty::ClosureKind) -> ValueRef { @@ -199,7 +199,7 @@ pub fn trans_closure_method<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>, // fn call_once(mut self, ...) { call_mut(&mut self, ...) } // // These are both the same at trans time. - trans_fn_once_adapter_shim(ccx, closure_def_id, substs, llfn) + trans_fn_once_adapter_shim(ccx, closure_def_id, substs, method_instance, llfn) } _ => { bug!("trans_closure_adapter_shim: cannot convert {:?} to {:?}", @@ -213,6 +213,7 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>( ccx: &'a CrateContext<'a, 'tcx>, closure_def_id: DefId, substs: ty::ClosureSubsts<'tcx>, + method_instance: Instance<'tcx>, llreffn: ValueRef) -> ValueRef { @@ -255,8 +256,7 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>( })); // Create the by-value helper. - let function_name = - symbol_names::internal_name_from_type_and_suffix(ccx, llonce_fn_ty, "once_shim"); + let function_name = method_instance.symbol_name(ccx.shared()); let lloncefn = declare::declare_fn(ccx, &function_name, llonce_fn_ty); attributes::set_frame_pointer_elimination(ccx, lloncefn); diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index b9449eeecf42..2849b384e1bd 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -210,9 +210,8 @@ use errors; use syntax_pos::DUMMY_SP; use base::custom_coerce_unsize_info; use context::SharedCrateContext; -use common::{fulfill_obligation, normalize_and_test_predicates, type_is_sized}; +use common::{fulfill_obligation, type_is_sized}; use glue::{self, DropGlueKind}; -use meth; use monomorphize::{self, Instance}; use util::nodemap::{FnvHashSet, FnvHashMap, DefIdMap}; @@ -899,17 +898,8 @@ fn do_static_trait_method_dispatch<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, // Now that we know which impl is being used, we can dispatch to // the actual function: match vtbl { - traits::VtableImpl(traits::VtableImplData { - impl_def_id: impl_did, - substs: impl_substs, - nested: _ }) => - { - let impl_method = meth::get_impl_method(tcx, - rcvr_substs, - impl_did, - impl_substs, - trait_method.name); - Some((impl_method.method.def_id, &impl_method.substs)) + traits::VtableImpl(impl_data) => { + Some(traits::find_method(tcx, trait_method.name, rcvr_substs, &impl_data)) } // If we have a closure or a function pointer, we will also encounter // the concrete closure/function somewhere else (during closure or fn @@ -1043,43 +1033,19 @@ fn create_trans_items_for_vtable_methods<'a, 'tcx>(scx: &SharedCrateContext<'a, if let ty::TyTrait(ref trait_ty) = trait_ty.sty { let poly_trait_ref = trait_ty.principal.with_self_ty(scx.tcx(), impl_ty); + let param_substs = Substs::empty(scx.tcx()); // Walk all methods of the trait, including those of its supertraits - for trait_ref in traits::supertraits(scx.tcx(), poly_trait_ref) { - let vtable = fulfill_obligation(scx, DUMMY_SP, trait_ref); - match vtable { - traits::VtableImpl( - traits::VtableImplData { - impl_def_id, - substs, - nested: _ }) => { - let items = meth::get_vtable_methods(scx.tcx(), impl_def_id, substs) - .into_iter() - // filter out None values - .filter_map(|opt_impl_method| opt_impl_method) - // create translation items - .filter_map(|impl_method| { - if can_have_local_instance(scx.tcx(), impl_method.method.def_id) { - Some(create_fn_trans_item(scx, - impl_method.method.def_id, - impl_method.substs, - Substs::empty(scx.tcx()))) - } else { - None - } - }); - - output.extend(items); - } - _ => { /* */ } - } - } + let methods = traits::get_vtable_methods(scx.tcx(), poly_trait_ref); + let methods = methods.filter_map(|method| method) + .filter_map(|(def_id, substs)| do_static_dispatch(scx, def_id, substs, param_substs)) + .filter(|&(def_id, _)| can_have_local_instance(scx.tcx(), def_id)) + .map(|(def_id, substs)| create_fn_trans_item(scx, def_id, substs, param_substs)); + output.extend(methods); // Also add the destructor let dg_type = glue::get_drop_glue_type(scx.tcx(), impl_ty); - if glue::type_needs_drop(scx.tcx(), dg_type) { - output.push(TransItem::DropGlue(DropGlueKind::Ty(dg_type))); - } + output.push(TransItem::DropGlue(DropGlueKind::Ty(dg_type))); } } @@ -1239,25 +1205,27 @@ fn create_trans_items_for_default_impls<'a, 'tcx>(scx: &SharedCrateContext<'a, ' let impl_substs = Substs::for_item(tcx, impl_def_id, |_, _| tcx.mk_region(ty::ReErased), |_, _| tcx.types.err); - let mth = meth::get_impl_method(tcx, - callee_substs, - impl_def_id, - impl_substs, - method.name); + let impl_data = traits::VtableImplData { + impl_def_id: impl_def_id, + substs: impl_substs, + nested: vec![] + }; + let (def_id, substs) = traits::find_method(tcx, + method.name, + callee_substs, + &impl_data); - assert!(mth.is_provided); - - let predicates = mth.method.predicates.predicates.subst(tcx, &mth.substs); - if !normalize_and_test_predicates(tcx, predicates) { + let predicates = tcx.lookup_predicates(def_id).predicates + .subst(tcx, substs); + if !traits::normalize_and_test_predicates(tcx, predicates) { continue; } if can_have_local_instance(tcx, method.def_id) { - let empty_substs = tcx.erase_regions(&mth.substs); let item = create_fn_trans_item(scx, method.def_id, callee_substs, - empty_substs); + tcx.erase_regions(&substs)); output.push(item); } } diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index e0de04d150ca..db1a54191903 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -150,15 +150,6 @@ pub fn type_is_zero_size<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) - llsize_of_alloc(ccx, llty) == 0 } -/// Generates a unique symbol based off the name given. This is used to create -/// unique symbols for things like closures. -pub fn gensym_name(name: &str) -> ast::Name { - let num = token::gensym(name).0; - // use one colon which will get translated to a period by the mangler, and - // we're guaranteed that `num` is globally unique for this crate. - token::gensym(&format!("{}:{}", name, num)) -} - /* * A note on nomenclature of linking: "extern", "foreign", and "upcall". * @@ -1002,35 +993,6 @@ pub fn fulfill_obligation<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, }) } -/// Normalizes the predicates and checks whether they hold. If this -/// returns false, then either normalize encountered an error or one -/// of the predicates did not hold. Used when creating vtables to -/// check for unsatisfiable methods. -pub fn normalize_and_test_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - predicates: Vec>) - -> bool -{ - debug!("normalize_and_test_predicates(predicates={:?})", - predicates); - - tcx.infer_ctxt(None, None, Reveal::All).enter(|infcx| { - let mut selcx = SelectionContext::new(&infcx); - let mut fulfill_cx = traits::FulfillmentContext::new(); - let cause = traits::ObligationCause::dummy(); - let traits::Normalized { value: predicates, obligations } = - traits::normalize(&mut selcx, cause.clone(), &predicates); - for obligation in obligations { - fulfill_cx.register_predicate_obligation(&infcx, obligation); - } - for predicate in predicates { - let obligation = traits::Obligation::new(cause.clone(), predicate); - fulfill_cx.register_predicate_obligation(&infcx, obligation); - } - - fulfill_cx.select_all_or_error(&infcx).is_ok() - }) -} - pub fn langcall(tcx: TyCtxt, span: Option, msg: &str, diff --git a/src/librustc_trans/meth.rs b/src/librustc_trans/meth.rs index 8540c7a99db1..e8dcaf71f2dd 100644 --- a/src/librustc_trans/meth.rs +++ b/src/librustc_trans/meth.rs @@ -8,33 +8,25 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::rc::Rc; - use attributes; use arena::TypedArena; -use back::symbol_names; use llvm::{ValueRef, get_params}; -use rustc::hir::def_id::DefId; -use rustc::ty::subst::{Subst, Substs}; -use rustc::traits::{self, Reveal}; +use rustc::traits; use abi::FnType; use base::*; use build::*; -use callee::{Callee, Virtual, trans_fn_pointer_shim}; -use closure; +use callee::Callee; use common::*; use consts; use debuginfo::DebugLoc; use declare; use glue; use machine; +use monomorphize::Instance; use type_::Type; use type_of::*; use value::Value; -use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; - -use syntax::ast::Name; -use syntax_pos::DUMMY_SP; +use rustc::ty; // drop_glue pointer, size, align. const VTABLE_OFFSET: usize = 3; @@ -73,23 +65,26 @@ pub fn get_virtual_method<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, /// In fact, all virtual calls can be thought of as normal trait calls /// that go through this shim function. pub fn trans_object_shim<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>, - method_ty: Ty<'tcx>, - vtable_index: usize) + callee: Callee<'tcx>) -> ValueRef { let _icx = push_ctxt("trans_object_shim"); let tcx = ccx.tcx(); - debug!("trans_object_shim(vtable_index={}, method_ty={:?})", - vtable_index, - method_ty); + debug!("trans_object_shim({:?})", callee); - let sig = tcx.erase_late_bound_regions(&method_ty.fn_sig()); + let (sig, abi, function_name) = match callee.ty.sty { + ty::TyFnDef(def_id, substs, f) => { + let instance = Instance::new(def_id, substs); + (&f.sig, f.abi, instance.symbol_name(ccx.shared())) + } + _ => bug!() + }; + + let sig = tcx.erase_late_bound_regions(sig); let sig = tcx.normalize_associated_type(&sig); - let fn_ty = FnType::new(ccx, method_ty.fn_abi(), &sig, &[]); + let fn_ty = FnType::new(ccx, abi, &sig, &[]); - let function_name = - symbol_names::internal_name_from_type_and_suffix(ccx, method_ty, "object_shim"); - let llfn = declare::define_internal_fn(ccx, &function_name, method_ty); + let llfn = declare::define_internal_fn(ccx, &function_name, callee.ty); attributes::set_frame_pointer_elimination(ccx, llfn); let (block_arena, fcx): (TypedArena<_>, FunctionContext); @@ -98,16 +93,7 @@ pub fn trans_object_shim<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>, let mut bcx = fcx.init(false); let dest = fcx.llretslotptr.get(); - - debug!("trans_object_shim: method_offset_in_vtable={}", - vtable_index); - let llargs = get_params(fcx.llfn); - - let callee = Callee { - data: Virtual(vtable_index), - ty: method_ty - }; bcx = callee.call(bcx, DebugLoc::None, &llargs[fcx.fn_ty.ret.is_indirect() as usize..], dest).bcx; @@ -140,72 +126,23 @@ pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, } // Not in the cache. Build it. - let methods = traits::supertraits(tcx, trait_ref.clone()).flat_map(|trait_ref| { - let vtable = fulfill_obligation(ccx.shared(), DUMMY_SP, trait_ref.clone()); - match vtable { - // Should default trait error here? - traits::VtableDefaultImpl(_) | - traits::VtableBuiltin(_) => { - Vec::new().into_iter() - } - traits::VtableImpl( - traits::VtableImplData { - impl_def_id: id, - substs, - nested: _ }) => { - let nullptr = C_null(Type::nil(ccx).ptr_to()); - get_vtable_methods(tcx, id, substs) - .into_iter() - .map(|opt_mth| opt_mth.map_or(nullptr, |mth| { - Callee::def(ccx, mth.method.def_id, &mth.substs).reify(ccx) - })) - .collect::>() - .into_iter() - } - traits::VtableClosure( - traits::VtableClosureData { - closure_def_id, - substs, - nested: _ }) => { - let trait_closure_kind = tcx.lang_items.fn_trait_kind(trait_ref.def_id()).unwrap(); - let llfn = closure::trans_closure_method(ccx, - closure_def_id, - substs, - trait_closure_kind); - vec![llfn].into_iter() - } - traits::VtableFnPointer( - traits::VtableFnPointerData { - fn_ty: bare_fn_ty, - nested: _ }) => { - let trait_closure_kind = tcx.lang_items.fn_trait_kind(trait_ref.def_id()).unwrap(); - vec![trans_fn_pointer_shim(ccx, trait_closure_kind, bare_fn_ty)].into_iter() - } - traits::VtableObject(ref data) => { - // this would imply that the Self type being erased is - // an object type; this cannot happen because we - // cannot cast an unsized type into a trait object - bug!("cannot get vtable for an object type: {:?}", - data); - } - traits::VtableParam(..) => { - bug!("resolved vtable for {:?} to bad vtable {:?} in trans", - trait_ref, - vtable); - } - } + let nullptr = C_null(Type::nil(ccx).ptr_to()); + let methods = traits::get_vtable_methods(tcx, trait_ref).map(|opt_mth| { + opt_mth.map_or(nullptr, |(def_id, substs)| { + Callee::def(ccx, def_id, substs).reify(ccx) + }) }); let size_ty = sizing_type_of(ccx, trait_ref.self_ty()); let size = machine::llsize_of_alloc(ccx, size_ty); let align = align_of(ccx, trait_ref.self_ty()); - let components: Vec<_> = vec![ + let components: Vec<_> = [ // Generate a destructor for the vtable. glue::get_drop_glue(ccx, trait_ref.self_ty()), C_uint(ccx, size), C_uint(ccx, align) - ].into_iter().chain(methods).collect(); + ].iter().cloned().chain(methods).collect(); let vtable_const = C_struct(ccx, &components, false); let align = machine::llalign_of_pref(ccx, val_ty(vtable_const)); @@ -214,122 +151,3 @@ pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ccx.vtables().borrow_mut().insert(trait_ref, vtable); vtable } - -pub fn get_vtable_methods<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - impl_id: DefId, - substs: &'tcx Substs<'tcx>) - -> Vec>> -{ - debug!("get_vtable_methods(impl_id={:?}, substs={:?}", impl_id, substs); - - let trait_id = match tcx.impl_trait_ref(impl_id) { - Some(t_id) => t_id.def_id, - None => bug!("make_impl_vtable: don't know how to \ - make a vtable for a type impl!") - }; - - tcx.populate_implementations_for_trait_if_necessary(trait_id); - - let trait_item_def_ids = tcx.impl_or_trait_items(trait_id); - trait_item_def_ids - .iter() - - // Filter out non-method items. - .filter_map(|&item_def_id| { - match tcx.impl_or_trait_item(item_def_id) { - ty::MethodTraitItem(m) => Some(m), - _ => None - } - }) - - // Now produce pointers for each remaining method. If the - // method could never be called from this object, just supply - // null. - .map(|trait_method_type| { - debug!("get_vtable_methods: trait_method_def_id={:?}", - trait_method_type.def_id); - - let name = trait_method_type.name; - - // Some methods cannot be called on an object; skip those. - if !tcx.is_vtable_safe_method(trait_id, &trait_method_type) { - debug!("get_vtable_methods: not vtable safe"); - return None; - } - - debug!("get_vtable_methods: trait_method_type={:?}", - trait_method_type); - - // the method may have some early-bound lifetimes, add - // regions for those - let method_substs = Substs::for_item(tcx, trait_method_type.def_id, - |_, _| tcx.mk_region(ty::ReErased), - |_, _| tcx.types.err); - - // The substitutions we have are on the impl, so we grab - // the method type from the impl to substitute into. - let mth = get_impl_method(tcx, method_substs, impl_id, substs, name); - - debug!("get_vtable_methods: mth={:?}", mth); - - // If this is a default method, it's possible that it - // relies on where clauses that do not hold for this - // particular set of type parameters. Note that this - // method could then never be called, so we do not want to - // try and trans it, in that case. Issue #23435. - if mth.is_provided { - let predicates = mth.method.predicates.predicates.subst(tcx, &mth.substs); - if !normalize_and_test_predicates(tcx, predicates) { - debug!("get_vtable_methods: predicates do not hold"); - return None; - } - } - - Some(mth) - }) - .collect() -} - -#[derive(Debug)] -pub struct ImplMethod<'tcx> { - pub method: Rc>, - pub substs: &'tcx Substs<'tcx>, - pub is_provided: bool -} - -/// Locates the applicable definition of a method, given its name. -pub fn get_impl_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - substs: &'tcx Substs<'tcx>, - impl_def_id: DefId, - impl_substs: &'tcx Substs<'tcx>, - name: Name) - -> ImplMethod<'tcx> -{ - assert!(!substs.needs_infer()); - - let trait_def_id = tcx.trait_id_of_impl(impl_def_id).unwrap(); - let trait_def = tcx.lookup_trait_def(trait_def_id); - - match trait_def.ancestors(impl_def_id).fn_defs(tcx, name).next() { - Some(node_item) => { - let substs = tcx.infer_ctxt(None, None, Reveal::All).enter(|infcx| { - let substs = substs.rebase_onto(tcx, trait_def_id, impl_substs); - let substs = traits::translate_substs(&infcx, impl_def_id, - substs, node_item.node); - tcx.lift(&substs).unwrap_or_else(|| { - bug!("trans::meth::get_impl_method: translate_substs \ - returned {:?} which contains inference types/regions", - substs); - }) - }); - ImplMethod { - method: node_item.item, - substs: substs, - is_provided: node_item.node.is_from_trait(), - } - } - None => { - bug!("method {:?} not found in {:?}", name, impl_def_id) - } - } -} From a2726f4a548f77f0443701c457f9f7628b5c6b6c Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Mon, 19 Sep 2016 12:37:12 +0300 Subject: [PATCH 438/443] rustc: allow less and handle fn pointers in the type hashing algorithm. --- src/librustc/ty/util.rs | 15 +++++++++------ src/librustc_trans/glue.rs | 2 ++ src/test/run-pass/typeid-intrinsic.rs | 4 ++++ 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 5c71f348b992..d834a7d485a3 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -436,17 +436,18 @@ impl<'a, 'gcx, 'tcx, H: Hasher> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tc TyInt(i) => self.hash(i), TyUint(u) => self.hash(u), TyFloat(f) => self.hash(f), - TyAdt(d, _) => self.def_id(d.did), TyArray(_, n) => self.hash(n), TyRawPtr(m) | TyRef(_, m) => self.hash(m.mutbl), TyClosure(def_id, _) | TyAnon(def_id, _) | TyFnDef(def_id, ..) => self.def_id(def_id), + TyAdt(d, _) => self.def_id(d.did), TyFnPtr(f) => { self.hash(f.unsafety); self.hash(f.abi); self.hash(f.sig.variadic()); + self.hash(f.sig.inputs().skip_binder().len()); } TyTrait(ref data) => { self.def_id(data.principal.def_id()); @@ -468,9 +469,10 @@ impl<'a, 'gcx, 'tcx, H: Hasher> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tc TyChar | TyStr | TyBox(_) | - TySlice(_) | - TyError => {} - TyInfer(_) => bug!() + TySlice(_) => {} + + TyError | + TyInfer(_) => bug!("TypeIdHasher: unexpected type {}", ty) } ty.super_visit_with(self) @@ -478,7 +480,7 @@ impl<'a, 'gcx, 'tcx, H: Hasher> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tc fn visit_region(&mut self, r: &'tcx ty::Region) -> bool { match *r { - ty::ReStatic | ty::ReErased => { + ty::ReErased => { self.hash::(0); } ty::ReLateBound(db, ty::BrAnon(i)) => { @@ -486,6 +488,7 @@ impl<'a, 'gcx, 'tcx, H: Hasher> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tc self.hash::(db.depth); self.hash(i); } + ty::ReStatic | ty::ReEmpty | ty::ReEarlyBound(..) | ty::ReLateBound(..) | @@ -493,7 +496,7 @@ impl<'a, 'gcx, 'tcx, H: Hasher> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tc ty::ReScope(..) | ty::ReVar(..) | ty::ReSkolemized(..) => { - bug!("unexpected region found when hashing a type") + bug!("TypeIdHasher: unexpected region {:?}", r) } } false diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs index 3073b1dbfaee..7b0122798722 100644 --- a/src/librustc_trans/glue.rs +++ b/src/librustc_trans/glue.rs @@ -92,6 +92,8 @@ pub fn get_drop_glue_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, t: Ty<'tcx>) -> Ty<'tcx> { assert!(t.is_normalized_for_trans()); + let t = tcx.erase_regions(&t); + // Even if there is no dtor for t, there might be one deeper down and we // might need to pass in the vtable ptr. if !type_is_sized(tcx, t) { diff --git a/src/test/run-pass/typeid-intrinsic.rs b/src/test/run-pass/typeid-intrinsic.rs index 36650368d57b..54d5415a5539 100644 --- a/src/test/run-pass/typeid-intrinsic.rs +++ b/src/test/run-pass/typeid-intrinsic.rs @@ -87,4 +87,8 @@ pub fn main() { assert_eq!(other1::id_u32_iterator(), other2::id_u32_iterator()); assert!(other1::id_i32_iterator() != other1::id_u32_iterator()); assert!(TypeId::of::() != TypeId::of::()); + + // Check fn pointer against collisions + assert!(TypeId::of:: A) -> A>() != + TypeId::of:: A, A) -> A>()); } From 4ac30013c3402d9349f83888a9d0903f0a68746e Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Mon, 19 Sep 2016 04:26:38 +0300 Subject: [PATCH 439/443] rustc_trans: don't do on-demand drop glue instantiation. --- src/librustc_trans/glue.rs | 20 ++----------------- .../instantiation-through-vtable.rs | 1 + .../codegen-units/item-collection/unsizing.rs | 1 + .../partitioning/vtable-through-const.rs | 1 + 4 files changed, 5 insertions(+), 18 deletions(-) diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs index 7b0122798722..2a20728f09be 100644 --- a/src/librustc_trans/glue.rs +++ b/src/librustc_trans/glue.rs @@ -216,30 +216,14 @@ fn get_drop_glue_core<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, g: DropGlueKind<'tcx>) -> ValueRef { let g = g.map_ty(|t| get_drop_glue_type(ccx.tcx(), t)); match ccx.drop_glues().borrow().get(&g) { - Some(&(glue, _)) => return glue, + Some(&(glue, _)) => glue, None => { - debug!("Could not find drop glue for {:?} -- {} -- {}. \ - Falling back to on-demand instantiation.", + bug!("Could not find drop glue for {:?} -- {} -- {}.", g, TransItem::DropGlue(g).to_raw_string(), ccx.codegen_unit().name()); } } - - // FIXME: #34151 - // Normally, getting here would indicate a bug in trans::collector, - // since it seems to have missed a translation item. When we are - // translating with non-MIR-based trans, however, the results of the - // collector are not entirely reliable since it bases its analysis - // on MIR. Thus, we'll instantiate the missing function on demand in - // this codegen unit, so that things keep working. - - TransItem::DropGlue(g).predefine(ccx, llvm::InternalLinkage); - TransItem::DropGlue(g).define(ccx); - - // Now that we made sure that the glue function is in ccx.drop_glues, - // give it another try - get_drop_glue_core(ccx, g) } pub fn implement_drop_glue<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, diff --git a/src/test/codegen-units/item-collection/instantiation-through-vtable.rs b/src/test/codegen-units/item-collection/instantiation-through-vtable.rs index b77252512200..ad466671cf79 100644 --- a/src/test/codegen-units/item-collection/instantiation-through-vtable.rs +++ b/src/test/codegen-units/item-collection/instantiation-through-vtable.rs @@ -31,6 +31,7 @@ impl Trait for Struct { fn main() { let s1 = Struct { _a: 0u32 }; + //~ TRANS_ITEM drop-glue i8 //~ TRANS_ITEM fn instantiation_through_vtable::{{impl}}[0]::foo[0] //~ TRANS_ITEM fn instantiation_through_vtable::{{impl}}[0]::bar[0] let _ = &s1 as &Trait; diff --git a/src/test/codegen-units/item-collection/unsizing.rs b/src/test/codegen-units/item-collection/unsizing.rs index 45ba441bc8ba..cd4cc258f7a6 100644 --- a/src/test/codegen-units/item-collection/unsizing.rs +++ b/src/test/codegen-units/item-collection/unsizing.rs @@ -57,6 +57,7 @@ fn main() { // simple case let bool_sized = &true; + //~ TRANS_ITEM drop-glue i8 //~ TRANS_ITEM fn unsizing::{{impl}}[0]::foo[0] let _bool_unsized = bool_sized as &Trait; diff --git a/src/test/codegen-units/partitioning/vtable-through-const.rs b/src/test/codegen-units/partitioning/vtable-through-const.rs index ee5e97cd9c21..0007eaae2897 100644 --- a/src/test/codegen-units/partitioning/vtable-through-const.rs +++ b/src/test/codegen-units/partitioning/vtable-through-const.rs @@ -69,6 +69,7 @@ mod mod1 { //~ TRANS_ITEM fn vtable_through_const::main[0] @@ vtable_through_const[External] fn main() { + //~ TRANS_ITEM drop-glue i8 @@ vtable_through_const[Internal] // Since Trait1::do_something() is instantiated via its default implementation, // it is considered a generic and is instantiated here only because it is From e4b18422ad3ee6bf1e749ccd337a25736a78c0bb Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Tue, 20 Sep 2016 15:39:05 -0700 Subject: [PATCH 440/443] Check for overlapping and simplify unit test --- src/libsyntax/codemap.rs | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index ce15bd89590b..6d68ce3646d5 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -392,8 +392,8 @@ impl CodeMap { return None; } - // ensure these follow the expected order - if sp_lhs.lo <= sp_rhs.lo { + // ensure these follow the expected order and we don't overlap + if (sp_lhs.lo <= sp_rhs.lo) && (sp_lhs.hi <= sp_rhs.lo) { Some(Span { lo: cmp::min(sp_lhs.lo, sp_rhs.lo), hi: cmp::max(sp_lhs.hi, sp_rhs.hi), @@ -1146,12 +1146,7 @@ mod tests { let span1 = span_from_selection(inputtext, selection1); let span2 = span_from_selection(inputtext, selection2); - if let Some(_) = cm.merge_spans(span1, span2) { - assert!(false); - } - else { - assert!(true); - } + assert!(cm.merge_spans(span1, span2).is_none()); } /// Returns the span corresponding to the `n`th occurrence of From 4db157af71dc32d38941b082d016c41adebc7a1d Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Wed, 21 Sep 2016 09:20:42 +0000 Subject: [PATCH 441/443] Allow attribute macro invocations at the crate root. --- src/libsyntax/ext/expand.rs | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 4e87d8ee9dda..e704934dba9c 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -184,13 +184,20 @@ impl<'a, 'b> MacroExpander<'a, 'b> { fn expand_crate(&mut self, mut krate: ast::Crate) -> ast::Crate { let err_count = self.cx.parse_sess.span_diagnostic.err_count(); - let mut krate_item = placeholder(ExpansionKind::Items, ast::DUMMY_NODE_ID) - .make_items().pop().unwrap().unwrap(); - krate_item.node = ast::ItemKind::Mod(krate.module); - let krate_item = Expansion::Items(SmallVector::one(P(krate_item))); + let krate_item = Expansion::Items(SmallVector::one(P(ast::Item { + attrs: krate.attrs, + span: krate.span, + node: ast::ItemKind::Mod(krate.module), + ident: keywords::Invalid.ident(), + id: ast::DUMMY_NODE_ID, + vis: ast::Visibility::Public, + }))); - krate.module = match self.expand(krate_item).make_items().pop().unwrap().unwrap().node { - ast::ItemKind::Mod(module) => module, + match self.expand(krate_item).make_items().pop().unwrap().unwrap() { + ast::Item { attrs, node: ast::ItemKind::Mod(module), .. } => { + krate.attrs = attrs; + krate.module = module; + }, _ => unreachable!(), }; krate.exported_macros = mem::replace(&mut self.cx.exported_macros, Vec::new()); From 3d8d55787b2c0f5b1aba01b08da13bf0d612818c Mon Sep 17 00:00:00 2001 From: Ashley Williams Date: Wed, 27 Jul 2016 10:47:19 -0700 Subject: [PATCH 442/443] add assert_ne and debug_assert_ne macros --- src/libcore/macros.rs | 63 ++++++++++++++++++++ src/libstd/lib.rs | 4 +- src/test/run-pass/assert-ne-macro-success.rs | 22 +++++++ src/test/run-pass/assert-ne-macro-unsized.rs | 13 ++++ 4 files changed, 100 insertions(+), 2 deletions(-) create mode 100644 src/test/run-pass/assert-ne-macro-success.rs create mode 100644 src/test/run-pass/assert-ne-macro-unsized.rs diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index f29a49dd5fe1..99c24e4c48d4 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -119,6 +119,44 @@ macro_rules! assert_eq { }); } +/// Asserts that two expressions are not equal to each other. +/// +/// On panic, this macro will print the values of the expressions with their +/// debug representations. +/// +/// # Examples +/// +/// ``` +/// let a = 3; +/// let b = 2; +/// assert_ne!(a, b); +/// ``` +#[macro_export] +#[stable(feature = "assert_ne", since = "1.12.0")] +macro_rules! assert_ne { + ($left:expr , $right:expr) => ({ + match (&$left, &$right) { + (left_val, right_val) => { + if *left_val == *right_val { + panic!("assertion failed: `(left != right)` \ + (left: `{:?}`, right: `{:?}`)", left_val, right_val) + } + } + } + }); + ($left:expr , $right:expr, $($arg:tt)*) => ({ + match (&($left), &($right)) { + (left_val, right_val) => { + if *left_val == *right_val { + panic!("assertion failed: `(left != right)` \ + (left: `{:?}`, right: `{:?}`): {}", left_val, right_val, + format_args!($($arg)*)) + } + } + } + }); +} + /// Ensure that a boolean expression is `true` at runtime. /// /// This will invoke the `panic!` macro if the provided expression cannot be @@ -189,6 +227,31 @@ macro_rules! debug_assert_eq { ($($arg:tt)*) => (if cfg!(debug_assertions) { assert_eq!($($arg)*); }) } +/// Asserts that two expressions are not equal to each other. +/// +/// On panic, this macro will print the values of the expressions with their +/// debug representations. +/// +/// Unlike `assert_ne!`, `debug_assert_ne!` statements are only enabled in non +/// optimized builds by default. An optimized build will omit all +/// `debug_assert_ne!` statements unless `-C debug-assertions` is passed to the +/// compiler. This makes `debug_assert_ne!` useful for checks that are too +/// expensive to be present in a release build but may be helpful during +/// development. +/// +/// # Examples +/// +/// ``` +/// let a = 3; +/// let b = 2; +/// debug_assert_ne!(a, b); +/// ``` +#[macro_export] +#[stable(feature = "assert_ne", since = "1.12.0")] +macro_rules! debug_assert_ne { + ($($arg:tt)*) => (if cfg!(debug_assertions) { assert_ne!($($arg)*); }) +} + /// Helper macro for reducing boilerplate code for matching `Result` together /// with converting downstream errors. /// diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 115a24fc83c2..912045453e08 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -304,8 +304,8 @@ use prelude::v1::*; // We want to reexport a few macros from core but libcore has already been // imported by the compiler (via our #[no_std] attribute) In this case we just // add a new crate name so we can attach the reexports to it. -#[macro_reexport(assert, assert_eq, debug_assert, debug_assert_eq, - unreachable, unimplemented, write, writeln, try)] +#[macro_reexport(assert, assert_eq, assert_ne, debug_assert, debug_assert_eq, + debug_assert_ne, unreachable, unimplemented, write, writeln, try)] extern crate core as __core; #[macro_use] diff --git a/src/test/run-pass/assert-ne-macro-success.rs b/src/test/run-pass/assert-ne-macro-success.rs new file mode 100644 index 000000000000..ce671d2f1b5a --- /dev/null +++ b/src/test/run-pass/assert-ne-macro-success.rs @@ -0,0 +1,22 @@ +// 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. + +#[derive(PartialEq, Debug)] +struct Point { x : isize } + +pub fn main() { + assert_ne!(666,14); + assert_ne!("666".to_string(),"abc".to_string()); + assert_ne!(Box::new(Point{x:666}),Box::new(Point{x:34})); + assert_ne!(&Point{x:666},&Point{x:34}); + assert_ne!(666, 42, "no gods no masters"); + assert_ne!(666, 42, "6 {} 6", "6"); + assert_ne!(666, 42, "{x}, {y}, {z}", x = 6, y = 6, z = 6); +} diff --git a/src/test/run-pass/assert-ne-macro-unsized.rs b/src/test/run-pass/assert-ne-macro-unsized.rs new file mode 100644 index 000000000000..eeac0b6f9f68 --- /dev/null +++ b/src/test/run-pass/assert-ne-macro-unsized.rs @@ -0,0 +1,13 @@ +// 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. + +pub fn main() { + assert_ne!([6, 6, 6][..], vec![1, 2, 3][..]); +} From f4fa62f4f2b984ca97e7d68dbf8c2f3cf88866c5 Mon Sep 17 00:00:00 2001 From: Jeffrey Seyfried Date: Wed, 21 Sep 2016 09:23:17 +0000 Subject: [PATCH 443/443] Add regression test. --- src/test/compile-fail/issue-36617.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 src/test/compile-fail/issue-36617.rs diff --git a/src/test/compile-fail/issue-36617.rs b/src/test/compile-fail/issue-36617.rs new file mode 100644 index 000000000000..9f5eeb1a45dc --- /dev/null +++ b/src/test/compile-fail/issue-36617.rs @@ -0,0 +1,11 @@ +// 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. + +#![derive(Copy)] //~ ERROR `derive` may only be applied to structs, enums and unions