]> git.lizzy.rs Git - rust.git/commitdiff
Auto merge of #37951 - jseyfried:improve_macro_resolution_perf, r=nrc
authorbors <bors@rust-lang.org>
Thu, 24 Nov 2016 21:31:47 +0000 (15:31 -0600)
committerGitHub <noreply@github.com>
Thu, 24 Nov 2016 21:31:47 +0000 (15:31 -0600)
macros: improve resolution performance

Avoid quadratic legacy macro name resolution in more cases.
r? @nrc

154 files changed:
configure
src/compiler-rt
src/doc/index.md
src/libcollections/lib.rs
src/libcollections/vec.rs
src/libcollectionstest/lib.rs
src/libcollectionstest/slice.rs
src/libcore/iter/mod.rs
src/libcore/slice.rs
src/libcoretest/iter.rs
src/librustc/cfg/construct.rs
src/librustc/hir/intravisit.rs
src/librustc/hir/lowering.rs
src/librustc/hir/mod.rs
src/librustc/hir/print.rs
src/librustc/lint/builtin.rs
src/librustc/middle/cstore.rs
src/librustc/middle/dependency_format.rs
src/librustc/middle/expr_use_visitor.rs
src/librustc/middle/liveness.rs
src/librustc/middle/reachable.rs
src/librustc/middle/region.rs
src/librustc/middle/resolve_lifetime.rs
src/librustc/middle/weak_lang_items.rs
src/librustc/session/code_stats.rs [new file with mode: 0644]
src/librustc/session/config.rs
src/librustc/session/mod.rs
src/librustc/ty/layout.rs
src/librustc/ty/mod.rs
src/librustc/ty/sty.rs
src/librustc/ty/walk.rs
src/librustc/util/common.rs
src/librustc_const_eval/check_match.rs
src/librustc_const_eval/eval.rs
src/librustc_data_structures/small_vec.rs
src/librustc_driver/driver.rs
src/librustc_incremental/calculate_svh/svh_visitor.rs
src/librustc_lint/lib.rs
src/librustc_metadata/creader.rs
src/librustc_metadata/cstore.rs
src/librustc_metadata/cstore_impl.rs
src/librustc_metadata/decoder.rs
src/librustc_metadata/encoder.rs
src/librustc_metadata/locator.rs
src/librustc_metadata/schema.rs
src/librustc_mir/build/expr/into.rs
src/librustc_mir/build/expr/stmt.rs
src/librustc_mir/build/mod.rs
src/librustc_mir/build/scope.rs
src/librustc_mir/hair/cx/expr.rs
src/librustc_mir/hair/mod.rs
src/librustc_passes/ast_validation.rs
src/librustc_passes/consts.rs
src/librustc_passes/diagnostics.rs
src/librustc_passes/loops.rs
src/librustc_resolve/lib.rs
src/librustc_save_analysis/dump_visitor.rs
src/librustc_save_analysis/lib.rs
src/librustc_trans/adt.rs
src/librustc_trans/back/archive.rs
src/librustc_trans/back/link.rs
src/librustc_trans/back/rpath.rs
src/librustc_trans/base.rs
src/librustc_typeck/check/callee.rs
src/librustc_typeck/check/cast.rs
src/librustc_typeck/check/mod.rs
src/librustc_typeck/check/regionck.rs
src/librustdoc/clean/inline.rs
src/librustdoc/clean/mod.rs
src/librustdoc/clean/simplify.rs
src/librustdoc/core.rs
src/librustdoc/html/render.rs
src/librustdoc/lib.rs
src/librustdoc/passes/collapse_docs.rs
src/librustdoc/passes/strip_hidden.rs
src/librustdoc/passes/unindent_comments.rs
src/librustdoc/test.rs
src/librustdoc/visit_ast.rs
src/librustdoc/visit_lib.rs
src/libstd/env.rs
src/libstd/fs.rs
src/libstd/net/addr.rs
src/libstd/sys/unix/fs.rs
src/libstd/sys/windows/c.rs
src/libstd/sys/windows/fs.rs
src/libsyntax/ast.rs
src/libsyntax/ext/base.rs
src/libsyntax/ext/build.rs
src/libsyntax/ext/expand.rs
src/libsyntax/ext/source_util.rs
src/libsyntax/ext/tt/macro_rules.rs
src/libsyntax/feature_gate.rs
src/libsyntax/fold.rs
src/libsyntax/parse/mod.rs
src/libsyntax/parse/parser.rs
src/libsyntax/print/pprust.rs
src/libsyntax/visit.rs
src/test/compile-fail/auxiliary/rmeta_meta.rs [new file with mode: 0644]
src/test/compile-fail/auxiliary/rmeta_rlib.rs [new file with mode: 0644]
src/test/compile-fail/cast-rfc0401.rs
src/test/compile-fail/directory_ownership/backcompat-warnings.rs [new file with mode: 0644]
src/test/compile-fail/directory_ownership/macro-expanded-mod.rs [new file with mode: 0644]
src/test/compile-fail/directory_ownership/macro_expanded_mod_helper/foo/bar.rs [new file with mode: 0644]
src/test/compile-fail/directory_ownership/macro_expanded_mod_helper/foo/mod.rs [new file with mode: 0644]
src/test/compile-fail/directory_ownership/mod_file_not_owning.rs [new file with mode: 0644]
src/test/compile-fail/directory_ownership/mod_file_not_owning_aux1.rs [new file with mode: 0644]
src/test/compile-fail/directory_ownership/mod_file_not_owning_aux2.rs [new file with mode: 0644]
src/test/compile-fail/directory_ownership/mod_file_not_owning_aux3.rs [new file with mode: 0644]
src/test/compile-fail/directory_ownership/non-inline-mod-restriction.rs [new file with mode: 0644]
src/test/compile-fail/directory_ownership/unowned_mod_with_path.rs [new file with mode: 0644]
src/test/compile-fail/feature-gate-loop-break-value.rs [new file with mode: 0644]
src/test/compile-fail/loop-break-value.rs [new file with mode: 0644]
src/test/compile-fail/macro-expanded-mod.rs [deleted file]
src/test/compile-fail/macro_expanded_mod_helper/foo/bar.rs [deleted file]
src/test/compile-fail/macro_expanded_mod_helper/foo/mod.rs [deleted file]
src/test/compile-fail/mod_file_not_owning.rs [deleted file]
src/test/compile-fail/mod_file_not_owning_aux1.rs [deleted file]
src/test/compile-fail/mod_file_not_owning_aux2.rs [deleted file]
src/test/compile-fail/non-inline-mod-restriction.rs [deleted file]
src/test/compile-fail/rmeta-lib-pass.rs [new file with mode: 0644]
src/test/compile-fail/rmeta-pass.rs [new file with mode: 0644]
src/test/compile-fail/rmeta.rs [new file with mode: 0644]
src/test/compile-fail/rmeta_lib.rs [new file with mode: 0644]
src/test/compile-fail/rmeta_meta_main.rs [new file with mode: 0644]
src/test/incremental/hashes/struct_constructors.rs [new file with mode: 0644]
src/test/parse-fail/circular_modules_hello.rs
src/test/run-make/save-analysis-fail/Makefile [new file with mode: 0644]
src/test/run-make/save-analysis-fail/SameDir.rs [new file with mode: 0644]
src/test/run-make/save-analysis-fail/SameDir3.rs [new file with mode: 0644]
src/test/run-make/save-analysis-fail/SubDir/mod.rs [new file with mode: 0644]
src/test/run-make/save-analysis-fail/foo.rs [new file with mode: 0644]
src/test/run-make/save-analysis-fail/krate2.rs [new file with mode: 0644]
src/test/run-pass-fulldeps/myriad-closures.rs [new file with mode: 0644]
src/test/run-pass/auxiliary/rmeta_rlib.rs [new file with mode: 0644]
src/test/run-pass/auxiliary/rmeta_rmeta.rs [new file with mode: 0644]
src/test/run-pass/issue-23699.rs [new file with mode: 0644]
src/test/run-pass/loop-break-value.rs [new file with mode: 0644]
src/test/run-pass/myriad-closures.rs [deleted file]
src/test/run-pass/rmeta.rs [new file with mode: 0644]
src/test/ui/print_type_sizes/anonymous.rs [new file with mode: 0644]
src/test/ui/print_type_sizes/generics.rs [new file with mode: 0644]
src/test/ui/print_type_sizes/generics.stdout [new file with mode: 0644]
src/test/ui/print_type_sizes/multiple_types.rs [new file with mode: 0644]
src/test/ui/print_type_sizes/multiple_types.stdout [new file with mode: 0644]
src/test/ui/print_type_sizes/no_duplicates.rs [new file with mode: 0644]
src/test/ui/print_type_sizes/no_duplicates.stdout [new file with mode: 0644]
src/test/ui/print_type_sizes/nullable.rs [new file with mode: 0644]
src/test/ui/print_type_sizes/nullable.stdout [new file with mode: 0644]
src/test/ui/print_type_sizes/packed.rs [new file with mode: 0644]
src/test/ui/print_type_sizes/packed.stdout [new file with mode: 0644]
src/test/ui/print_type_sizes/padding.rs [new file with mode: 0644]
src/test/ui/print_type_sizes/padding.stdout [new file with mode: 0644]
src/test/ui/print_type_sizes/variants.rs [new file with mode: 0644]
src/test/ui/print_type_sizes/variants.stdout [new file with mode: 0644]

index 133af075795c67981ff45e6241f455b7297302cf..5311bf4b064eb8cac4c9054a9df70c8017175b1d 100755 (executable)
--- a/configure
+++ b/configure
@@ -856,7 +856,7 @@ probe_need CFG_CMAKE cmake
 if [ -n "$CFG_ANTLR4" ]
 then
    CFG_ANTLR4_JAR="\"$(find /usr/ -name antlr-complete.jar 2>/dev/null | head -n 1)\""
-   if [ "x" -eq "x$CFG_ANTLR4_JAR" ]
+   if [ "x" = "x$CFG_ANTLR4_JAR" ]
    then
      CFG_ANTLR4_JAR="\"$(find ~ -name antlr-complete.jar 2>/dev/null | head -n 1)\""
    fi
index 3bc0272cab9fdcfc2ef4df9625ec3c9d5909db79..a8fc4c169fac43a5dc204d4fd56ddb1739f8c178 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 3bc0272cab9fdcfc2ef4df9625ec3c9d5909db79
+Subproject commit a8fc4c169fac43a5dc204d4fd56ddb1739f8c178
index f8a1ec134d9242faa877a156868a53dfc5efa110..71dfcf0b067ec2395b45fb0652b36036d1dd6e7f 100644 (file)
@@ -17,7 +17,7 @@ the language.
 
 [**The Rust Reference**][ref]. While Rust does not have a
 specification, the reference tries to describe its working in
-detail. It tends to be out of date.
+detail. It is accurate, but not necessarily complete.
 
 [**Standard Library API Reference**][api]. Documentation for the
 standard library.
index 23d6edd6d794e88c86cc7b2cfc2d0267365a2ee6..f6d83b25b0d89c598468015b5fdfdb04dfd6f19e 100644 (file)
@@ -36,6 +36,7 @@
 #![cfg_attr(not(test), feature(char_escape_debug))]
 #![feature(core_intrinsics)]
 #![feature(dropck_parametricity)]
+#![feature(exact_size_is_empty)]
 #![feature(fmt_internals)]
 #![feature(fused)]
 #![feature(heap_api)]
index 24f8e3a2d918144a8cbda94dccfb1545ef292a95..f26324127003b32b12ecc7570b93ff627c19f8e6 100644 (file)
@@ -1988,7 +1988,11 @@ fn next_back(&mut self) -> Option<T> {
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T> ExactSizeIterator for IntoIter<T> {}
+impl<T> ExactSizeIterator for IntoIter<T> {
+    fn is_empty(&self) -> bool {
+        self.ptr == self.end
+    }
+}
 
 #[unstable(feature = "fused", issue = "35602")]
 impl<T> FusedIterator for IntoIter<T> {}
@@ -2082,7 +2086,11 @@ fn drop(&mut self) {
 
 
 #[stable(feature = "drain", since = "1.6.0")]
-impl<'a, T> ExactSizeIterator for Drain<'a, T> {}
+impl<'a, T> ExactSizeIterator for Drain<'a, T> {
+    fn is_empty(&self) -> bool {
+        self.iter.is_empty()
+    }
+}
 
 #[unstable(feature = "fused", issue = "35602")]
 impl<'a, T> FusedIterator for Drain<'a, T> {}
index 14ec8d58bef61065ad669414be9eb19850670a8d..1e08074b14db8bf5d634544cdf1742df809ba7eb 100644 (file)
@@ -18,6 +18,7 @@
 #![feature(const_fn)]
 #![feature(dedup_by)]
 #![feature(enumset)]
+#![feature(exact_size_is_empty)]
 #![feature(pattern)]
 #![feature(rand)]
 #![feature(repeat_str)]
index a6230ef471cec0f69f9cb197ae8f9cd24a16c9c0..0e63e8d4a1ec8ad6a5ec32202b7841e8d2810b8e 100644 (file)
@@ -633,6 +633,16 @@ fn test_iter_clone() {
     assert_eq!(it.next(), jt.next());
 }
 
+#[test]
+fn test_iter_is_empty() {
+    let xs = [1, 2, 5, 10, 11];
+    for i in 0..xs.len() {
+        for j in i..xs.len() {
+            assert_eq!(xs[i..j].iter().is_empty(), xs[i..j].is_empty());
+        }
+    }
+}
+
 #[test]
 fn test_mut_iterator() {
     let mut xs = [1, 2, 3, 4, 5];
index cd2e0cb11d35e0a2c3362cd217337648b94f6175..2e08508de67f3ad1b887c8d922ae580e1360de94 100644 (file)
@@ -368,7 +368,16 @@ fn next_back(&mut self) -> Option<<I as Iterator>::Item> { self.iter.next() }
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<I> ExactSizeIterator for Rev<I>
-    where I: ExactSizeIterator + DoubleEndedIterator {}
+    where I: ExactSizeIterator + DoubleEndedIterator
+{
+    fn len(&self) -> usize {
+        self.iter.len()
+    }
+
+    fn is_empty(&self) -> bool {
+        self.iter.is_empty()
+    }
+}
 
 #[unstable(feature = "fused", issue = "35602")]
 impl<I> FusedIterator for Rev<I>
@@ -425,7 +434,15 @@ fn next_back(&mut self) -> Option<T> {
 #[stable(feature = "iter_cloned", since = "1.1.0")]
 impl<'a, I, T: 'a> ExactSizeIterator for Cloned<I>
     where I: ExactSizeIterator<Item=&'a T>, T: Clone
-{}
+{
+    fn len(&self) -> usize {
+        self.it.len()
+    }
+
+    fn is_empty(&self) -> bool {
+        self.it.is_empty()
+    }
+}
 
 #[unstable(feature = "fused", issue = "35602")]
 impl<'a, I, T: 'a> FusedIterator for Cloned<I>
@@ -1007,7 +1024,16 @@ fn next_back(&mut self) -> Option<B> {
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<B, I: ExactSizeIterator, F> ExactSizeIterator for Map<I, F>
-    where F: FnMut(I::Item) -> B {}
+    where F: FnMut(I::Item) -> B
+{
+    fn len(&self) -> usize {
+        self.iter.len()
+    }
+
+    fn is_empty(&self) -> bool {
+        self.iter.is_empty()
+    }
+}
 
 #[unstable(feature = "fused", issue = "35602")]
 impl<B, I: FusedIterator, F> FusedIterator for Map<I, F>
@@ -1236,7 +1262,15 @@ fn next_back(&mut self) -> Option<(usize, <I as Iterator>::Item)> {
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<I> ExactSizeIterator for Enumerate<I> where I: ExactSizeIterator {}
+impl<I> ExactSizeIterator for Enumerate<I> where I: ExactSizeIterator {
+    fn len(&self) -> usize {
+        self.iter.len()
+    }
+
+    fn is_empty(&self) -> bool {
+        self.iter.is_empty()
+    }
+}
 
 #[doc(hidden)]
 unsafe impl<I> TrustedRandomAccess for Enumerate<I>
@@ -1273,54 +1307,68 @@ unsafe impl<I> TrustedLen for Enumerate<I>
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Peekable<I: Iterator> {
     iter: I,
-    peeked: Option<I::Item>,
+    /// Remember a peeked value, even if it was None.
+    peeked: Option<Option<I::Item>>,
 }
 
+// Peekable must remember if a None has been seen in the `.peek()` method.
+// It ensures that `.peek(); .peek();` or `.peek(); .next();` only advances the
+// underlying iterator at most once. This does not by itself make the iterator
+// fused.
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<I: Iterator> Iterator for Peekable<I> {
     type Item = I::Item;
 
     #[inline]
     fn next(&mut self) -> Option<I::Item> {
-        match self.peeked {
-            Some(_) => self.peeked.take(),
+        match self.peeked.take() {
+            Some(v) => v,
             None => self.iter.next(),
         }
     }
 
     #[inline]
     #[rustc_inherit_overflow_checks]
-    fn count(self) -> usize {
-        (if self.peeked.is_some() { 1 } else { 0 }) + self.iter.count()
+    fn count(mut self) -> usize {
+        match self.peeked.take() {
+            Some(None) => 0,
+            Some(Some(_)) => 1 + self.iter.count(),
+            None => self.iter.count(),
+        }
     }
 
     #[inline]
     fn nth(&mut self, n: usize) -> Option<I::Item> {
-        match self.peeked {
-            Some(_) if n == 0 => self.peeked.take(),
-            Some(_) => {
-                self.peeked = None;
-                self.iter.nth(n-1)
-            },
-            None => self.iter.nth(n)
+        match self.peeked.take() {
+            // the .take() below is just to avoid "move into pattern guard"
+            Some(ref mut v) if n == 0 => v.take(),
+            Some(None) => None,
+            Some(Some(_)) => self.iter.nth(n - 1),
+            None => self.iter.nth(n),
         }
     }
 
     #[inline]
-    fn last(self) -> Option<I::Item> {
-        self.iter.last().or(self.peeked)
+    fn last(mut self) -> Option<I::Item> {
+        let peek_opt = match self.peeked.take() {
+            Some(None) => return None,
+            Some(v) => v,
+            None => None,
+        };
+        self.iter.last().or(peek_opt)
     }
 
     #[inline]
     fn size_hint(&self) -> (usize, Option<usize>) {
+        let peek_len = match self.peeked {
+            Some(None) => return (0, Some(0)),
+            Some(Some(_)) => 1,
+            None => 0,
+        };
         let (lo, hi) = self.iter.size_hint();
-        if self.peeked.is_some() {
-            let lo = lo.saturating_add(1);
-            let hi = hi.and_then(|x| x.checked_add(1));
-            (lo, hi)
-        } else {
-            (lo, hi)
-        }
+        let lo = lo.saturating_add(peek_len);
+        let hi = hi.and_then(|x| x.checked_add(peek_len));
+        (lo, hi)
     }
 }
 
@@ -1372,9 +1420,13 @@ impl<I: Iterator> Peekable<I> {
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn peek(&mut self) -> Option<&I::Item> {
         if self.peeked.is_none() {
-            self.peeked = self.iter.next();
+            self.peeked = Some(self.iter.next());
+        }
+        match self.peeked {
+            Some(Some(ref value)) => Some(value),
+            Some(None) => None,
+            _ => unreachable!(),
         }
-        self.peeked.as_ref()
     }
 }
 
@@ -1927,7 +1979,15 @@ fn next_back(&mut self) -> Option<<I as Iterator>::Item> {
 
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<I> ExactSizeIterator for Fuse<I> where I: ExactSizeIterator {}
+impl<I> ExactSizeIterator for Fuse<I> where I: ExactSizeIterator {
+    fn len(&self) -> usize {
+        self.iter.len()
+    }
+
+    fn is_empty(&self) -> bool {
+        self.iter.is_empty()
+    }
+}
 
 /// An iterator that calls a function with a reference to each element before
 /// yielding it.
@@ -1994,7 +2054,16 @@ fn next_back(&mut self) -> Option<I::Item> {
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<I: ExactSizeIterator, F> ExactSizeIterator for Inspect<I, F>
-    where F: FnMut(&I::Item) {}
+    where F: FnMut(&I::Item)
+{
+    fn len(&self) -> usize {
+        self.iter.len()
+    }
+
+    fn is_empty(&self) -> bool {
+        self.iter.is_empty()
+    }
+}
 
 #[unstable(feature = "fused", issue = "35602")]
 impl<I: FusedIterator, F> FusedIterator for Inspect<I, F>
index 871b63145ca6d24c8981bae053aadc54bfee7a6c..ede45111ebbc587371980cd02e27129f2022d6ef 100644 (file)
@@ -983,7 +983,11 @@ fn iter_nth(&mut self, n: usize) -> Option<&'a T> {
 iterator!{struct Iter -> *const T, &'a T}
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, T> ExactSizeIterator for Iter<'a, T> {}
+impl<'a, T> ExactSizeIterator for Iter<'a, T> {
+    fn is_empty(&self) -> bool {
+        self.ptr == self.end
+    }
+}
 
 #[unstable(feature = "fused", issue = "35602")]
 impl<'a, T> FusedIterator for Iter<'a, T> {}
@@ -1107,7 +1111,11 @@ fn iter_nth(&mut self, n: usize) -> Option<&'a mut T> {
 iterator!{struct IterMut -> *mut T, &'a mut T}
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, T> ExactSizeIterator for IterMut<'a, T> {}
+impl<'a, T> ExactSizeIterator for IterMut<'a, T> {
+    fn is_empty(&self) -> bool {
+        self.ptr == self.end
+    }
+}
 
 #[unstable(feature = "fused", issue = "35602")]
 impl<'a, T> FusedIterator for IterMut<'a, T> {}
index 58b6444ef88cd95f278d4c0b458516573b1cc5c4..274539dfa6699ff2ae4be624b0d717fbdf769fd5 100644 (file)
@@ -274,6 +274,74 @@ fn test_iterator_peekable_last() {
     let mut it = ys.iter().peekable();
     assert_eq!(it.peek(), Some(&&0));
     assert_eq!(it.last(), Some(&0));
+
+    let mut it = ys.iter().peekable();
+    assert_eq!(it.next(), Some(&0));
+    assert_eq!(it.peek(), None);
+    assert_eq!(it.last(), None);
+}
+
+/// This is an iterator that follows the Iterator contract,
+/// but it is not fused. After having returned None once, it will start
+/// producing elements if .next() is called again.
+pub struct CycleIter<'a, T: 'a> {
+    index: usize,
+    data: &'a [T],
+}
+
+pub fn cycle<T>(data: &[T]) -> CycleIter<T> {
+    CycleIter {
+        index: 0,
+        data: data,
+    }
+}
+
+impl<'a, T> Iterator for CycleIter<'a, T> {
+    type Item = &'a T;
+    fn next(&mut self) -> Option<Self::Item> {
+        let elt = self.data.get(self.index);
+        self.index += 1;
+        self.index %= 1 + self.data.len();
+        elt
+    }
+}
+
+#[test]
+fn test_iterator_peekable_remember_peek_none_1() {
+    // Check that the loop using .peek() terminates
+    let data = [1, 2, 3];
+    let mut iter = cycle(&data).peekable();
+
+    let mut n = 0;
+    while let Some(_) = iter.next() {
+        let is_the_last = iter.peek().is_none();
+        assert_eq!(is_the_last, n == data.len() - 1);
+        n += 1;
+        if n > data.len() { break; }
+    }
+    assert_eq!(n, data.len());
+}
+
+#[test]
+fn test_iterator_peekable_remember_peek_none_2() {
+    let data = [0];
+    let mut iter = cycle(&data).peekable();
+    iter.next();
+    assert_eq!(iter.peek(), None);
+    assert_eq!(iter.last(), None);
+}
+
+#[test]
+fn test_iterator_peekable_remember_peek_none_3() {
+    let data = [0];
+    let mut iter = cycle(&data).peekable();
+    iter.peek();
+    assert_eq!(iter.nth(0), Some(&0));
+
+    let mut iter = cycle(&data).peekable();
+    iter.next();
+    assert_eq!(iter.peek(), None);
+    assert_eq!(iter.nth(0), None);
 }
 
 #[test]
index 22c7d14be29d205dbe172c7a96ca322605d7df6d..c399623462b5d732368fe2fab0ac64b762521ee2 100644 (file)
@@ -223,7 +223,7 @@ fn expr(&mut self, expr: &hir::Expr, pred: CFGIndex) -> CFGIndex {
                 expr_exit
             }
 
-            hir::ExprLoop(ref body, _) => {
+            hir::ExprLoop(ref body, _, _) => {
                 //
                 //     [pred]
                 //       |
@@ -282,9 +282,10 @@ fn expr(&mut self, expr: &hir::Expr, pred: CFGIndex) -> CFGIndex {
                 self.add_unreachable_node()
             }
 
-            hir::ExprBreak(label) => {
+            hir::ExprBreak(label, ref opt_expr) => {
+                let v = self.opt_expr(opt_expr, pred);
                 let loop_scope = self.find_scope(expr, label.map(|l| l.node));
-                let b = self.add_ast_node(expr.id, &[pred]);
+                let b = self.add_ast_node(expr.id, &[v]);
                 self.add_exiting_edge(expr, b,
                                       loop_scope, loop_scope.break_index);
                 self.add_unreachable_node()
@@ -299,15 +300,15 @@ fn expr(&mut self, expr: &hir::Expr, pred: CFGIndex) -> CFGIndex {
             }
 
             hir::ExprArray(ref elems) => {
-                self.straightline(expr, pred, elems.iter().map(|e| &**e))
+                self.straightline(expr, pred, elems.iter().map(|e| &*e))
             }
 
             hir::ExprCall(ref func, ref args) => {
-                self.call(expr, pred, &func, args.iter().map(|e| &**e))
+                self.call(expr, pred, &func, args.iter().map(|e| &*e))
             }
 
             hir::ExprMethodCall(.., ref args) => {
-                self.call(expr, pred, &args[0], args[1..].iter().map(|e| &**e))
+                self.call(expr, pred, &args[0], args[1..].iter().map(|e| &*e))
             }
 
             hir::ExprIndex(ref l, ref r) |
@@ -320,7 +321,7 @@ fn expr(&mut self, expr: &hir::Expr, pred: CFGIndex) -> CFGIndex {
             }
 
             hir::ExprTup(ref exprs) => {
-                self.straightline(expr, pred, exprs.iter().map(|e| &**e))
+                self.straightline(expr, pred, exprs.iter().map(|e| &*e))
             }
 
             hir::ExprStruct(_, ref fields, ref base) => {
@@ -353,8 +354,8 @@ fn expr(&mut self, expr: &hir::Expr, pred: CFGIndex) -> CFGIndex {
             }
 
             hir::ExprInlineAsm(_, ref outputs, ref inputs) => {
-                let post_outputs = self.exprs(outputs.iter().map(|e| &**e), pred);
-                let post_inputs = self.exprs(inputs.iter().map(|e| &**e), post_outputs);
+                let post_outputs = self.exprs(outputs.iter().map(|e| &*e), pred);
+                let post_inputs = self.exprs(inputs.iter().map(|e| &*e), post_outputs);
                 self.add_ast_node(expr.id, &[post_inputs])
             }
 
index 4cfa889ec561676f7e1156bd7c55cb4afd51827a..7dd88e36dd1f55ca7fe93d2092f2f893e801fe8c 100644 (file)
@@ -882,7 +882,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
             visitor.visit_block(block);
             walk_opt_sp_name(visitor, opt_sp_name);
         }
-        ExprLoop(ref block, ref opt_sp_name) => {
+        ExprLoop(ref block, ref opt_sp_name, _) => {
             visitor.visit_block(block);
             walk_opt_sp_name(visitor, opt_sp_name);
         }
@@ -923,7 +923,11 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
             }
             visitor.visit_path(path, expression.id)
         }
-        ExprBreak(ref opt_sp_name) | ExprAgain(ref opt_sp_name) => {
+        ExprBreak(ref opt_sp_name, ref opt_expr) => {
+            walk_opt_sp_name(visitor, opt_sp_name);
+            walk_list!(visitor, visit_expr, opt_expr);
+        }
+        ExprAgain(ref opt_sp_name) => {
             walk_opt_sp_name(visitor, opt_sp_name);
         }
         ExprRet(ref optional_expression) => {
index 9547e09afe0035a6942c1caca56b38afa2e28897..5af7c18e1a1078f4c9cc14849f59b0691d8b01ba 100644 (file)
@@ -210,8 +210,8 @@ fn lower_arm(&mut self, arm: &Arm) -> hir::Arm {
         hir::Arm {
             attrs: self.lower_attrs(&arm.attrs),
             pats: arm.pats.iter().map(|x| self.lower_pat(x)).collect(),
-            guard: arm.guard.as_ref().map(|ref x| self.lower_expr(x)),
-            body: self.lower_expr(&arm.body),
+            guard: arm.guard.as_ref().map(|ref x| P(self.lower_expr(x))),
+            body: P(self.lower_expr(&arm.body)),
         }
     }
 
@@ -262,10 +262,10 @@ fn lower_ty(&mut self, t: &Ty) -> P<hir::Ty> {
                     hir::TyObjectSum(self.lower_ty(ty), self.lower_bounds(bounds))
                 }
                 TyKind::Array(ref ty, ref e) => {
-                    hir::TyArray(self.lower_ty(ty), self.lower_expr(e))
+                    hir::TyArray(self.lower_ty(ty), P(self.lower_expr(e)))
                 }
                 TyKind::Typeof(ref expr) => {
-                    hir::TyTypeof(self.lower_expr(expr))
+                    hir::TyTypeof(P(self.lower_expr(expr)))
                 }
                 TyKind::PolyTraitRef(ref bounds) => {
                     hir::TyPolyTraitRef(self.lower_bounds(bounds))
@@ -292,7 +292,7 @@ fn lower_variant(&mut self, v: &Variant) -> hir::Variant {
                 name: v.node.name.name,
                 attrs: self.lower_attrs(&v.node.attrs),
                 data: self.lower_variant_data(&v.node.data),
-                disr_expr: v.node.disr_expr.as_ref().map(|e| self.lower_expr(e)),
+                disr_expr: v.node.disr_expr.as_ref().map(|e| P(self.lower_expr(e))),
             },
             span: v.span,
         }
@@ -350,7 +350,7 @@ fn lower_local(&mut self, l: &Local) -> P<hir::Local> {
             id: l.id,
             ty: l.ty.as_ref().map(|t| self.lower_ty(t)),
             pat: self.lower_pat(&l.pat),
-            init: l.init.as_ref().map(|e| self.lower_expr(e)),
+            init: l.init.as_ref().map(|e| P(self.lower_expr(e))),
             span: l.span,
             attrs: l.attrs.clone(),
         })
@@ -550,7 +550,7 @@ fn lower_struct_field(&mut self, (index, f): (usize, &StructField)) -> hir::Stru
     fn lower_field(&mut self, f: &Field) -> hir::Field {
         hir::Field {
             name: respan(f.ident.span, f.ident.node.name),
-            expr: self.lower_expr(&f.expr),
+            expr: P(self.lower_expr(&f.expr)),
             span: f.span,
             is_shorthand: f.is_shorthand,
         }
@@ -599,10 +599,10 @@ fn lower_item_kind(&mut self, i: &ItemKind) -> hir::Item_ {
             ItemKind::Static(ref t, m, ref e) => {
                 hir::ItemStatic(self.lower_ty(t),
                                 self.lower_mutability(m),
-                                self.lower_expr(e))
+                                P(self.lower_expr(e)))
             }
             ItemKind::Const(ref t, ref e) => {
-                hir::ItemConst(self.lower_ty(t), self.lower_expr(e))
+                hir::ItemConst(self.lower_ty(t), P(self.lower_expr(e)))
             }
             ItemKind::Fn(ref decl, unsafety, constness, abi, ref generics, ref body) => {
                 let body = self.lower_block(body);
@@ -611,7 +611,7 @@ fn lower_item_kind(&mut self, i: &ItemKind) -> hir::Item_ {
                             self.lower_constness(constness),
                             abi,
                             self.lower_generics(generics),
-                            self.expr_block(body, ThinVec::new()))
+                            P(self.expr_block(body, ThinVec::new())))
             }
             ItemKind::Mod(ref m) => hir::ItemMod(self.lower_mod(m)),
             ItemKind::ForeignMod(ref nm) => hir::ItemForeignMod(self.lower_foreign_mod(nm)),
@@ -672,13 +672,13 @@ fn lower_trait_item(&mut self, i: &TraitItem) -> hir::TraitItem {
                 node: match i.node {
                     TraitItemKind::Const(ref ty, ref default) => {
                         hir::ConstTraitItem(this.lower_ty(ty),
-                                            default.as_ref().map(|x| this.lower_expr(x)))
+                                            default.as_ref().map(|x| P(this.lower_expr(x))))
                     }
                     TraitItemKind::Method(ref sig, ref body) => {
                         hir::MethodTraitItem(this.lower_method_sig(sig),
                                              body.as_ref().map(|x| {
                             let body = this.lower_block(x);
-                            this.expr_block(body, ThinVec::new())
+                            P(this.expr_block(body, ThinVec::new()))
                         }))
                     }
                     TraitItemKind::Type(ref bounds, ref default) => {
@@ -702,12 +702,12 @@ fn lower_impl_item(&mut self, i: &ImplItem) -> hir::ImplItem {
                 defaultness: this.lower_defaultness(i.defaultness, true /* [1] */),
                 node: match i.node {
                     ImplItemKind::Const(ref ty, ref expr) => {
-                        hir::ImplItemKind::Const(this.lower_ty(ty), this.lower_expr(expr))
+                        hir::ImplItemKind::Const(this.lower_ty(ty), P(this.lower_expr(expr)))
                     }
                     ImplItemKind::Method(ref sig, ref body) => {
                         let body = this.lower_block(body);
                         hir::ImplItemKind::Method(this.lower_method_sig(sig),
-                                                  this.expr_block(body, ThinVec::new()))
+                                                  P(this.expr_block(body, ThinVec::new())))
                     }
                     ImplItemKind::Type(ref ty) => hir::ImplItemKind::Type(this.lower_ty(ty)),
                     ImplItemKind::Macro(..) => panic!("Shouldn't exist any more"),
@@ -885,7 +885,7 @@ fn lower_pat(&mut self, p: &Pat) -> P<hir::Pat> {
                         }
                     })
                 }
-                PatKind::Lit(ref e) => hir::PatKind::Lit(self.lower_expr(e)),
+                PatKind::Lit(ref e) => hir::PatKind::Lit(P(self.lower_expr(e))),
                 PatKind::TupleStruct(ref path, ref pats, ddpos) => {
                     hir::PatKind::TupleStruct(self.lower_path(path),
                                         pats.iter().map(|x| self.lower_pat(x)).collect(), ddpos)
@@ -920,7 +920,7 @@ fn lower_pat(&mut self, p: &Pat) -> P<hir::Pat> {
                     hir::PatKind::Ref(self.lower_pat(inner), self.lower_mutability(mutbl))
                 }
                 PatKind::Range(ref e1, ref e2) => {
-                    hir::PatKind::Range(self.lower_expr(e1), self.lower_expr(e2))
+                    hir::PatKind::Range(P(self.lower_expr(e1)), P(self.lower_expr(e2)))
                 }
                 PatKind::Slice(ref before, ref slice, ref after) => {
                     hir::PatKind::Slice(before.iter().map(|x| self.lower_pat(x)).collect(),
@@ -933,8 +933,8 @@ fn lower_pat(&mut self, p: &Pat) -> P<hir::Pat> {
         })
     }
 
-    fn lower_expr(&mut self, e: &Expr) -> P<hir::Expr> {
-        P(hir::Expr {
+    fn lower_expr(&mut self, e: &Expr) -> hir::Expr {
+        hir::Expr {
             id: e.id,
             node: match e.node {
                 // Issue #22181:
@@ -954,7 +954,7 @@ fn lower_expr(&mut self, e: &Expr) -> P<hir::Expr> {
                 //
                 // But for now there are type-inference issues doing that.
                 ExprKind::Box(ref e) => {
-                    hir::ExprBox(self.lower_expr(e))
+                    hir::ExprBox(P(self.lower_expr(e)))
                 }
 
                 // Desugar ExprBox: `in (PLACE) EXPR`
@@ -968,8 +968,8 @@ fn lower_expr(&mut self, e: &Expr) -> P<hir::Expr> {
                     //     std::intrinsics::move_val_init(raw_place, pop_unsafe!( EXPR ));
                     //     InPlace::finalize(place)
                     // })
-                    let placer_expr = self.lower_expr(placer);
-                    let value_expr = self.lower_expr(value_expr);
+                    let placer_expr = P(self.lower_expr(placer));
+                    let value_expr = P(self.lower_expr(value_expr));
 
                     let placer_ident = self.str_to_ident("placer");
                     let place_ident = self.str_to_ident("place");
@@ -983,7 +983,7 @@ fn lower_expr(&mut self, e: &Expr) -> P<hir::Expr> {
                     let make_call = |this: &mut LoweringContext, p, args| {
                         let path = this.std_path(e.span, p);
                         let path = this.expr_path(path, ThinVec::new());
-                        this.expr_call(e.span, path, args)
+                        P(this.expr_call(e.span, path, args))
                     };
 
                     let mk_stmt_let = |this: &mut LoweringContext, bind, expr| {
@@ -996,11 +996,11 @@ fn lower_expr(&mut self, e: &Expr) -> P<hir::Expr> {
 
                     // let placer = <placer_expr> ;
                     let (s1, placer_binding) = {
-                        let placer_expr = self.signal_block_expr(hir_vec![],
-                                                                 placer_expr,
-                                                                 e.span,
-                                                                 hir::PopUnstableBlock,
-                                                                 ThinVec::new());
+                        let placer_expr = P(self.signal_block_expr(hir_vec![],
+                                                                   placer_expr,
+                                                                   e.span,
+                                                                   hir::PopUnstableBlock,
+                                                                   ThinVec::new()));
                         mk_stmt_let(self, placer_ident, placer_expr)
                     };
 
@@ -1013,7 +1013,7 @@ fn lower_expr(&mut self, e: &Expr) -> P<hir::Expr> {
 
                     // let p_ptr = Place::pointer(&mut place);
                     let (s3, p_ptr_binding) = {
-                        let agent = self.expr_ident(e.span, place_ident, place_binding);
+                        let agent = P(self.expr_ident(e.span, place_ident, place_binding));
                         let args = hir_vec![self.expr_mut_addr_of(e.span, agent)];
                         let call = make_call(self, &place_pointer, args);
                         mk_stmt_let(self, p_ptr_ident, call)
@@ -1021,11 +1021,11 @@ fn lower_expr(&mut self, e: &Expr) -> P<hir::Expr> {
 
                     // pop_unsafe!(EXPR));
                     let pop_unsafe_expr = {
-                        let value_expr = self.signal_block_expr(hir_vec![],
-                                                                value_expr,
-                                                                e.span,
-                                                                hir::PopUnstableBlock,
-                                                                ThinVec::new());
+                        let value_expr = P(self.signal_block_expr(hir_vec![],
+                                                                  value_expr,
+                                                                  e.span,
+                                                                  hir::PopUnstableBlock,
+                                                                  ThinVec::new()));
                         self.signal_block_expr(hir_vec![],
                                                value_expr,
                                                e.span,
@@ -1047,11 +1047,11 @@ fn lower_expr(&mut self, e: &Expr) -> P<hir::Expr> {
 
                         let place = self.expr_ident(e.span, place_ident, place_binding);
                         let call = make_call(self, &inplace_finalize, hir_vec![place]);
-                        self.signal_block_expr(hir_vec![call_move_val_init],
-                                               call,
-                                               e.span,
-                                               hir::PushUnsafeBlock(hir::CompilerGenerated),
-                                               ThinVec::new())
+                        P(self.signal_block_expr(hir_vec![call_move_val_init],
+                                                 call,
+                                                 e.span,
+                                                 hir::PushUnsafeBlock(hir::CompilerGenerated),
+                                                 ThinVec::new()))
                     };
 
                     return self.signal_block_expr(hir_vec![s1, s2, s3],
@@ -1065,15 +1065,15 @@ fn lower_expr(&mut self, e: &Expr) -> P<hir::Expr> {
                     hir::ExprArray(exprs.iter().map(|x| self.lower_expr(x)).collect())
                 }
                 ExprKind::Repeat(ref expr, ref count) => {
-                    let expr = self.lower_expr(expr);
-                    let count = self.lower_expr(count);
+                    let expr = P(self.lower_expr(expr));
+                    let count = P(self.lower_expr(count));
                     hir::ExprRepeat(expr, count)
                 }
                 ExprKind::Tup(ref elts) => {
                     hir::ExprTup(elts.iter().map(|x| self.lower_expr(x)).collect())
                 }
                 ExprKind::Call(ref f, ref args) => {
-                    let f = self.lower_expr(f);
+                    let f = P(self.lower_expr(f));
                     hir::ExprCall(f, args.iter().map(|x| self.lower_expr(x)).collect())
                 }
                 ExprKind::MethodCall(i, ref tps, ref args) => {
@@ -1083,27 +1083,27 @@ fn lower_expr(&mut self, e: &Expr) -> P<hir::Expr> {
                 }
                 ExprKind::Binary(binop, ref lhs, ref rhs) => {
                     let binop = self.lower_binop(binop);
-                    let lhs = self.lower_expr(lhs);
-                    let rhs = self.lower_expr(rhs);
+                    let lhs = P(self.lower_expr(lhs));
+                    let rhs = P(self.lower_expr(rhs));
                     hir::ExprBinary(binop, lhs, rhs)
                 }
                 ExprKind::Unary(op, ref ohs) => {
                     let op = self.lower_unop(op);
-                    let ohs = self.lower_expr(ohs);
+                    let ohs = P(self.lower_expr(ohs));
                     hir::ExprUnary(op, ohs)
                 }
                 ExprKind::Lit(ref l) => hir::ExprLit(P((**l).clone())),
                 ExprKind::Cast(ref expr, ref ty) => {
-                    let expr = self.lower_expr(expr);
+                    let expr = P(self.lower_expr(expr));
                     hir::ExprCast(expr, self.lower_ty(ty))
                 }
                 ExprKind::Type(ref expr, ref ty) => {
-                    let expr = self.lower_expr(expr);
+                    let expr = P(self.lower_expr(expr));
                     hir::ExprType(expr, self.lower_ty(ty))
                 }
                 ExprKind::AddrOf(m, ref ohs) => {
                     let m = self.lower_mutability(m);
-                    let ohs = self.lower_expr(ohs);
+                    let ohs = P(self.lower_expr(ohs));
                     hir::ExprAddrOf(m, ohs)
                 }
                 // More complicated than you might expect because the else branch
@@ -1114,7 +1114,7 @@ fn lower_expr(&mut self, e: &Expr) -> P<hir::Expr> {
                             ExprKind::IfLet(..) => {
                                 // wrap the if-let expr in a block
                                 let span = els.span;
-                                let els = self.lower_expr(els);
+                                let els = P(self.lower_expr(els));
                                 let id = self.next_id();
                                 let blk = P(hir::Block {
                                     stmts: hir_vec![],
@@ -1123,23 +1123,25 @@ fn lower_expr(&mut self, e: &Expr) -> P<hir::Expr> {
                                     rules: hir::DefaultBlock,
                                     span: span,
                                 });
-                                self.expr_block(blk, ThinVec::new())
+                                P(self.expr_block(blk, ThinVec::new()))
                             }
-                            _ => self.lower_expr(els),
+                            _ => P(self.lower_expr(els)),
                         }
                     });
 
-                    hir::ExprIf(self.lower_expr(cond), self.lower_block(blk), else_opt)
+                    hir::ExprIf(P(self.lower_expr(cond)), self.lower_block(blk), else_opt)
                 }
                 ExprKind::While(ref cond, ref body, opt_ident) => {
-                    hir::ExprWhile(self.lower_expr(cond), self.lower_block(body),
+                    hir::ExprWhile(P(self.lower_expr(cond)), self.lower_block(body),
                                    self.lower_opt_sp_ident(opt_ident))
                 }
                 ExprKind::Loop(ref body, opt_ident) => {
-                    hir::ExprLoop(self.lower_block(body), self.lower_opt_sp_ident(opt_ident))
+                    hir::ExprLoop(self.lower_block(body),
+                                  self.lower_opt_sp_ident(opt_ident),
+                                  hir::LoopSource::Loop)
                 }
                 ExprKind::Match(ref expr, ref arms) => {
-                    hir::ExprMatch(self.lower_expr(expr),
+                    hir::ExprMatch(P(self.lower_expr(expr)),
                                    arms.iter().map(|x| self.lower_arm(x)).collect(),
                                    hir::MatchSource::Normal)
                 }
@@ -1147,33 +1149,33 @@ fn lower_expr(&mut self, e: &Expr) -> P<hir::Expr> {
                     self.with_parent_def(e.id, |this| {
                         hir::ExprClosure(this.lower_capture_clause(capture_clause),
                                          this.lower_fn_decl(decl),
-                                         this.lower_expr(body),
+                                         P(this.lower_expr(body)),
                                          fn_decl_span)
                     })
                 }
                 ExprKind::Block(ref blk) => hir::ExprBlock(self.lower_block(blk)),
                 ExprKind::Assign(ref el, ref er) => {
-                    hir::ExprAssign(self.lower_expr(el), self.lower_expr(er))
+                    hir::ExprAssign(P(self.lower_expr(el)), P(self.lower_expr(er)))
                 }
                 ExprKind::AssignOp(op, ref el, ref er) => {
                     hir::ExprAssignOp(self.lower_binop(op),
-                                      self.lower_expr(el),
-                                      self.lower_expr(er))
+                                      P(self.lower_expr(el)),
+                                      P(self.lower_expr(er)))
                 }
                 ExprKind::Field(ref el, ident) => {
-                    hir::ExprField(self.lower_expr(el), respan(ident.span, ident.node.name))
+                    hir::ExprField(P(self.lower_expr(el)), respan(ident.span, ident.node.name))
                 }
                 ExprKind::TupField(ref el, ident) => {
-                    hir::ExprTupField(self.lower_expr(el), ident)
+                    hir::ExprTupField(P(self.lower_expr(el)), ident)
                 }
                 ExprKind::Index(ref el, ref er) => {
-                    hir::ExprIndex(self.lower_expr(el), self.lower_expr(er))
+                    hir::ExprIndex(P(self.lower_expr(el)), P(self.lower_expr(er)))
                 }
                 ExprKind::Range(ref e1, ref e2, lims) => {
                     fn make_struct(this: &mut LoweringContext,
                                    ast_expr: &Expr,
                                    path: &[&str],
-                                   fields: &[(&str, &P<Expr>)]) -> P<hir::Expr> {
+                                   fields: &[(&str, &P<Expr>)]) -> hir::Expr {
                         let struct_path = this.std_path(ast_expr.span,
                                                         &iter::once(&"ops").chain(path)
                                                                            .map(|s| *s)
@@ -1183,12 +1185,12 @@ fn make_struct(this: &mut LoweringContext,
                             this.expr_path(struct_path, ast_expr.attrs.clone())
                         } else {
                             let fields = fields.into_iter().map(|&(s, e)| {
-                                let expr = this.lower_expr(&e);
-                                let signal_block = this.signal_block_expr(hir_vec![],
-                                                                          expr,
-                                                                          e.span,
-                                                                          hir::PopUnstableBlock,
-                                                                          ThinVec::new());
+                                let expr = P(this.lower_expr(&e));
+                                let signal_block = P(this.signal_block_expr(hir_vec![],
+                                                                            expr,
+                                                                            e.span,
+                                                                            hir::PopUnstableBlock,
+                                                                            ThinVec::new()));
                                 this.field(Symbol::intern(s), signal_block, ast_expr.span)
                             }).collect();
                             let attrs = ast_expr.attrs.clone();
@@ -1242,9 +1244,12 @@ fn make_struct(this: &mut LoweringContext,
                     });
                     hir::ExprPath(hir_qself, self.lower_path(path))
                 }
-                ExprKind::Break(opt_ident) => hir::ExprBreak(self.lower_opt_sp_ident(opt_ident)),
+                ExprKind::Break(opt_ident, ref opt_expr) => {
+                    hir::ExprBreak(self.lower_opt_sp_ident(opt_ident),
+                                   opt_expr.as_ref().map(|x| P(self.lower_expr(x))))
+                }
                 ExprKind::Continue(opt_ident) => hir::ExprAgain(self.lower_opt_sp_ident(opt_ident)),
-                ExprKind::Ret(ref e) => hir::ExprRet(e.as_ref().map(|x| self.lower_expr(x))),
+                ExprKind::Ret(ref e) => hir::ExprRet(e.as_ref().map(|x| P(self.lower_expr(x)))),
                 ExprKind::InlineAsm(ref asm) => {
                     let hir_asm = hir::InlineAsm {
                         inputs: asm.inputs.iter().map(|&(ref c, _)| c.clone()).collect(),
@@ -1272,20 +1277,19 @@ fn make_struct(this: &mut LoweringContext,
                 ExprKind::Struct(ref path, ref fields, ref maybe_expr) => {
                     hir::ExprStruct(P(self.lower_path(path)),
                                     fields.iter().map(|x| self.lower_field(x)).collect(),
-                                    maybe_expr.as_ref().map(|x| self.lower_expr(x)))
+                                    maybe_expr.as_ref().map(|x| P(self.lower_expr(x))))
                 }
                 ExprKind::Paren(ref ex) => {
-                    return self.lower_expr(ex).map(|mut ex| {
-                        // include parens in span, but only if it is a super-span.
-                        if e.span.contains(ex.span) {
-                            ex.span = e.span;
-                        }
-                        // merge attributes into the inner expression.
-                        let mut attrs = e.attrs.clone();
-                        attrs.extend::<Vec<_>>(ex.attrs.into());
-                        ex.attrs = attrs;
-                        ex
-                    });
+                    let mut ex = self.lower_expr(ex);
+                    // include parens in span, but only if it is a super-span.
+                    if e.span.contains(ex.span) {
+                        ex.span = e.span;
+                    }
+                    // merge attributes into the inner expression.
+                    let mut attrs = e.attrs.clone();
+                    attrs.extend::<Vec<_>>(ex.attrs.into());
+                    ex.attrs = attrs;
+                    return ex;
                 }
 
                 // Desugar ExprIfLet
@@ -1302,13 +1306,13 @@ fn make_struct(this: &mut LoweringContext,
                     // `<pat> => <body>`
                     let pat_arm = {
                         let body = self.lower_block(body);
-                        let body_expr = self.expr_block(body, ThinVec::new());
+                        let body_expr = P(self.expr_block(body, ThinVec::new()));
                         let pat = self.lower_pat(pat);
                         self.arm(hir_vec![pat], body_expr)
                     };
 
                     // `[_ if <else_opt_if_cond> => <else_opt_if_body>,]`
-                    let mut else_opt = else_opt.as_ref().map(|e| self.lower_expr(e));
+                    let mut else_opt = else_opt.as_ref().map(|e| P(self.lower_expr(e)));
                     let else_if_arms = {
                         let mut arms = vec![];
                         loop {
@@ -1322,7 +1326,7 @@ fn make_struct(this: &mut LoweringContext,
                                                 attrs: hir_vec![],
                                                 pats: hir_vec![pat_under],
                                                 guard: Some(cond),
-                                                body: self.expr_block(then, ThinVec::new()),
+                                                body: P(self.expr_block(then, ThinVec::new())),
                                             });
                                             else_opt.map(|else_opt| (else_opt, true))
                                         }
@@ -1362,7 +1366,7 @@ fn make_struct(this: &mut LoweringContext,
                     arms.extend(else_if_arms);
                     arms.push(else_arm);
 
-                    let sub_expr = self.lower_expr(sub_expr);
+                    let sub_expr = P(self.lower_expr(sub_expr));
                     // add attributes to the outer returned expr node
                     return self.expr(e.span,
                                      hir::ExprMatch(sub_expr,
@@ -1388,7 +1392,7 @@ fn make_struct(this: &mut LoweringContext,
                     // `<pat> => <body>`
                     let pat_arm = {
                         let body = self.lower_block(body);
-                        let body_expr = self.expr_block(body, ThinVec::new());
+                        let body_expr = P(self.expr_block(body, ThinVec::new()));
                         let pat = self.lower_pat(pat);
                         self.arm(hir_vec![pat], body_expr)
                     };
@@ -1402,7 +1406,7 @@ fn make_struct(this: &mut LoweringContext,
 
                     // `match <sub_expr> { ... }`
                     let arms = hir_vec![pat_arm, break_arm];
-                    let sub_expr = self.lower_expr(sub_expr);
+                    let sub_expr = P(self.lower_expr(sub_expr));
                     let match_expr = self.expr(e.span,
                                                hir::ExprMatch(sub_expr,
                                                               arms,
@@ -1410,11 +1414,12 @@ fn make_struct(this: &mut LoweringContext,
                                                ThinVec::new());
 
                     // `[opt_ident]: loop { ... }`
-                    let loop_block = self.block_expr(match_expr);
-                    let loop_expr = hir::ExprLoop(loop_block, self.lower_opt_sp_ident(opt_ident));
+                    let loop_block = P(self.block_expr(P(match_expr)));
+                    let loop_expr = hir::ExprLoop(loop_block, self.lower_opt_sp_ident(opt_ident),
+                                                  hir::LoopSource::WhileLet);
                     // add attributes to the outer returned expr node
                     let attrs = e.attrs.clone();
-                    return P(hir::Expr { id: e.id, node: loop_expr, span: e.span, attrs: attrs });
+                    return hir::Expr { id: e.id, node: loop_expr, span: e.span, attrs: attrs };
                 }
 
                 // Desugar ExprForLoop
@@ -1471,20 +1476,23 @@ fn make_struct(this: &mut LoweringContext,
                     // `match ::std::iter::Iterator::next(&mut iter) { ... }`
                     let match_expr = {
                         let next_path = self.std_path(e.span, &["iter", "Iterator", "next"]);
-                        let iter = self.expr_ident(e.span, iter, iter_pat.id);
+                        let iter = P(self.expr_ident(e.span, iter, iter_pat.id));
                         let ref_mut_iter = self.expr_mut_addr_of(e.span, iter);
                         let next_path = self.expr_path(next_path, ThinVec::new());
-                        let next_expr = self.expr_call(e.span, next_path, hir_vec![ref_mut_iter]);
+                        let next_expr = P(self.expr_call(e.span, next_path,
+                                          hir_vec![ref_mut_iter]));
                         let arms = hir_vec![pat_arm, break_arm];
 
-                        self.expr(e.span,
-                                  hir::ExprMatch(next_expr, arms, hir::MatchSource::ForLoopDesugar),
-                                  ThinVec::new())
+                        P(self.expr(e.span,
+                                    hir::ExprMatch(next_expr, arms,
+                                                   hir::MatchSource::ForLoopDesugar),
+                                    ThinVec::new()))
                     };
 
                     // `[opt_ident]: loop { ... }`
-                    let loop_block = self.block_expr(match_expr);
-                    let loop_expr = hir::ExprLoop(loop_block, self.lower_opt_sp_ident(opt_ident));
+                    let loop_block = P(self.block_expr(match_expr));
+                    let loop_expr = hir::ExprLoop(loop_block, self.lower_opt_sp_ident(opt_ident),
+                                                  hir::LoopSource::ForLoop);
                     let loop_expr = P(hir::Expr {
                         id: e.id,
                         node: loop_expr,
@@ -1501,13 +1509,13 @@ fn make_struct(this: &mut LoweringContext,
                                                            &["iter", "IntoIterator", "into_iter"]);
 
                         let into_iter = self.expr_path(into_iter_path, ThinVec::new());
-                        self.expr_call(e.span, into_iter, hir_vec![head])
+                        P(self.expr_call(e.span, into_iter, hir_vec![head]))
                     };
 
-                    let match_expr = self.expr_match(e.span,
-                                                     into_iter_expr,
-                                                     hir_vec![iter_arm],
-                                                     hir::MatchSource::ForLoopDesugar);
+                    let match_expr = P(self.expr_match(e.span,
+                                                       into_iter_expr,
+                                                       hir_vec![iter_arm],
+                                                       hir::MatchSource::ForLoopDesugar));
 
                     // `{ let _result = ...; _result }`
                     // underscore prevents an unused_variables lint if the head diverges
@@ -1515,8 +1523,8 @@ fn make_struct(this: &mut LoweringContext,
                     let (let_stmt, let_stmt_binding) =
                         self.stmt_let(e.span, false, result_ident, match_expr);
 
-                    let result = self.expr_ident(e.span, result_ident, let_stmt_binding);
-                    let block = self.block_all(e.span, hir_vec![let_stmt], Some(result));
+                    let result = P(self.expr_ident(e.span, result_ident, let_stmt_binding));
+                    let block = P(self.block_all(e.span, hir_vec![let_stmt], Some(result)));
                     // add the attributes to the outer returned expr node
                     return self.expr_block(block, e.attrs.clone());
                 }
@@ -1536,7 +1544,7 @@ fn make_struct(this: &mut LoweringContext,
                     // { Carrier::translate( { <expr> } ) }
                     let discr = {
                         // expand <expr>
-                        let sub_expr = self.lower_expr(sub_expr);
+                        let sub_expr = P(self.lower_expr(sub_expr));
                         let sub_expr = self.signal_block_expr(hir_vec![],
                                                               sub_expr,
                                                               e.span,
@@ -1545,20 +1553,20 @@ fn make_struct(this: &mut LoweringContext,
 
                         let path = self.std_path(e.span, &["ops", "Carrier", "translate"]);
                         let path = self.expr_path(path, ThinVec::new());
-                        let call = self.expr_call(e.span, path, hir_vec![sub_expr]);
+                        let call = P(self.expr_call(e.span, path, hir_vec![sub_expr]));
 
-                        self.signal_block_expr(hir_vec![],
-                                               call,
-                                               e.span,
-                                               hir::PushUnstableBlock,
-                                               ThinVec::new())
+                        P(self.signal_block_expr(hir_vec![],
+                                                 call,
+                                                 e.span,
+                                                 hir::PushUnstableBlock,
+                                                 ThinVec::new()))
                     };
 
                     // Ok(val) => val
                     let ok_arm = {
                         let val_ident = self.str_to_ident("val");
                         let val_pat = self.pat_ident(e.span, val_ident);
-                        let val_expr = self.expr_ident(e.span, val_ident, val_pat.id);
+                        let val_expr = P(self.expr_ident(e.span, val_ident, val_pat.id));
                         let ok_pat = self.pat_ok(e.span, val_pat);
 
                         self.arm(hir_vec![ok_pat], val_expr)
@@ -1578,15 +1586,16 @@ fn make_struct(this: &mut LoweringContext,
                         let from_err_expr = {
                             let path = self.std_path(e.span, &["ops", "Carrier", "from_error"]);
                             let from_err = self.expr_path(path, ThinVec::new());
-                            self.expr_call(e.span, from_err, hir_vec![from_expr])
+                            P(self.expr_call(e.span, from_err, hir_vec![from_expr]))
                         };
 
-                        let ret_expr = self.expr(e.span,
-                                                 hir::Expr_::ExprRet(Some(from_err_expr)),
-                                                                     ThinVec::new());
+                        let ret_expr = P(self.expr(e.span,
+                                                   hir::Expr_::ExprRet(Some(from_err_expr)),
+                                                                       ThinVec::new()));
                         let ret_stmt = self.stmt_expr(ret_expr);
-                        let block = self.signal_block_stmt(ret_stmt, e.span,
-                                                           hir::PushUnstableBlock, ThinVec::new());
+                        let block = P(self.signal_block_stmt(ret_stmt, e.span,
+                                                             hir::PushUnstableBlock,
+                                                             ThinVec::new()));
 
                         let err_pat = self.pat_err(e.span, err_local);
                         self.arm(hir_vec![err_pat], block)
@@ -1600,7 +1609,7 @@ fn make_struct(this: &mut LoweringContext,
             },
             span: e.span,
             attrs: e.attrs.clone(),
-        })
+        }
     }
 
     fn lower_stmt(&mut self, s: &Stmt) -> hir::Stmt {
@@ -1621,13 +1630,13 @@ fn lower_stmt(&mut self, s: &Stmt) -> hir::Stmt {
             },
             StmtKind::Expr(ref e) => {
                 Spanned {
-                    node: hir::StmtExpr(self.lower_expr(e), s.id),
+                    node: hir::StmtExpr(P(self.lower_expr(e)), s.id),
                     span: s.span,
                 }
             }
             StmtKind::Semi(ref e) => {
                 Spanned {
-                    node: hir::StmtSemi(self.lower_expr(e), s.id),
+                    node: hir::StmtSemi(P(self.lower_expr(e)), s.id),
                     span: s.span,
                 }
             }
@@ -1721,15 +1730,15 @@ fn field(&mut self, name: Name, expr: P<hir::Expr>, span: Span) -> hir::Field {
     }
 
     fn expr_break(&mut self, span: Span, attrs: ThinVec<Attribute>) -> P<hir::Expr> {
-        self.expr(span, hir::ExprBreak(None), attrs)
+        P(self.expr(span, hir::ExprBreak(None, None), attrs))
     }
 
-    fn expr_call(&mut self, span: Span, e: P<hir::Expr>, args: hir::HirVec<P<hir::Expr>>)
-                 -> P<hir::Expr> {
+    fn expr_call(&mut self, span: Span, e: P<hir::Expr>, args: hir::HirVec<hir::Expr>)
+                 -> hir::Expr {
         self.expr(span, hir::ExprCall(e, args), ThinVec::new())
     }
 
-    fn expr_ident(&mut self, span: Span, id: Name, binding: NodeId) -> P<hir::Expr> {
+    fn expr_ident(&mut self, span: Span, id: Name, binding: NodeId) -> hir::Expr {
         let expr_path = hir::ExprPath(None, self.path_ident(span, id));
         let expr = self.expr(span, expr_path, ThinVec::new());
 
@@ -1742,13 +1751,13 @@ fn expr_ident(&mut self, span: Span, id: Name, binding: NodeId) -> P<hir::Expr>
         expr
     }
 
-    fn expr_mut_addr_of(&mut self, span: Span, e: P<hir::Expr>) -> P<hir::Expr> {
+    fn expr_mut_addr_of(&mut self, span: Span, e: P<hir::Expr>) -> hir::Expr {
         self.expr(span, hir::ExprAddrOf(hir::MutMutable, e), ThinVec::new())
     }
 
     fn expr_path(&mut self, path: hir::Path, attrs: ThinVec<Attribute>) -> P<hir::Expr> {
         let def = self.resolver.resolve_generated_global_path(&path, true);
-        let expr = self.expr(path.span, hir::ExprPath(None, path), attrs);
+        let expr = P(self.expr(path.span, hir::ExprPath(None, path), attrs));
         self.resolver.record_resolution(expr.id, def);
         expr
     }
@@ -1758,16 +1767,16 @@ fn expr_match(&mut self,
                   arg: P<hir::Expr>,
                   arms: hir::HirVec<hir::Arm>,
                   source: hir::MatchSource)
-                  -> P<hir::Expr> {
+                  -> hir::Expr {
         self.expr(span, hir::ExprMatch(arg, arms, source), ThinVec::new())
     }
 
-    fn expr_block(&mut self, b: P<hir::Block>, attrs: ThinVec<Attribute>) -> P<hir::Expr> {
+    fn expr_block(&mut self, b: P<hir::Block>, attrs: ThinVec<Attribute>) -> hir::Expr {
         self.expr(b.span, hir::ExprBlock(b), attrs)
     }
 
-    fn expr_tuple(&mut self, sp: Span, exprs: hir::HirVec<P<hir::Expr>>) -> P<hir::Expr> {
-        self.expr(sp, hir::ExprTup(exprs), ThinVec::new())
+    fn expr_tuple(&mut self, sp: Span, exprs: hir::HirVec<hir::Expr>) -> P<hir::Expr> {
+        P(self.expr(sp, hir::ExprTup(exprs), ThinVec::new()))
     }
 
     fn expr_struct(&mut self,
@@ -1777,18 +1786,18 @@ fn expr_struct(&mut self,
                    e: Option<P<hir::Expr>>,
                    attrs: ThinVec<Attribute>) -> P<hir::Expr> {
         let def = self.resolver.resolve_generated_global_path(&path, false);
-        let expr = self.expr(sp, hir::ExprStruct(P(path), fields, e), attrs);
+        let expr = P(self.expr(sp, hir::ExprStruct(P(path), fields, e), attrs));
         self.resolver.record_resolution(expr.id, def);
         expr
     }
 
-    fn expr(&mut self, span: Span, node: hir::Expr_, attrs: ThinVec<Attribute>) -> P<hir::Expr> {
-        P(hir::Expr {
+    fn expr(&mut self, span: Span, node: hir::Expr_, attrs: ThinVec<Attribute>) -> hir::Expr {
+        hir::Expr {
             id: self.next_id(),
             node: node,
             span: span,
             attrs: attrs,
-        })
+        }
     }
 
     fn stmt_let(&mut self, sp: Span, mutbl: bool, ident: Name, ex: P<hir::Expr>)
@@ -1820,19 +1829,19 @@ fn stmt_expr(&self, expr: P<hir::Expr>) -> hir::Stmt {
         }
     }
 
-    fn block_expr(&mut self, expr: P<hir::Expr>) -> P<hir::Block> {
+    fn block_expr(&mut self, expr: P<hir::Expr>) -> hir::Block {
         self.block_all(expr.span, hir::HirVec::new(), Some(expr))
     }
 
     fn block_all(&mut self, span: Span, stmts: hir::HirVec<hir::Stmt>, expr: Option<P<hir::Expr>>)
-                 -> P<hir::Block> {
-        P(hir::Block {
+                 -> hir::Block {
+        hir::Block {
             stmts: stmts,
             expr: expr,
             id: self.next_id(),
             rules: hir::DefaultBlock,
             span: span,
-        })
+        }
     }
 
     fn pat_ok(&mut self, span: Span, pat: P<hir::Pat>) -> P<hir::Pat> {
@@ -1972,7 +1981,7 @@ fn signal_block_expr(&mut self,
                          span: Span,
                          rule: hir::BlockCheckMode,
                          attrs: ThinVec<Attribute>)
-                         -> P<hir::Expr> {
+                         -> hir::Expr {
         let id = self.next_id();
         let block = P(hir::Block {
             rules: rule,
@@ -1989,7 +1998,7 @@ fn signal_block_stmt(&mut self,
                          span: Span,
                          rule: hir::BlockCheckMode,
                          attrs: ThinVec<Attribute>)
-                         -> P<hir::Expr> {
+                         -> hir::Expr {
         let id = self.next_id();
         let block = P(hir::Block {
             rules: rule,
index b5f892f0ff7ace30a831ece6e506eb33fa001a65..31648765224254796ca75be5e292b5035ac9470b 100644 (file)
@@ -867,12 +867,12 @@ pub enum Expr_ {
     /// A `box x` expression.
     ExprBox(P<Expr>),
     /// An array (`[a, b, c, d]`)
-    ExprArray(HirVec<P<Expr>>),
+    ExprArray(HirVec<Expr>),
     /// A function call
     ///
     /// The first field resolves to the function itself (usually an `ExprPath`),
     /// and the second field is the list of arguments
-    ExprCall(P<Expr>, HirVec<P<Expr>>),
+    ExprCall(P<Expr>, HirVec<Expr>),
     /// A method call (`x.foo::<Bar, Baz>(a, b, c, d)`)
     ///
     /// The `Spanned<Name>` is the identifier for the method name.
@@ -885,9 +885,9 @@ pub enum Expr_ {
     ///
     /// Thus, `x.foo::<Bar, Baz>(a, b, c, d)` is represented as
     /// `ExprMethodCall(foo, [Bar, Baz], [x, a, b, c, d])`.
-    ExprMethodCall(Spanned<Name>, HirVec<P<Ty>>, HirVec<P<Expr>>),
+    ExprMethodCall(Spanned<Name>, HirVec<P<Ty>>, HirVec<Expr>),
     /// A tuple (`(a, b, c ,d)`)
-    ExprTup(HirVec<P<Expr>>),
+    ExprTup(HirVec<Expr>),
     /// A binary operation (For example: `a + b`, `a * b`)
     ExprBinary(BinOp, P<Expr>, P<Expr>),
     /// A unary operation (For example: `!x`, `*x`)
@@ -908,7 +908,7 @@ pub enum Expr_ {
     /// Conditionless loop (can be exited with break, continue, or return)
     ///
     /// `'label: loop { block }`
-    ExprLoop(P<Block>, Option<Spanned<Name>>),
+    ExprLoop(P<Block>, Option<Spanned<Name>>, LoopSource),
     /// A `match` block, with a source that indicates whether or not it is
     /// the result of a desugaring, and if so, which kind.
     ExprMatch(P<Expr>, HirVec<Arm>, MatchSource),
@@ -944,14 +944,14 @@ pub enum Expr_ {
     /// A referencing operation (`&a` or `&mut a`)
     ExprAddrOf(Mutability, P<Expr>),
     /// A `break`, with an optional label to break
-    ExprBreak(Option<Spanned<Name>>),
+    ExprBreak(Option<Spanned<Name>>, Option<P<Expr>>),
     /// A `continue`, with an optional label
     ExprAgain(Option<Spanned<Name>>),
     /// A `return`, with an optional value to be returned
     ExprRet(Option<P<Expr>>),
 
     /// Inline assembly (from `asm!`), with its outputs and inputs.
-    ExprInlineAsm(P<InlineAsm>, HirVec<P<Expr>>, HirVec<P<Expr>>),
+    ExprInlineAsm(P<InlineAsm>, HirVec<Expr>, HirVec<Expr>),
 
     /// A struct or struct-like variant literal expression.
     ///
@@ -1002,6 +1002,18 @@ pub enum MatchSource {
     TryDesugar,
 }
 
+/// The loop type that yielded an ExprLoop
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
+pub enum LoopSource {
+    /// A `loop { .. }` loop
+    Loop,
+    /// A `while let _ = _ { .. }` loop
+    WhileLet,
+    /// A `for _ in _ { .. }` loop
+    ForLoop,
+}
+
+
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
 pub enum CaptureClause {
     CaptureByValue,
index b9d1d7e4efbb986a91e3348c06fa13f760287f14..c109e84bf6186a65ee7b224d962e5d3b982b6a31 100644 (file)
@@ -452,7 +452,7 @@ pub fn commasep_cmnt<T, F, G>(&mut self,
         self.end()
     }
 
-    pub fn commasep_exprs(&mut self, b: Breaks, exprs: &[P<hir::Expr>]) -> io::Result<()> {
+    pub fn commasep_exprs(&mut self, b: Breaks, exprs: &[hir::Expr]) -> io::Result<()> {
         self.commasep_cmnt(b, exprs, |s, e| s.print_expr(&e), |e| e.span)
     }
 
@@ -1200,7 +1200,7 @@ pub fn print_if_let(&mut self,
     }
 
 
-    fn print_call_post(&mut self, args: &[P<hir::Expr>]) -> io::Result<()> {
+    fn print_call_post(&mut self, args: &[hir::Expr]) -> io::Result<()> {
         self.popen()?;
         self.commasep_exprs(Inconsistent, args)?;
         self.pclose()
@@ -1218,10 +1218,10 @@ pub fn print_expr_maybe_paren(&mut self, expr: &hir::Expr) -> io::Result<()> {
         Ok(())
     }
 
-    fn print_expr_vec(&mut self, exprs: &[P<hir::Expr>]) -> io::Result<()> {
+    fn print_expr_vec(&mut self, exprs: &[hir::Expr]) -> io::Result<()> {
         self.ibox(indent_unit)?;
         word(&mut self.s, "[")?;
-        self.commasep_exprs(Inconsistent, &exprs[..])?;
+        self.commasep_exprs(Inconsistent, exprs)?;
         word(&mut self.s, "]")?;
         self.end()
     }
@@ -1274,16 +1274,16 @@ fn print_expr_struct(&mut self,
         Ok(())
     }
 
-    fn print_expr_tup(&mut self, exprs: &[P<hir::Expr>]) -> io::Result<()> {
+    fn print_expr_tup(&mut self, exprs: &[hir::Expr]) -> io::Result<()> {
         self.popen()?;
-        self.commasep_exprs(Inconsistent, &exprs[..])?;
+        self.commasep_exprs(Inconsistent, exprs)?;
         if exprs.len() == 1 {
             word(&mut self.s, ",")?;
         }
         self.pclose()
     }
 
-    fn print_expr_call(&mut self, func: &hir::Expr, args: &[P<hir::Expr>]) -> io::Result<()> {
+    fn print_expr_call(&mut self, func: &hir::Expr, args: &[hir::Expr]) -> io::Result<()> {
         self.print_expr_maybe_paren(func)?;
         self.print_call_post(args)
     }
@@ -1291,7 +1291,7 @@ fn print_expr_call(&mut self, func: &hir::Expr, args: &[P<hir::Expr>]) -> io::Re
     fn print_expr_method_call(&mut self,
                               name: Spanned<ast::Name>,
                               tys: &[P<hir::Ty>],
-                              args: &[P<hir::Expr>])
+                              args: &[hir::Expr])
                               -> io::Result<()> {
         let base_args = &args[1..];
         self.print_expr(&args[0])?;
@@ -1340,7 +1340,7 @@ pub fn print_expr(&mut self, expr: &hir::Expr) -> io::Result<()> {
                 self.print_expr(expr)?;
             }
             hir::ExprArray(ref exprs) => {
-                self.print_expr_vec(&exprs[..])?;
+                self.print_expr_vec(exprs)?;
             }
             hir::ExprRepeat(ref element, ref count) => {
                 self.print_expr_repeat(&element, &count)?;
@@ -1349,13 +1349,13 @@ pub fn print_expr(&mut self, expr: &hir::Expr) -> io::Result<()> {
                 self.print_expr_struct(path, &fields[..], wth)?;
             }
             hir::ExprTup(ref exprs) => {
-                self.print_expr_tup(&exprs[..])?;
+                self.print_expr_tup(exprs)?;
             }
             hir::ExprCall(ref func, ref args) => {
-                self.print_expr_call(&func, &args[..])?;
+                self.print_expr_call(&func, args)?;
             }
             hir::ExprMethodCall(name, ref tys, ref args) => {
-                self.print_expr_method_call(name, &tys[..], &args[..])?;
+                self.print_expr_method_call(name, &tys[..], args)?;
             }
             hir::ExprBinary(op, ref lhs, ref rhs) => {
                 self.print_expr_binary(op, &lhs, &rhs)?;
@@ -1393,7 +1393,7 @@ pub fn print_expr(&mut self, expr: &hir::Expr) -> io::Result<()> {
                 space(&mut self.s)?;
                 self.print_block(&blk)?;
             }
-            hir::ExprLoop(ref blk, opt_sp_name) => {
+            hir::ExprLoop(ref blk, opt_sp_name, _) => {
                 if let Some(sp_name) = opt_sp_name {
                     self.print_name(sp_name.node)?;
                     self.word_space(":")?;
@@ -1471,13 +1471,17 @@ pub fn print_expr(&mut self, expr: &hir::Expr) -> io::Result<()> {
             hir::ExprPath(Some(ref qself), ref path) => {
                 self.print_qpath(path, qself, true)?
             }
-            hir::ExprBreak(opt_name) => {
+            hir::ExprBreak(opt_name, ref opt_expr) => {
                 word(&mut self.s, "break")?;
                 space(&mut self.s)?;
                 if let Some(name) = opt_name {
                     self.print_name(name.node)?;
                     space(&mut self.s)?;
                 }
+                if let Some(ref expr) = *opt_expr {
+                    self.print_expr(expr)?;
+                    space(&mut self.s)?;
+                }
             }
             hir::ExprAgain(opt_name) => {
                 word(&mut self.s, "continue")?;
index 82a46f76401d52a2a559bc6edd0fce550069009a..96aee04b6b7ab826f172d3d390378e52992b9d82 100644 (file)
 
 declare_lint! {
     pub HR_LIFETIME_IN_ASSOC_TYPE,
-    Warn,
+    Deny,
     "binding for associated type references higher-ranked lifetime \
      that does not appear in the trait input types"
 }
     "detects extra requirements in impls that were erroneously allowed"
 }
 
+declare_lint! {
+    pub LEGACY_DIRECTORY_OWNERSHIP,
+    Warn,
+    "non-inline, non-`#[path]` modules (e.g. `mod foo;`) were erroneously allowed in some files \
+     not named `mod.rs`"
+}
+
 /// Does nothing as a lint pass, but registers some `Lint`s
 /// which are used by other parts of the compiler.
 #[derive(Copy, Clone)]
@@ -242,7 +249,8 @@ fn get_lints(&self) -> LintArray {
             LIFETIME_UNDERSCORE,
             SAFE_EXTERN_STATICS,
             PATTERNS_IN_FNS_WITHOUT_BODY,
-            EXTRA_REQUIREMENT_IN_IMPL
+            EXTRA_REQUIREMENT_IN_IMPL,
+            LEGACY_DIRECTORY_OWNERSHIP
         )
     }
 }
index 168aba774333e99c1cf0af4284efe91f49f9f104..a7f28dd6d58c4009711d14d1cefdafc1b47761ef 100644 (file)
@@ -56,12 +56,13 @@ pub struct LinkMeta {
     pub crate_hash: Svh,
 }
 
-// Where a crate came from on the local filesystem. One of these two options
+// Where a crate came from on the local filesystem. One of these three options
 // must be non-None.
 #[derive(PartialEq, Clone, Debug)]
 pub struct CrateSource {
     pub dylib: Option<(PathBuf, PathKind)>,
     pub rlib: Option<(PathBuf, PathKind)>,
+    pub rmeta: Option<(PathBuf, PathKind)>,
 }
 
 #[derive(RustcEncodable, RustcDecodable, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Debug)]
@@ -76,6 +77,30 @@ pub enum DepKind {
     Explicit,
 }
 
+#[derive(PartialEq, Clone, Debug)]
+pub enum LibSource {
+    Some(PathBuf),
+    MetadataOnly,
+    None,
+}
+
+impl LibSource {
+    pub fn is_some(&self) -> bool {
+        if let LibSource::Some(_) = *self {
+            true
+        } else {
+            false
+        }
+    }
+
+    pub fn option(&self) -> Option<PathBuf> {
+        match *self {
+            LibSource::Some(ref p) => Some(p.clone()),
+            LibSource::MetadataOnly | LibSource::None => None,
+        }
+    }
+}
+
 #[derive(Copy, Debug, PartialEq, Clone, RustcEncodable, RustcDecodable)]
 pub enum LinkagePreference {
     RequireDynamic,
@@ -244,7 +269,7 @@ fn maybe_get_item_ast<'a>(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
     // utility functions
     fn metadata_filename(&self) -> &str;
     fn metadata_section_name(&self, target: &Target) -> &str;
-    fn used_crates(&self, prefer: LinkagePreference) -> Vec<(CrateNum, Option<PathBuf>)>;
+    fn used_crates(&self, prefer: LinkagePreference) -> Vec<(CrateNum, LibSource)>;
     fn used_crate_source(&self, cnum: CrateNum) -> CrateSource;
     fn extern_mod_stmt_cnum(&self, emod_id: ast::NodeId) -> Option<CrateNum>;
     fn encode_metadata<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
@@ -427,7 +452,7 @@ fn used_link_args(&self) -> Vec<String> { vec![] }
     // utility functions
     fn metadata_filename(&self) -> &str { bug!("metadata_filename") }
     fn metadata_section_name(&self, target: &Target) -> &str { bug!("metadata_section_name") }
-    fn used_crates(&self, prefer: LinkagePreference) -> Vec<(CrateNum, Option<PathBuf>)>
+    fn used_crates(&self, prefer: LinkagePreference) -> Vec<(CrateNum, LibSource)>
         { vec![] }
     fn used_crate_source(&self, cnum: CrateNum) -> CrateSource { bug!("used_crate_source") }
     fn extern_mod_stmt_cnum(&self, emod_id: ast::NodeId) -> Option<CrateNum> { None }
index 92d1ab85c5a05afcf806eb14e7330c9d595b22a1..ee7f13f9e6e2266ddfafe6e0aa8b4dc629e6b560 100644 (file)
@@ -114,7 +114,7 @@ fn calculate_type(sess: &session::Session,
 
         // No linkage happens with rlibs, we just needed the metadata (which we
         // got long ago), so don't bother with anything.
-        config::CrateTypeRlib => return Vec::new(),
+        config::CrateTypeRlib | config::CrateTypeMetadata => return Vec::new(),
 
         // Staticlibs and cdylibs must have all static dependencies. If any fail
         // to be found, we generate some nice pretty errors.
@@ -192,7 +192,7 @@ fn calculate_type(sess: &session::Session,
         if src.dylib.is_none() &&
            !formats.contains_key(&cnum) &&
            sess.cstore.dep_kind(cnum) == DepKind::Explicit {
-            assert!(src.rlib.is_some());
+            assert!(src.rlib.is_some() || src.rmeta.is_some());
             info!("adding staticlib: {}", sess.cstore.crate_name(cnum));
             add_library(sess, cnum, RequireStatic, &mut formats);
             ret[cnum.as_usize() - 1] = Linkage::Static;
index 231da576f2b99d8f821a1d2aeed6480fac018a05..594ed408d8cd48efed2a73c9c87873d96f384e4c 100644 (file)
@@ -327,7 +327,7 @@ fn delegate_consume(&mut self,
         self.delegate.consume(consume_id, consume_span, cmt, mode);
     }
 
-    fn consume_exprs(&mut self, exprs: &[P<hir::Expr>]) {
+    fn consume_exprs(&mut self, exprs: &[hir::Expr]) {
         for expr in exprs {
             self.consume_expr(&expr);
         }
@@ -472,11 +472,10 @@ pub fn walk_expr(&mut self, expr: &hir::Expr) {
                 self.consume_exprs(inputs);
             }
 
-            hir::ExprBreak(..) |
             hir::ExprAgain(..) |
             hir::ExprLit(..) => {}
 
-            hir::ExprLoop(ref blk, _) => {
+            hir::ExprLoop(ref blk, _, _) => {
                 self.walk_block(&blk);
             }
 
@@ -514,7 +513,7 @@ pub fn walk_expr(&mut self, expr: &hir::Expr) {
                 self.walk_block(&blk);
             }
 
-            hir::ExprRet(ref opt_expr) => {
+            hir::ExprBreak(_, ref opt_expr) | hir::ExprRet(ref opt_expr) => {
                 if let Some(ref expr) = *opt_expr {
                     self.consume_expr(&expr);
                 }
index cf53fcf2dac86658b82a24721743fdd5d397e42b..4b1787ba593cbcae173ec7b63239e4293e3c2983 100644 (file)
 use std::io;
 use std::rc::Rc;
 use syntax::ast::{self, NodeId};
-use syntax::ptr::P;
 use syntax::symbol::keywords;
 use syntax_pos::Span;
 
@@ -491,7 +490,7 @@ fn visit_expr(ir: &mut IrMaps, expr: &Expr) {
       hir::ExprIndex(..) | hir::ExprField(..) | hir::ExprTupField(..) |
       hir::ExprArray(..) | hir::ExprCall(..) | hir::ExprMethodCall(..) |
       hir::ExprTup(..) | hir::ExprBinary(..) | hir::ExprAddrOf(..) |
-      hir::ExprCast(..) | hir::ExprUnary(..) | hir::ExprBreak(_) |
+      hir::ExprCast(..) | hir::ExprUnary(..) | hir::ExprBreak(..) |
       hir::ExprAgain(_) | hir::ExprLit(_) | hir::ExprRet(..) |
       hir::ExprBlock(..) | hir::ExprAssign(..) | hir::ExprAssignOp(..) |
       hir::ExprStruct(..) | hir::ExprRepeat(..) |
@@ -902,7 +901,7 @@ fn propagate_through_local(&mut self, local: &hir::Local, succ: LiveNode)
         self.define_bindings_in_pat(&local.pat, succ)
     }
 
-    fn propagate_through_exprs(&mut self, exprs: &[P<Expr>], succ: LiveNode)
+    fn propagate_through_exprs(&mut self, exprs: &[Expr], succ: LiveNode)
                                -> LiveNode {
         exprs.iter().rev().fold(succ, |succ, expr| {
             self.propagate_through_expr(&expr, succ)
@@ -991,7 +990,7 @@ fn propagate_through_expr(&mut self, expr: &Expr, succ: LiveNode)
 
           // Note that labels have been resolved, so we don't need to look
           // at the label ident
-          hir::ExprLoop(ref blk, _) => {
+          hir::ExprLoop(ref blk, _, _) => {
             self.propagate_through_loop(expr, LoopLoop, &blk, succ)
           }
 
@@ -1036,7 +1035,7 @@ fn propagate_through_expr(&mut self, expr: &Expr, succ: LiveNode)
             self.propagate_through_opt_expr(o_e.as_ref().map(|e| &**e), exit_ln)
           }
 
-          hir::ExprBreak(opt_label) => {
+          hir::ExprBreak(opt_label, ref opt_expr) => {
               // Find which label this break jumps to
               let sc = self.find_loop_scope(opt_label.map(|l| l.node), expr.id, expr.span);
 
@@ -1044,7 +1043,7 @@ fn propagate_through_expr(&mut self, expr: &Expr, succ: LiveNode)
               // look it up in the break loop nodes table
 
               match self.break_ln.get(&sc) {
-                  Some(&b) => b,
+                  Some(&b) => self.propagate_through_opt_expr(opt_expr.as_ref().map(|e| &**e), b),
                   None => span_bug!(expr.span, "break to unknown label")
               }
           }
@@ -1058,7 +1057,7 @@ fn propagate_through_expr(&mut self, expr: &Expr, succ: LiveNode)
 
               match self.cont_ln.get(&sc) {
                   Some(&b) => b,
-                  None => span_bug!(expr.span, "loop to unknown label")
+                  None => span_bug!(expr.span, "continue to unknown label")
               }
           }
 
@@ -1087,7 +1086,7 @@ fn propagate_through_expr(&mut self, expr: &Expr, succ: LiveNode)
           // Uninteresting cases: just propagate in rev exec order
 
           hir::ExprArray(ref exprs) => {
-            self.propagate_through_exprs(&exprs[..], succ)
+            self.propagate_through_exprs(exprs, succ)
           }
 
           hir::ExprRepeat(ref element, ref count) => {
@@ -1111,7 +1110,7 @@ fn propagate_through_expr(&mut self, expr: &Expr, succ: LiveNode)
             } else {
                 succ
             };
-            let succ = self.propagate_through_exprs(&args[..], succ);
+            let succ = self.propagate_through_exprs(args, succ);
             self.propagate_through_expr(&f, succ)
           }
 
@@ -1124,11 +1123,11 @@ fn propagate_through_expr(&mut self, expr: &Expr, succ: LiveNode)
             } else {
                 succ
             };
-            self.propagate_through_exprs(&args[..], succ)
+            self.propagate_through_exprs(args, succ)
           }
 
           hir::ExprTup(ref exprs) => {
-            self.propagate_through_exprs(&exprs[..], succ)
+            self.propagate_through_exprs(exprs, succ)
           }
 
           hir::ExprBinary(op, ref l, ref r) if op.node.is_lazy() => {
index ac614494355a26c37277ebc4f7e1a8aca87d1c4d..35e0e494771ba131a46b6a488beb2b7a5147e823 100644 (file)
@@ -140,7 +140,7 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
     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::CrateTypeProcMacro
+            *ty == config::CrateTypeProcMacro || *ty == config::CrateTypeMetadata
         });
         ReachableContext {
             tcx: tcx,
index 5f9a6b283c6a06c42c921b9d8afd951851dc752a..0dbde2d21caf5607bd145920a88874abe85407f3 100644 (file)
@@ -805,7 +805,7 @@ fn resolve_expr(visitor: &mut RegionResolutionVisitor, expr: &hir::Expr) {
                 terminating(then.id);
             }
 
-            hir::ExprLoop(ref body, _) => {
+            hir::ExprLoop(ref body, _, _) => {
                 terminating(body.id);
             }
 
index a0043d0a886208c5e475d1cf75fa92a876a4ad7b..41da5562e23fa4f488bda5112ba63367fa810284 100644 (file)
@@ -462,7 +462,7 @@ fn visit_item(&mut self, _: &hir::Item) {
     fn expression_label(ex: &hir::Expr) -> Option<(ast::Name, Span)> {
         match ex.node {
             hir::ExprWhile(.., Some(label)) |
-            hir::ExprLoop(_, Some(label)) => Some((label.node, label.span)),
+            hir::ExprLoop(_, Some(label), _) => Some((label.node, label.span)),
             _ => None,
         }
     }
index ec6971d596b14cfa54bd16a13191dc84ab89be4b..30690c099194f644308b86cff6153a9a8f7a311e 100644 (file)
@@ -75,7 +75,8 @@ fn verify(sess: &Session, items: &lang_items::LanguageItems) {
             config::CrateTypeCdylib |
             config::CrateTypeExecutable |
             config::CrateTypeStaticlib => true,
-            config::CrateTypeRlib => false,
+            config::CrateTypeRlib |
+            config::CrateTypeMetadata => false,
         }
     });
     if !needs_check {
diff --git a/src/librustc/session/code_stats.rs b/src/librustc/session/code_stats.rs
new file mode 100644 (file)
index 0000000..8308c54
--- /dev/null
@@ -0,0 +1,173 @@
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use ty::AdtKind;
+use ty::layout::{Align, Size};
+
+use rustc_data_structures::fx::{FxHashSet};
+
+use std::cmp::{self, Ordering};
+
+#[derive(Clone, PartialEq, Eq, Hash, Debug)]
+pub struct VariantInfo {
+    pub name: Option<String>,
+    pub kind: SizeKind,
+    pub size: u64,
+    pub align: u64,
+    pub fields: Vec<FieldInfo>,
+}
+
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
+pub enum SizeKind { Exact, Min }
+
+#[derive(Clone, PartialEq, Eq, Hash, Debug)]
+pub struct FieldInfo {
+    pub name: String,
+    pub offset: u64,
+    pub size: u64,
+    pub align: u64,
+}
+
+impl From<AdtKind> for DataTypeKind {
+    fn from(kind: AdtKind) -> Self {
+        match kind {
+            AdtKind::Struct => DataTypeKind::Struct,
+            AdtKind::Enum => DataTypeKind::Enum,
+            AdtKind::Union => DataTypeKind::Union,
+        }
+    }
+}
+
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
+pub enum DataTypeKind {
+    Struct,
+    Union,
+    Enum,
+    Closure,
+}
+
+#[derive(PartialEq, Eq, Hash, Debug)]
+pub struct TypeSizeInfo {
+    pub kind: DataTypeKind,
+    pub type_description: String,
+    pub align: u64,
+    pub overall_size: u64,
+    pub opt_discr_size: Option<u64>,
+    pub variants: Vec<VariantInfo>,
+}
+
+#[derive(PartialEq, Eq, Debug)]
+pub struct CodeStats {
+    type_sizes: FxHashSet<TypeSizeInfo>,
+}
+
+impl CodeStats {
+    pub fn new() -> Self { CodeStats { type_sizes: FxHashSet() } }
+
+    pub fn record_type_size<S: ToString>(&mut self,
+                                         kind: DataTypeKind,
+                                         type_desc: S,
+                                         align: Align,
+                                         overall_size: Size,
+                                         opt_discr_size: Option<Size>,
+                                         variants: Vec<VariantInfo>) {
+        let info = TypeSizeInfo {
+            kind: kind,
+            type_description: type_desc.to_string(),
+            align: align.abi(),
+            overall_size: overall_size.bytes(),
+            opt_discr_size: opt_discr_size.map(|s| s.bytes()),
+            variants: variants,
+        };
+        self.type_sizes.insert(info);
+    }
+
+    pub fn print_type_sizes(&self) {
+        let mut sorted: Vec<_> = self.type_sizes.iter().collect();
+
+        // Primary sort: large-to-small.
+        // Secondary sort: description (dictionary order)
+        sorted.sort_by(|info1, info2| {
+            // (reversing cmp order to get large-to-small ordering)
+            match info2.overall_size.cmp(&info1.overall_size) {
+                Ordering::Equal => info1.type_description.cmp(&info2.type_description),
+                other => other,
+            }
+        });
+
+        for info in &sorted {
+            println!("print-type-size type: `{}`: {} bytes, alignment: {} bytes",
+                     info.type_description, info.overall_size, info.align);
+            let indent = "    ";
+
+            let discr_size = if let Some(discr_size) = info.opt_discr_size {
+                println!("print-type-size {}discriminant: {} bytes",
+                         indent, discr_size);
+                discr_size
+            } else {
+                0
+            };
+
+            // We start this at discr_size (rather than 0) because
+            // things like C-enums do not have variants but we still
+            // want the max_variant_size at the end of the loop below
+            // to reflect the presence of the discriminant.
+            let mut max_variant_size = discr_size;
+
+            let struct_like = match info.kind {
+                DataTypeKind::Struct | DataTypeKind::Closure => true,
+                DataTypeKind::Enum | DataTypeKind::Union => false,
+            };
+            for (i, variant_info) in info.variants.iter().enumerate() {
+                let VariantInfo { ref name, kind: _, align: _, size, ref fields } = *variant_info;
+                let indent = if !struct_like {
+                    let name = match name.as_ref() {
+                        Some(name) => format!("{}", name),
+                        None => format!("{}", i),
+                    };
+                    println!("print-type-size {}variant `{}`: {} bytes",
+                             indent, name, size - discr_size);
+                    "        "
+                } else {
+                    assert!(i < 1);
+                    "    "
+                };
+                max_variant_size = cmp::max(max_variant_size, size);
+
+                let mut min_offset = discr_size;
+                for field in fields {
+                    let FieldInfo { ref name, offset, size, align } = *field;
+
+                    // Include field alignment in output only if it caused padding injection
+                    if min_offset != offset {
+                        let pad = offset - min_offset;
+                        println!("print-type-size {}padding: {} bytes",
+                                 indent, pad);
+                        println!("print-type-size {}field `.{}`: {} bytes, alignment: {} bytes",
+                                 indent, name, size, align);
+                    } else {
+                        println!("print-type-size {}field `.{}`: {} bytes",
+                                 indent, name, size);
+                    }
+
+                    min_offset = offset + size;
+                }
+            }
+
+            assert!(max_variant_size <= info.overall_size,
+                    "max_variant_size {} !<= {} overall_size",
+                    max_variant_size, info.overall_size);
+            if max_variant_size < info.overall_size {
+                println!("print-type-size {}end padding: {} bytes",
+                         indent, info.overall_size - max_variant_size);
+            }
+        }
+    }
+}
index 103e2a949df19a24177df00930985a4f650441fc..26dafed7019ed7b9e25c8f6732fb222636aa4ab6 100644 (file)
@@ -78,18 +78,6 @@ pub enum OutputType {
     DepInfo,
 }
 
-#[derive(Clone, Copy, Debug, PartialEq, Eq)]
-pub enum ErrorOutputType {
-    HumanReadable(ColorConfig),
-    Json,
-}
-
-impl Default for ErrorOutputType {
-    fn default() -> ErrorOutputType {
-        ErrorOutputType::HumanReadable(ColorConfig::Auto)
-    }
-}
-
 impl OutputType {
     fn is_compatible_with_codegen_units_and_single_output_file(&self) -> bool {
         match *self {
@@ -125,6 +113,18 @@ pub fn extension(&self) -> &'static str {
     }
 }
 
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub enum ErrorOutputType {
+    HumanReadable(ColorConfig),
+    Json,
+}
+
+impl Default for ErrorOutputType {
+    fn default() -> ErrorOutputType {
+        ErrorOutputType::HumanReadable(ColorConfig::Auto)
+    }
+}
+
 // Use tree-based collections to cheaply get a deterministic Hash implementation.
 // DO NOT switch BTreeMap out for an unsorted container type! That would break
 // dependency tracking for commandline arguments.
@@ -483,6 +483,7 @@ pub enum CrateType {
     CrateTypeStaticlib,
     CrateTypeCdylib,
     CrateTypeProcMacro,
+    CrateTypeMetadata,
 }
 
 #[derive(Clone, Hash)]
@@ -908,6 +909,8 @@ fn parse_panic_strategy(slot: &mut Option<PanicStrategy>, v: Option<&str>) -> bo
           "keep the AST after lowering it to HIR"),
     show_span: Option<String> = (None, parse_opt_string, [TRACKED],
           "show spans for compiler debugging (expr|pat|ty)"),
+    print_type_sizes: bool = (false, parse_bool, [UNTRACKED],
+          "print layout information for each type encountered"),
     print_trans_items: Option<String> = (None, parse_opt_string, [UNTRACKED],
           "print the result of the translation item collection pass"),
     mir_opt_level: Option<usize> = (None, parse_opt_uint, [TRACKED],
@@ -1147,7 +1150,7 @@ pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
                              assumed.", "[KIND=]NAME"),
         opt::multi_s("", "crate-type", "Comma separated list of types of crates
                                     for the compiler to emit",
-                   "[bin|lib|rlib|dylib|cdylib|staticlib]"),
+                   "[bin|lib|rlib|dylib|cdylib|staticlib|metadata]"),
         opt::opt_s("", "crate-name", "Specify the name of the crate being built",
                "NAME"),
         opt::multi_s("", "emit", "Comma separated list of types of output for \
@@ -1539,6 +1542,7 @@ pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateTy
                 "cdylib"    => CrateTypeCdylib,
                 "bin"       => CrateTypeExecutable,
                 "proc-macro" => CrateTypeProcMacro,
+                "metadata"  => CrateTypeMetadata,
                 _ => {
                     return Err(format!("unknown crate type: `{}`",
                                        part));
@@ -1623,6 +1627,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
             CrateTypeStaticlib => "staticlib".fmt(f),
             CrateTypeCdylib => "cdylib".fmt(f),
             CrateTypeProcMacro => "proc-macro".fmt(f),
+            CrateTypeMetadata => "metadata".fmt(f),
         }
     }
 }
index 9577a25b3f83099769a13165d522c3915c287a55..3d8cfd199615e491c916909e0c81cc10e12b5b82 100644 (file)
@@ -8,6 +8,9 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+pub use self::code_stats::{CodeStats, DataTypeKind, FieldInfo};
+pub use self::code_stats::{SizeKind, TypeSizeInfo, VariantInfo};
+
 use dep_graph::DepGraph;
 use hir::def_id::{CrateNum, DefIndex};
 use hir::svh::Svh;
@@ -49,6 +52,7 @@
 use std::time::Duration;
 use libc::c_int;
 
+mod code_stats;
 pub mod config;
 pub mod filesearch;
 pub mod search_paths;
@@ -112,6 +116,9 @@ pub struct Session {
     /// Some measurements that are being gathered during compilation.
     pub perf_stats: PerfStats,
 
+    /// Data about code being compiled, gathered during compilation.
+    pub code_stats: RefCell<CodeStats>,
+
     next_node_id: Cell<ast::NodeId>,
 }
 
@@ -624,7 +631,8 @@ pub fn build_session_(sopts: config::Options,
             incr_comp_hashes_count: Cell::new(0),
             incr_comp_bytes_hashed: Cell::new(0),
             symbol_hash_time: Cell::new(Duration::from_secs(0)),
-        }
+        },
+        code_stats: RefCell::new(CodeStats::new()),
     };
 
     init_llvm(&sess);
index 5ee1c3678d675df1aba5a4567112dd7a986b40ee..bc3c5d6ed4e203d845ae3e6c3697d0a8394175ab 100644 (file)
@@ -559,11 +559,14 @@ pub fn extend<I>(&mut self, dl: &TargetDataLayout,
 
             self.offsets.push(offset);
 
+            debug!("Struct::extend offset: {:?} field: {:?} {:?}", offset, field, field.size(dl));
 
             offset = offset.checked_add(field.size(dl), dl)
                            .map_or(Err(LayoutError::SizeOverflow(scapegoat)), Ok)?;
         }
 
+        debug!("Struct::extend min_size: {:?}", offset);
+
         self.min_size = offset;
 
         Ok(())
@@ -707,12 +710,16 @@ pub fn extend<I>(&mut self, dl: &TargetDataLayout,
                      index, scapegoat);
             }
 
+            debug!("Union::extend field: {:?} {:?}", field, field.size(dl));
+
             if !self.packed {
                 self.align = self.align.max(field.align(dl));
             }
             self.min_size = cmp::max(self.min_size, field.size(dl));
         }
 
+        debug!("Union::extend min-size: {:?}", self.min_size);
+
         Ok(())
     }
 
index e94e93158c47a2de9d3f2b8e464fdb10a1c78e82..7982c641ede5cbefbbef80337319e3976f478b8a 100644 (file)
@@ -30,7 +30,7 @@
 use ty::walk::TypeWalker;
 use util::common::MemoizationMap;
 use util::nodemap::NodeSet;
-use util::nodemap::FxHashMap;
+use util::nodemap::{FxHashMap, FxHashSet};
 
 use serialize::{self, Encodable, Encoder};
 use std::borrow::Cow;
@@ -48,6 +48,7 @@
 use syntax_pos::{DUMMY_SP, Span};
 
 use rustc_const_math::ConstInt;
+use rustc_data_structures::accumulate_vec::IntoIter as AccIntoIter;
 
 use hir;
 use hir::itemlikevisit::ItemLikeVisitor;
@@ -1389,6 +1390,22 @@ fn default_encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
 
 impl<'tcx> serialize::UseSpecializedDecodable for AdtDef<'tcx> {}
 
+impl<'a, 'gcx, 'tcx> AdtDefData<'tcx, 'static> {
+    #[inline]
+    pub fn is_uninhabited_recurse(&'tcx self,
+                                  visited: &mut FxHashSet<(DefId, &'tcx Substs<'tcx>)>,
+                                  block: Option<NodeId>,
+                                  cx: TyCtxt<'a, 'gcx, 'tcx>,
+                                  substs: &'tcx Substs<'tcx>) -> bool {
+        if !visited.insert((self.did, substs)) {
+            return false;
+        };
+        self.variants.iter().all(|v| {
+            v.is_uninhabited_recurse(visited, block, cx, substs, self.is_union())
+        })
+    }
+}
+
 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
 pub enum AdtKind { Struct, Union, Enum }
 
@@ -1531,11 +1548,6 @@ pub fn all_fields(&self) ->
         self.variants.iter().flat_map(VariantDefData::fields_iter)
     }
 
-    #[inline]
-    pub fn is_empty(&self) -> bool {
-        self.variants.is_empty()
-    }
-
     #[inline]
     pub fn is_univariant(&self) -> bool {
         self.variants.len() == 1
@@ -1795,6 +1807,22 @@ pub fn field_named(&self, name: ast::Name) -> &FieldDefData<'tcx, 'container> {
     }
 }
 
+impl<'a, 'gcx, 'tcx> VariantDefData<'tcx, 'static> {
+    #[inline]
+    pub fn is_uninhabited_recurse(&'tcx self,
+                                  visited: &mut FxHashSet<(DefId, &'tcx Substs<'tcx>)>,
+                                  block: Option<NodeId>,
+                                  cx: TyCtxt<'a, 'gcx, 'tcx>,
+                                  substs: &'tcx Substs<'tcx>,
+                                  is_union: bool) -> bool {
+        if is_union {
+            self.fields.iter().all(|f| f.is_uninhabited_recurse(visited, block, cx, substs))
+        } else {
+            self.fields.iter().any(|f| f.is_uninhabited_recurse(visited, block, cx, substs))
+        }
+    }
+}
+
 impl<'a, 'gcx, 'tcx, 'container> FieldDefData<'tcx, 'container> {
     pub fn new(did: DefId,
                name: Name,
@@ -1820,6 +1848,18 @@ pub fn fulfill_ty(&self, ty: Ty<'container>) {
     }
 }
 
+impl<'a, 'gcx, 'tcx> FieldDefData<'tcx, 'static> {
+    #[inline]
+    pub fn is_uninhabited_recurse(&'tcx self,
+                                  visited: &mut FxHashSet<(DefId, &'tcx Substs<'tcx>)>,
+                                  block: Option<NodeId>,
+                                  tcx: TyCtxt<'a, 'gcx, 'tcx>,
+                                  substs: &'tcx Substs<'tcx>) -> bool {
+        block.map_or(true, |b| self.vis.is_accessible_from(b, &tcx.map)) &&
+        self.ty(tcx, substs).is_uninhabited_recurse(visited, block, tcx)
+    }
+}
+
 /// Records the substitutions used to translate the polytype for an
 /// item into the monotype of an item reference.
 #[derive(Clone, RustcEncodable, RustcDecodable)]
@@ -1887,7 +1927,7 @@ pub fn walk(&'tcx self) -> TypeWalker<'tcx> {
     /// Iterator that walks the immediate children of `self`.  Hence
     /// `Foo<Bar<i32>, u32>` yields the sequence `[Bar<i32>, u32]`
     /// (but not `i32`, like `walk`).
-    pub fn walk_shallow(&'tcx self) -> IntoIter<Ty<'tcx>> {
+    pub fn walk_shallow(&'tcx self) -> AccIntoIter<walk::TypeWalkerArray<'tcx>> {
         walk::walk_shallow(self)
     }
 
index 81896ecfb53411446b42aa2bc17e7b5ab70f4f76..cb3176cce10bd468e747db63596e2f0691205e21 100644 (file)
@@ -22,8 +22,9 @@
 use std::fmt;
 use std::ops;
 use syntax::abi;
-use syntax::ast::{self, Name};
+use syntax::ast::{self, Name, NodeId};
 use syntax::symbol::{keywords, InternedString};
+use util::nodemap::FxHashSet;
 
 use serialize;
 
@@ -929,19 +930,27 @@ pub fn is_never(&self) -> bool {
         }
     }
 
-    pub fn is_uninhabited(&self, _cx: TyCtxt) -> bool {
-        // FIXME(#24885): be smarter here, the AdtDefData::is_empty method could easily be made
-        // more complete.
+    /// Checks whether a type is uninhabited.
+    /// If `block` is `Some(id)` it also checks that the uninhabited-ness is visible from `id`.
+    pub fn is_uninhabited(&self, block: Option<NodeId>, cx: TyCtxt<'a, 'gcx, 'tcx>) -> bool {
+        let mut visited = FxHashSet::default();
+        self.is_uninhabited_recurse(&mut visited, block, cx)
+    }
+
+    pub fn is_uninhabited_recurse(&self,
+                                  visited: &mut FxHashSet<(DefId, &'tcx Substs<'tcx>)>,
+                                  block: Option<NodeId>,
+                                  cx: TyCtxt<'a, 'gcx, 'tcx>) -> bool {
         match self.sty {
-            TyAdt(def, _) => def.is_empty(),
+            TyAdt(def, substs) => {
+                def.is_uninhabited_recurse(visited, block, cx, substs)
+            },
 
-            // 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.
-            //TyNever => true,
-            //TyTuple(ref tys) => tys.iter().any(|ty| ty.is_uninhabited(cx)),
+            TyNever => true,
+            TyTuple(ref tys) => tys.iter().any(|ty| ty.is_uninhabited_recurse(visited, block, cx)),
+            TyArray(ty, len) => len > 0 && ty.is_uninhabited_recurse(visited, block, cx),
+            TyRef(_, ref tm) => tm.ty.is_uninhabited_recurse(visited, block, cx),
 
-            // FIXME(canndrew): this line breaks core::fmt
-            //TyRef(_, ref tm) => tm.ty.is_uninhabited(cx),
             _ => false,
         }
     }
index a6ecfd2fb70668405327f35d7ba2eb6064bc7d35..2f9468dbe5887e532203a67afb07be4c64d16e98 100644 (file)
 //! WARNING: this does not keep track of the region depth.
 
 use ty::{self, Ty};
-use std::iter::Iterator;
-use std::vec::IntoIter;
+use rustc_data_structures::small_vec::SmallVec;
+use rustc_data_structures::accumulate_vec::IntoIter as AccIntoIter;
+
+// The TypeWalker's stack is hot enough that it's worth going to some effort to
+// avoid heap allocations.
+pub type TypeWalkerArray<'tcx> = [Ty<'tcx>; 8];
+pub type TypeWalkerStack<'tcx> = SmallVec<TypeWalkerArray<'tcx>>;
 
 pub struct TypeWalker<'tcx> {
-    stack: Vec<Ty<'tcx>>,
+    stack: TypeWalkerStack<'tcx>,
     last_subtree: usize,
 }
 
 impl<'tcx> TypeWalker<'tcx> {
     pub fn new(ty: Ty<'tcx>) -> TypeWalker<'tcx> {
-        TypeWalker { stack: vec![ty], last_subtree: 1, }
+        TypeWalker { stack: SmallVec::one(ty), last_subtree: 1, }
     }
 
     /// Skips the subtree of types corresponding to the last type
@@ -61,8 +66,8 @@ fn next(&mut self) -> Option<Ty<'tcx>> {
     }
 }
 
-pub fn walk_shallow<'tcx>(ty: Ty<'tcx>) -> IntoIter<Ty<'tcx>> {
-    let mut stack = vec![];
+pub fn walk_shallow<'tcx>(ty: Ty<'tcx>) -> AccIntoIter<TypeWalkerArray<'tcx>> {
+    let mut stack = SmallVec::new();
     push_subtypes(&mut stack, ty);
     stack.into_iter()
 }
@@ -73,7 +78,7 @@ pub fn walk_shallow<'tcx>(ty: Ty<'tcx>) -> IntoIter<Ty<'tcx>> {
 // known to be significant to any code, but it seems like the
 // natural order one would expect (basically, the order of the
 // types as they are written).
-fn push_subtypes<'tcx>(stack: &mut Vec<Ty<'tcx>>, parent_ty: Ty<'tcx>) {
+fn push_subtypes<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent_ty: Ty<'tcx>) {
     match parent_ty.sty {
         ty::TyBool | ty::TyChar | ty::TyInt(_) | ty::TyUint(_) | ty::TyFloat(_) |
         ty::TyStr | ty::TyInfer(_) | ty::TyParam(_) | ty::TyNever | ty::TyError => {
@@ -112,7 +117,7 @@ fn push_subtypes<'tcx>(stack: &mut Vec<Ty<'tcx>>, parent_ty: Ty<'tcx>) {
     }
 }
 
-fn push_sig_subtypes<'tcx>(stack: &mut Vec<Ty<'tcx>>, sig: &ty::PolyFnSig<'tcx>) {
+fn push_sig_subtypes<'tcx>(stack: &mut TypeWalkerStack<'tcx>, sig: &ty::PolyFnSig<'tcx>) {
     stack.push(sig.0.output);
     stack.extend(sig.0.inputs.iter().cloned().rev());
 }
index 7cd5fd78df528981329792c6f9585bf522e6d81a..e01856b2a476265b161671e78b5760d249e545ae 100644 (file)
 use std::path::Path;
 use std::time::{Duration, Instant};
 
-use hir;
-use hir::intravisit;
-use hir::intravisit::Visitor;
-
 // The name of the associated type for `Fn` return types
 pub const FN_OUTPUT_NAME: &'static str = "Output";
 
@@ -186,57 +182,6 @@ pub fn indenter() -> Indenter {
     Indenter { _cannot_construct_outside_of_this_module: () }
 }
 
-struct LoopQueryVisitor<P> where P: FnMut(&hir::Expr_) -> bool {
-    p: P,
-    flag: bool,
-}
-
-impl<'v, P> Visitor<'v> for LoopQueryVisitor<P> where P: FnMut(&hir::Expr_) -> bool {
-    fn visit_expr(&mut self, e: &hir::Expr) {
-        self.flag |= (self.p)(&e.node);
-        match e.node {
-          // Skip inner loops, since a break in the inner loop isn't a
-          // break inside the outer loop
-          hir::ExprLoop(..) | hir::ExprWhile(..) => {}
-          _ => intravisit::walk_expr(self, e)
-        }
-    }
-}
-
-// Takes a predicate p, returns true iff p is true for any subexpressions
-// of b -- skipping any inner loops (loop, while, loop_body)
-pub fn loop_query<P>(b: &hir::Block, p: P) -> bool where P: FnMut(&hir::Expr_) -> bool {
-    let mut v = LoopQueryVisitor {
-        p: p,
-        flag: false,
-    };
-    intravisit::walk_block(&mut v, b);
-    return v.flag;
-}
-
-struct BlockQueryVisitor<P> where P: FnMut(&hir::Expr) -> bool {
-    p: P,
-    flag: bool,
-}
-
-impl<'v, P> Visitor<'v> for BlockQueryVisitor<P> where P: FnMut(&hir::Expr) -> bool {
-    fn visit_expr(&mut self, e: &hir::Expr) {
-        self.flag |= (self.p)(e);
-        intravisit::walk_expr(self, e)
-    }
-}
-
-// Takes a predicate p, returns true iff p is true for any subexpressions
-// of b -- skipping any inner loops (loop, while, loop_body)
-pub fn block_query<P>(b: &hir::Block, p: P) -> bool where P: FnMut(&hir::Expr) -> bool {
-    let mut v = BlockQueryVisitor {
-        p: p,
-        flag: false,
-    };
-    intravisit::walk_block(&mut v, &b);
-    return v.flag;
-}
-
 pub trait MemoizationMap {
     type Key: Clone;
     type Value: Clone;
index f63a27e0d7563fd5df3af52c4d8000f7de7c1c48..3c94d7d6fd5d14919824d55b931de929616ce987 100644 (file)
@@ -204,7 +204,7 @@ fn check_match(
             // Check for empty enum, because is_useful only works on inhabited types.
             let pat_ty = self.tcx.tables().node_id_to_type(scrut.id);
             if inlined_arms.is_empty() {
-                if !pat_ty.is_uninhabited(self.tcx) {
+                if !pat_ty.is_uninhabited(Some(scrut.id), self.tcx) {
                     // We know the type is inhabited, so this must be wrong
                     let mut err = create_e0004(self.tcx.sess, span,
                                                format!("non-exhaustive patterns: type {} \
index c265fa97e2957d2b094ad7f7d8e9c59d8b7d0acf..b594fe9853a43ac35a2b5bf8ca247300fd18fdde 100644 (file)
@@ -297,7 +297,7 @@ pub fn const_expr_to_pat<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                 _ => bug!()
             };
             let pats = args.iter()
-                           .map(|expr| const_expr_to_pat(tcx, &**expr, pat_id, span))
+                           .map(|expr| const_expr_to_pat(tcx, &*expr, pat_id, span))
                            .collect::<Result<_, _>>()?;
             PatKind::TupleStruct(path, pats, None)
         }
index 565a3c443a34ab0581c33bdb6cd1045c33c0d24f..4e2b3786021026bf85b6821724ee0cfe3612201b 100644 (file)
@@ -130,6 +130,18 @@ pub fn insert(&mut self, index: usize, element: A::Element) {
             self.set_len(len + 1);
         }
     }
+
+    pub fn truncate(&mut self, len: usize) {
+        unsafe {
+            while len < self.len() {
+                // Decrement len before the drop_in_place(), so a panic on Drop
+                // doesn't re-drop the just-failed value.
+                let newlen = self.len() - 1;
+                self.set_len(newlen);
+                ::std::ptr::drop_in_place(self.get_unchecked_mut(newlen));
+            }
+        }
+    }
 }
 
 impl<A: Array> Deref for SmallVec<A> {
index 228119e6cc7da46206696a7bf6452a38361182cc..9a4ecef0c0ebd16d91aa36670a9a6835e2bb4248 100644 (file)
@@ -215,6 +215,10 @@ macro_rules! controller_entry_point {
         })??
     };
 
+    if sess.opts.debugging_opts.print_type_sizes {
+        sess.code_stats.borrow().print_type_sizes();
+    }
+
     let phase5_result = phase_5_run_llvm_passes(sess, &trans, &outputs);
 
     controller_entry_point!(after_llvm,
@@ -855,7 +859,7 @@ macro_rules! try_with_f {
 
     time(time_passes,
          "loop checking",
-         || loops::check_crate(sess, &hir_map));
+         || loops::check_crate(sess, &resolutions.def_map, &hir_map));
 
     time(time_passes,
               "static item recursion checking",
@@ -1182,6 +1186,9 @@ pub fn collect_crate_types(session: &Session, attrs: &[ast::Attribute]) -> Vec<c
                          Some(ref n) if *n == "rlib" => {
                              Some(config::CrateTypeRlib)
                          }
+                         Some(ref n) if *n == "metadata" => {
+                             Some(config::CrateTypeMetadata)
+                         }
                          Some(ref n) if *n == "dylib" => {
                              Some(config::CrateTypeDylib)
                          }
index 4bad264ac8749d7c0b71ef12564d51d75c3cc52f..fd0856393fc1b3b9c8b39bbe0d9a5e5cd73f3568 100644 (file)
@@ -322,7 +322,7 @@ fn saw_expr<'a>(node: &'a Expr_,
         ExprType(..)             => (SawExprType, false),
         ExprIf(..)               => (SawExprIf, false),
         ExprWhile(..)            => (SawExprWhile, false),
-        ExprLoop(_, id)          => (SawExprLoop(id.map(|id| id.node.as_str())), false),
+        ExprLoop(_, id, _)       => (SawExprLoop(id.map(|id| id.node.as_str())), false),
         ExprMatch(..)            => (SawExprMatch, false),
         ExprClosure(cc, _, _, _) => (SawExprClosure(cc), false),
         ExprBlock(..)            => (SawExprBlock, false),
@@ -335,7 +335,7 @@ fn saw_expr<'a>(node: &'a Expr_,
         ExprIndex(..)            => (SawExprIndex, true),
         ExprPath(ref qself, _)   => (SawExprPath(qself.as_ref().map(|q| q.position)), false),
         ExprAddrOf(m, _)         => (SawExprAddrOf(m), false),
-        ExprBreak(id)            => (SawExprBreak(id.map(|id| id.node.as_str())), false),
+        ExprBreak(id, _)         => (SawExprBreak(id.map(|id| id.node.as_str())), false),
         ExprAgain(id)            => (SawExprAgain(id.map(|id| id.node.as_str())), false),
         ExprRet(..)              => (SawExprRet, false),
         ExprInlineAsm(ref a,..)  => (SawExprInlineAsm(a), false),
index 114c0ea556ef5f6b712721da87b618f3da336977..1a3ea5db871ebedc1363cba4e1f9550f9623fcbc 100644 (file)
@@ -232,6 +232,10 @@ macro_rules! add_lint_group {
             id: LintId::of(EXTRA_REQUIREMENT_IN_IMPL),
             reference: "issue #37166 <https://github.com/rust-lang/rust/issues/37166>",
         },
+        FutureIncompatibleInfo {
+            id: LintId::of(LEGACY_DIRECTORY_OWNERSHIP),
+            reference: "issue #37872 <https://github.com/rust-lang/rust/issues/37872>",
+        },
         ]);
 
     // Register renamed and removed lints
index 269fb1dcea4c20840252eb3d4c1dd2fa04b9833e..27c00481bfd3adad17006212acada0650b339915 100644 (file)
@@ -44,6 +44,7 @@
 pub struct Library {
     pub dylib: Option<(PathBuf, PathKind)>,
     pub rlib: Option<(PathBuf, PathKind)>,
+    pub rmeta: Option<(PathBuf, PathKind)>,
     pub metadata: MetadataBlob,
 }
 
@@ -62,10 +63,11 @@ fn dump_crates(cstore: &CStore) {
         info!("  cnum: {}", data.cnum);
         info!("  hash: {}", data.hash());
         info!("  reqd: {:?}", data.dep_kind.get());
-        let CrateSource { dylib, rlib } = data.source.clone();
+        let CrateSource { dylib, rlib, rmeta } = data.source.clone();
         dylib.map(|dl| info!("  dylib: {}", dl.0.display()));
         rlib.map(|rl|  info!("   rlib: {}", rl.0.display()));
-    })
+        rmeta.map(|rl| info!("   rmeta: {}", rl.0.display()));
+    });
 }
 
 #[derive(Debug)]
@@ -278,6 +280,7 @@ fn register_crate(&mut self,
                 ident: ident.to_string(),
                 dylib: lib.dylib.clone().map(|p| p.0),
                 rlib:  lib.rlib.clone().map(|p| p.0),
+                rmeta: lib.rmeta.clone().map(|p| p.0),
             })
         } else {
             None
@@ -285,7 +288,7 @@ fn register_crate(&mut self,
         // Maintain a reference to the top most crate.
         let root = if root.is_some() { root } else { &crate_paths };
 
-        let Library { dylib, rlib, metadata } = lib;
+        let Library { dylib, rlib, rmeta, metadata } = lib;
 
         let cnum_map = self.resolve_crate_deps(root, &crate_root, &metadata, cnum, span, dep_kind);
 
@@ -305,6 +308,7 @@ fn register_crate(&mut self,
             source: cstore::CrateSource {
                 dylib: dylib,
                 rlib: rlib,
+                rmeta: rmeta,
             },
         });
 
@@ -767,7 +771,8 @@ fn inject_allocator_crate(&mut self) {
                 config::CrateTypeProcMacro |
                 config::CrateTypeCdylib |
                 config::CrateTypeStaticlib => need_lib_alloc = true,
-                config::CrateTypeRlib => {}
+                config::CrateTypeRlib |
+                config::CrateTypeMetadata => {}
             }
         }
         if !need_lib_alloc && !need_exe_alloc { return }
index ce47b936ddc0ebc17db0994fea3e5ff43e8e71e5..7c1834c1576a8f1f5e8d5318a5c92121652e960b 100644 (file)
@@ -25,7 +25,6 @@
 
 use std::cell::{RefCell, Cell};
 use std::rc::Rc;
-use std::path::PathBuf;
 use flate::Bytes;
 use syntax::{ast, attr};
 use syntax::ext::base::SyntaxExtension;
@@ -34,7 +33,7 @@
 
 pub use rustc::middle::cstore::{NativeLibrary, LinkagePreference};
 pub use rustc::middle::cstore::{NativeStatic, NativeFramework, NativeUnknown};
-pub use rustc::middle::cstore::{CrateSource, LinkMeta};
+pub use rustc::middle::cstore::{CrateSource, LinkMeta, LibSource};
 
 // A map from external crate numbers (as decoded from some crate file) to
 // local crate numbers (as generated during this session). Each external
@@ -45,6 +44,7 @@
 pub enum MetadataBlob {
     Inflated(Bytes),
     Archive(locator::ArchiveMetadata),
+    Raw(Vec<u8>),
 }
 
 /// Holds information about a syntax_pos::FileMap imported from another crate.
@@ -186,7 +186,7 @@ pub fn push_dependencies_in_postorder(&self, ordering: &mut Vec<CrateNum>, krate
     // positions.
     pub fn do_get_used_crates(&self,
                               prefer: LinkagePreference)
-                              -> Vec<(CrateNum, Option<PathBuf>)> {
+                              -> Vec<(CrateNum, LibSource)> {
         let mut ordering = Vec::new();
         for (&num, _) in self.metas.borrow().iter() {
             self.push_dependencies_in_postorder(&mut ordering, num);
@@ -202,6 +202,16 @@ pub fn do_get_used_crates(&self,
                     LinkagePreference::RequireDynamic => data.source.dylib.clone().map(|p| p.0),
                     LinkagePreference::RequireStatic => data.source.rlib.clone().map(|p| p.0),
                 };
+                let path = match path {
+                    Some(p) => LibSource::Some(p),
+                    None => {
+                        if data.source.rmeta.is_some() {
+                            LibSource::MetadataOnly
+                        } else {
+                            LibSource::None
+                        }
+                    }
+                };
                 Some((cnum, path))
             })
             .collect::<Vec<_>>();
index 407166203de87b4f12dc263e39a439f21cc6ce5e..ead933384b96d9b4e18bbfbe807270c406e83c02 100644 (file)
@@ -13,7 +13,7 @@
 use locator;
 use schema;
 
-use rustc::middle::cstore::{InlinedItem, CrateStore, CrateSource, DepKind, ExternCrate};
+use rustc::middle::cstore::{InlinedItem, CrateStore, CrateSource, LibSource, DepKind, ExternCrate};
 use rustc::middle::cstore::{NativeLibrary, LinkMeta, LinkagePreference, LoadedMacro};
 use rustc::hir::def::{self, Def};
 use rustc::middle::lang_items;
@@ -28,7 +28,6 @@
 use rustc::util::nodemap::{NodeSet, DefIdMap};
 use rustc_back::PanicStrategy;
 
-use std::path::PathBuf;
 use syntax::ast;
 use syntax::attr;
 use syntax::parse::new_parser_from_source_str;
@@ -545,7 +544,7 @@ fn metadata_section_name(&self, target: &Target) -> &str
         locator::meta_section_name(target)
     }
 
-    fn used_crates(&self, prefer: LinkagePreference) -> Vec<(CrateNum, Option<PathBuf>)>
+    fn used_crates(&self, prefer: LinkagePreference) -> Vec<(CrateNum, LibSource)>
     {
         self.do_get_used_crates(prefer)
     }
index fb1314992c094d0596ab1618c618a69e112383ec..f59f2bcc074764c42bf61f55e5da3a6729239536 100644 (file)
@@ -88,8 +88,9 @@ fn decoder(self, pos: usize) -> DecodeContext<'a, 'tcx> {
 impl<'a, 'tcx> Metadata<'a, 'tcx> for &'a MetadataBlob {
     fn raw_bytes(self) -> &'a [u8] {
         match *self {
-            MetadataBlob::Inflated(ref vec) => &vec[..],
+            MetadataBlob::Inflated(ref vec) => vec,
             MetadataBlob::Archive(ref ar) => ar.as_slice(),
+            MetadataBlob::Raw(ref vec) => vec,
         }
     }
 }
@@ -420,6 +421,10 @@ pub fn is_compatible(&self) -> bool {
         self.raw_bytes().starts_with(METADATA_HEADER)
     }
 
+    pub fn get_rustc_version(&self) -> String {
+        Lazy::with_position(METADATA_HEADER.len() + 4).decode(self)
+    }
+
     pub fn get_root(&self) -> CrateRoot {
         let slice = self.raw_bytes();
         let offset = METADATA_HEADER.len();
index 2f4b0d5c87b0dc6fb1df552a8df4200897d804d6..665f3de0a3ba7fda9a389cc3c257d19f4ae19708 100644 (file)
@@ -1278,7 +1278,6 @@ fn encode_crate_root(&mut self) -> Lazy<CrateRoot> {
         let link_meta = self.link_meta;
         let is_proc_macro = tcx.sess.crate_types.borrow().contains(&CrateTypeProcMacro);
         let root = self.lazy(&CrateRoot {
-            rustc_version: rustc_version(),
             name: link_meta.crate_name,
             triple: tcx.sess.opts.target_triple.clone(),
             hash: link_meta.crate_hash,
@@ -1368,7 +1367,8 @@ pub fn encode_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     // Will be filed with the root position after encoding everything.
     cursor.write_all(&[0, 0, 0, 0]).unwrap();
 
-    let root = EncodeContext {
+    let root = {
+        let mut ecx = EncodeContext {
             opaque: opaque::Encoder::new(&mut cursor),
             tcx: tcx,
             reexports: reexports,
@@ -1378,8 +1378,15 @@ pub fn encode_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             lazy_state: LazyState::NoNode,
             type_shorthands: Default::default(),
             predicate_shorthands: Default::default(),
-        }
-        .encode_crate_root();
+        };
+
+        // Encode the rustc version string in a predictable location.
+        rustc_version().encode(&mut ecx).unwrap();
+
+        // Encode all the entries and extra information in the crate,
+        // culminating in the `CrateRoot` which points to all of it.
+        ecx.encode_crate_root()
+    };
     let mut result = cursor.into_inner();
 
     // Encode the root position.
index f5196f7ea8428470783899cb9a514bb8580cb6f1..868bc363791350d53e322af81e3e99c426157579 100644 (file)
 //! is a platform-defined dynamic library. Each library has a metadata somewhere
 //! inside of it.
 //!
+//! A third kind of dependency is an rmeta file. These are metadata files and do
+//! not contain any code, etc. To a first approximation, these are treated in the
+//! same way as rlibs. Where there is both an rlib and an rmeta file, the rlib
+//! gets priority (even if the rmeta file is newer). An rmeta file is only
+//! useful for checking a downstream crate, attempting to link one will cause an
+//! error.
+//!
 //! When translating a crate name to a crate on the filesystem, we all of a
 //! sudden need to take into account both rlibs and dylibs! Linkage later on may
 //! use either one of these files, as each has their pros/cons. The job of crate
 
 use std::cmp;
 use std::fmt;
-use std::fs;
-use std::io;
+use std::fs::{self, File};
+use std::io::{self, Read};
 use std::path::{Path, PathBuf};
 use std::ptr;
 use std::slice;
@@ -276,6 +283,7 @@ pub struct CratePaths {
     pub ident: String,
     pub dylib: Option<PathBuf>,
     pub rlib: Option<PathBuf>,
+    pub rmeta: Option<PathBuf>,
 }
 
 pub const METADATA_FILENAME: &'static str = "rust.metadata.bin";
@@ -283,6 +291,7 @@ pub struct CratePaths {
 #[derive(Copy, Clone, PartialEq)]
 enum CrateFlavor {
     Rlib,
+    Rmeta,
     Dylib,
 }
 
@@ -290,6 +299,7 @@ impl fmt::Display for CrateFlavor {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         f.write_str(match *self {
             CrateFlavor::Rlib => "rlib",
+            CrateFlavor::Rmeta => "rmeta",
             CrateFlavor::Dylib => "dylib",
         })
     }
@@ -297,12 +307,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 
 impl CratePaths {
     fn paths(&self) -> Vec<PathBuf> {
-        match (&self.dylib, &self.rlib) {
-            (&None, &None) => vec![],
-            (&Some(ref p), &None) |
-            (&None, &Some(ref p)) => vec![p.clone()],
-            (&Some(ref p1), &Some(ref p2)) => vec![p1.clone(), p2.clone()],
-        }
+        self.dylib.iter().chain(self.rlib.iter()).chain(self.rmeta.iter()).cloned().collect()
     }
 }
 
@@ -458,32 +463,35 @@ fn find_library_crate(&mut self) -> Option<Library> {
                 None => return FileDoesntMatch,
                 Some(file) => file,
             };
-            let (hash, rlib) = if file.starts_with(&rlib_prefix[..]) && file.ends_with(".rlib") {
-                (&file[(rlib_prefix.len())..(file.len() - ".rlib".len())], true)
-            } else if file.starts_with(&dylib_prefix) &&
-                                         file.ends_with(&dypair.1) {
-                (&file[(dylib_prefix.len())..(file.len() - dypair.1.len())], false)
-            } else {
-                if file.starts_with(&staticlib_prefix[..]) && file.ends_with(&staticpair.1) {
-                    staticlibs.push(CrateMismatch {
-                        path: path.to_path_buf(),
-                        got: "static".to_string(),
-                    });
-                }
-                return FileDoesntMatch;
-            };
+            let (hash, found_kind) =
+                if file.starts_with(&rlib_prefix[..]) && file.ends_with(".rlib") {
+                    (&file[(rlib_prefix.len())..(file.len() - ".rlib".len())], CrateFlavor::Rlib)
+                } else if file.starts_with(&rlib_prefix[..]) && file.ends_with(".rmeta") {
+                    (&file[(rlib_prefix.len())..(file.len() - ".rmeta".len())], CrateFlavor::Rmeta)
+                } else if file.starts_with(&dylib_prefix) &&
+                                             file.ends_with(&dypair.1) {
+                    (&file[(dylib_prefix.len())..(file.len() - dypair.1.len())], CrateFlavor::Dylib)
+                } else {
+                    if file.starts_with(&staticlib_prefix[..]) && file.ends_with(&staticpair.1) {
+                        staticlibs.push(CrateMismatch {
+                            path: path.to_path_buf(),
+                            got: "static".to_string(),
+                        });
+                    }
+                    return FileDoesntMatch;
+                };
             info!("lib candidate: {}", path.display());
 
             let hash_str = hash.to_string();
             let slot = candidates.entry(hash_str)
-                .or_insert_with(|| (FxHashMap(), FxHashMap()));
-            let (ref mut rlibs, ref mut dylibs) = *slot;
+                .or_insert_with(|| (FxHashMap(), FxHashMap(), FxHashMap()));
+            let (ref mut rlibs, ref mut rmetas, ref mut dylibs) = *slot;
             fs::canonicalize(path)
                 .map(|p| {
-                    if rlib {
-                        rlibs.insert(p, kind);
-                    } else {
-                        dylibs.insert(p, kind);
+                    match found_kind {
+                        CrateFlavor::Rlib => { rlibs.insert(p, kind); }
+                        CrateFlavor::Rmeta => { rmetas.insert(p, kind); }
+                        CrateFlavor::Dylib => { dylibs.insert(p, kind); }
                     }
                     FileMatches
                 })
@@ -500,15 +508,17 @@ fn find_library_crate(&mut self) -> Option<Library> {
         // libraries corresponds to the crate id and hash criteria that this
         // search is being performed for.
         let mut libraries = FxHashMap();
-        for (_hash, (rlibs, dylibs)) in candidates {
+        for (_hash, (rlibs, rmetas, dylibs)) in candidates {
             let mut slot = None;
             let rlib = self.extract_one(rlibs, CrateFlavor::Rlib, &mut slot);
+            let rmeta = self.extract_one(rmetas, CrateFlavor::Rmeta, &mut slot);
             let dylib = self.extract_one(dylibs, CrateFlavor::Dylib, &mut slot);
             if let Some((h, m)) = slot {
                 libraries.insert(h,
                                  Library {
                                      dylib: dylib,
                                      rlib: rlib,
+                                     rmeta: rmeta,
                                      metadata: m,
                                  });
             }
@@ -629,25 +639,26 @@ fn extract_one(&mut self,
     }
 
     fn crate_matches(&mut self, metadata: &MetadataBlob, libpath: &Path) -> Option<Svh> {
-        let root = metadata.get_root();
-        if let Some(is_proc_macro) = self.is_proc_macro {
-            if root.macro_derive_registrar.is_some() != is_proc_macro {
-                return None;
-            }
-        }
-
         let rustc_version = rustc_version();
-        if root.rustc_version != rustc_version {
+        let found_version = metadata.get_rustc_version();
+        if found_version != rustc_version {
             info!("Rejecting via version: expected {} got {}",
                   rustc_version,
-                  root.rustc_version);
+                  found_version);
             self.rejected_via_version.push(CrateMismatch {
                 path: libpath.to_path_buf(),
-                got: root.rustc_version,
+                got: found_version,
             });
             return None;
         }
 
+        let root = metadata.get_root();
+        if let Some(is_proc_macro) = self.is_proc_macro {
+            if root.macro_derive_registrar.is_some() != is_proc_macro {
+                return None;
+            }
+        }
+
         if self.should_match_name {
             if self.crate_name != root.name {
                 info!("Rejecting via crate name");
@@ -704,6 +715,7 @@ fn find_commandline_library<'b, LOCS>(&mut self, locs: LOCS) -> Option<Library>
         let sess = self.sess;
         let dylibname = self.dylibname();
         let mut rlibs = FxHashMap();
+        let mut rmetas = FxHashMap();
         let mut dylibs = FxHashMap();
         {
             let locs = locs.map(|l| PathBuf::from(l)).filter(|loc| {
@@ -722,7 +734,8 @@ fn find_commandline_library<'b, LOCS>(&mut self, locs: LOCS) -> Option<Library>
                         return false;
                     }
                 };
-                if file.starts_with("lib") && file.ends_with(".rlib") {
+                if file.starts_with("lib") &&
+                   (file.ends_with(".rlib") || file.ends_with(".rmeta")) {
                     return true;
                 } else {
                     let (ref prefix, ref suffix) = dylibname;
@@ -745,6 +758,8 @@ fn find_commandline_library<'b, LOCS>(&mut self, locs: LOCS) -> Option<Library>
             for loc in locs {
                 if loc.file_name().unwrap().to_str().unwrap().ends_with(".rlib") {
                     rlibs.insert(fs::canonicalize(&loc).unwrap(), PathKind::ExternFlag);
+                } else if loc.file_name().unwrap().to_str().unwrap().ends_with(".rmeta") {
+                    rmetas.insert(fs::canonicalize(&loc).unwrap(), PathKind::ExternFlag);
                 } else {
                     dylibs.insert(fs::canonicalize(&loc).unwrap(), PathKind::ExternFlag);
                 }
@@ -754,9 +769,10 @@ fn find_commandline_library<'b, LOCS>(&mut self, locs: LOCS) -> Option<Library>
         // Extract the rlib/dylib pair.
         let mut slot = None;
         let rlib = self.extract_one(rlibs, CrateFlavor::Rlib, &mut slot);
+        let rmeta = self.extract_one(rmetas, CrateFlavor::Rmeta, &mut slot);
         let dylib = self.extract_one(dylibs, CrateFlavor::Dylib, &mut slot);
 
-        if rlib.is_none() && dylib.is_none() {
+        if rlib.is_none() && rmeta.is_none() && dylib.is_none() {
             return None;
         }
         match slot {
@@ -764,6 +780,7 @@ fn find_commandline_library<'b, LOCS>(&mut self, locs: LOCS) -> Option<Library>
                 Some(Library {
                     dylib: dylib,
                     rlib: rlib,
+                    rmeta: rmeta,
                     metadata: metadata,
                 })
             }
@@ -851,6 +868,15 @@ fn get_metadata_section_imp(target: &Target,
                 Ok(blob)
             }
         };
+    } else if flavor == CrateFlavor::Rmeta {
+        let mut file = File::open(filename).map_err(|_|
+            format!("could not open file: '{}'", filename.display()))?;
+        let mut buf = vec![];
+        file.read_to_end(&mut buf).map_err(|_|
+            format!("failed to read rlib metadata: '{}'", filename.display()))?;
+        let blob = MetadataBlob::Raw(buf);
+        verify_decompressed_encoding_version(&blob, filename)?;
+        return Ok(blob);
     }
     unsafe {
         let buf = common::path2cstr(filename);
@@ -934,6 +960,8 @@ pub fn list_file_metadata(target: &Target, path: &Path, out: &mut io::Write) ->
     let filename = path.file_name().unwrap().to_str().unwrap();
     let flavor = if filename.ends_with(".rlib") {
         CrateFlavor::Rlib
+    } else if filename.ends_with(".rmeta") {
+        CrateFlavor::Rmeta
     } else {
         CrateFlavor::Dylib
     };
index e11719dc40f2a83aa1ccfdb2047ec46fbabf0397..32e89f64f0ec1516b2049e8f5a46bafefde83342 100644 (file)
@@ -34,15 +34,17 @@ pub fn rustc_version() -> String {
 
 /// 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;
+/// the rustc version can't be found to compare with `rustc_version()`.
+pub const METADATA_VERSION: u8 = 4;
 
 /// 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`.
+/// This header is followed by the position of the `CrateRoot`,
+/// which is encoded as a 32-bit big-endian unsigned integer,
+/// and further followed by the rustc version string.
 pub const METADATA_HEADER: &'static [u8; 12] =
     &[0, 0, 0, 0, b'r', b'u', b's', b't', 0, 0, 0, METADATA_VERSION];
 
@@ -163,7 +165,6 @@ pub enum LazyState {
 
 #[derive(RustcEncodable, RustcDecodable)]
 pub struct CrateRoot {
-    pub rustc_version: String,
     pub name: Symbol,
     pub triple: String,
     pub hash: hir::svh::Svh,
index 5fa08442221001cce28bbcab1d6f6ab93121d010..5a77de08070281763ba800cc6796895a5cd353fb 100644 (file)
@@ -169,41 +169,39 @@ pub fn into_expr(&mut self,
                 this.cfg.terminate(block, source_info,
                                    TerminatorKind::Goto { target: loop_block });
 
-                let might_break = this.in_loop_scope(loop_block, exit_block, move |this| {
-                    // conduct the test, if necessary
-                    let body_block;
-                    if let Some(cond_expr) = opt_cond_expr {
-                        // This loop has a condition, ergo its exit_block is reachable.
-                        this.find_loop_scope(expr_span, None).might_break = true;
+                this.in_loop_scope(
+                    loop_block, exit_block, destination.clone(),
+                    move |this| {
+                        // conduct the test, if necessary
+                        let body_block;
+                        if let Some(cond_expr) = opt_cond_expr {
+                            let loop_block_end;
+                            let cond = unpack!(
+                                loop_block_end = this.as_operand(loop_block, cond_expr));
+                            body_block = this.cfg.start_new_block();
+                            this.cfg.terminate(loop_block_end, source_info,
+                                               TerminatorKind::If {
+                                                   cond: cond,
+                                                   targets: (body_block, exit_block)
+                                               });
 
-                        let loop_block_end;
-                        let cond = unpack!(loop_block_end = this.as_operand(loop_block, cond_expr));
-                        body_block = this.cfg.start_new_block();
-                        this.cfg.terminate(loop_block_end, source_info,
-                                           TerminatorKind::If {
-                                               cond: cond,
-                                               targets: (body_block, exit_block)
-                                           });
-                    } else {
-                        body_block = loop_block;
-                    }
+                            // if the test is false, there's no `break` to assign `destination`, so
+                            // we have to do it; this overwrites any `break`-assigned value but it's
+                            // always `()` anyway
+                            this.cfg.push_assign_unit(exit_block, source_info, destination);
+                        } else {
+                            body_block = loop_block;
+                        }
 
-                    // The “return” value of the loop body must always be an unit, but we cannot
-                    // reuse that as a “return” value of the whole loop expressions, because some
-                    // loops are diverging (e.g. `loop {}`). Thus, we introduce a unit temporary as
-                    // the destination for the loop body and assign the loop’s own “return” value
-                    // immediately after the iteration is finished.
-                    let tmp = this.get_unit_temp();
-                    // Execute the body, branching back to the test.
-                    let body_block_end = unpack!(this.into(&tmp, body_block, body));
-                    this.cfg.terminate(body_block_end, source_info,
-                                       TerminatorKind::Goto { target: loop_block });
-                });
-                // If the loop may reach its exit_block, we assign an empty tuple to the
-                // destination to keep the MIR well-formed.
-                if might_break {
-                    this.cfg.push_assign_unit(exit_block, source_info, destination);
-                }
+                        // The “return” value of the loop body must always be an unit. We therefore
+                        // introduce a unit temporary as the destination for the loop body.
+                        let tmp = this.get_unit_temp();
+                        // Execute the body, branching back to the test.
+                        let body_block_end = unpack!(this.into(&tmp, body_block, body));
+                        this.cfg.terminate(body_block_end, source_info,
+                                           TerminatorKind::Goto { target: loop_block });
+                    }
+                );
                 exit_block.unit()
             }
             ExprKind::Call { ty, fun, args } => {
index 4a1926e7c57d4ec59886a4b4fcfb1503ccac540b..f04d630379a35c99ed6dfdb27b3515190fe9daf1 100644 (file)
@@ -11,9 +11,7 @@
 use build::{BlockAnd, BlockAndExtension, Builder};
 use build::scope::LoopScope;
 use hair::*;
-use rustc::middle::region::CodeExtent;
 use rustc::mir::*;
-use syntax_pos::Span;
 
 impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
 
@@ -79,14 +77,28 @@ pub fn stmt_expr(&mut self, mut block: BasicBlock, expr: Expr<'tcx>) -> BlockAnd
                 block.unit()
             }
             ExprKind::Continue { label } => {
-                this.break_or_continue(expr_span, label, block,
-                                       |loop_scope| loop_scope.continue_block)
+                let LoopScope { continue_block, extent, .. } =
+                    *this.find_loop_scope(expr_span, label);
+                this.exit_scope(expr_span, extent, block, continue_block);
+                this.cfg.start_new_block().unit()
             }
-            ExprKind::Break { label } => {
-                this.break_or_continue(expr_span, label, block, |loop_scope| {
-                    loop_scope.might_break = true;
-                    loop_scope.break_block
-                })
+            ExprKind::Break { label, value } => {
+                let (break_block, extent, destination) = {
+                    let LoopScope {
+                        break_block,
+                        extent,
+                        ref break_destination,
+                        ..
+                    } = *this.find_loop_scope(expr_span, label);
+                    (break_block, extent, break_destination.clone())
+                };
+                if let Some(value) = value {
+                    unpack!(block = this.into(&destination, block, value))
+                } else {
+                    this.cfg.push_assign_unit(block, source_info, &destination)
+                }
+                this.exit_scope(expr_span, extent, block, break_block);
+                this.cfg.start_new_block().unit()
             }
             ExprKind::Return { value } => {
                 block = match value {
@@ -115,20 +127,4 @@ pub fn stmt_expr(&mut self, mut block: BasicBlock, expr: Expr<'tcx>) -> BlockAnd
         }
     }
 
-    fn break_or_continue<F>(&mut self,
-                            span: Span,
-                            label: Option<CodeExtent>,
-                            block: BasicBlock,
-                            exit_selector: F)
-                            -> BlockAnd<()>
-        where F: FnOnce(&mut LoopScope) -> BasicBlock
-    {
-        let (exit_block, extent) = {
-            let loop_scope = self.find_loop_scope(span, label);
-            (exit_selector(loop_scope), loop_scope.extent)
-        };
-        self.exit_scope(span, extent, block, exit_block);
-        self.cfg.start_new_block().unit()
-    }
-
 }
index d281b2a32d045619b08460aa394a904b8d2bb92e..5713ee45b9d8f4c5927285d84ea993567b1f7053 100644 (file)
@@ -38,7 +38,7 @@ pub struct Builder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
 
     /// the current set of loops; see the `scope` module for more
     /// details
-    loop_scopes: Vec<scope::LoopScope>,
+    loop_scopes: Vec<scope::LoopScope<'tcx>>,
 
     /// the vector of all scopes that we have created thus far;
     /// we track this for debuginfo later
index 4d9b6c0e05a4250345e82fc8277f8b2b863a642b..e5fac94a8a494eb2f344a6fb5ae6964b01cae69a 100644 (file)
@@ -177,7 +177,7 @@ struct FreeData<'tcx> {
 }
 
 #[derive(Clone, Debug)]
-pub struct LoopScope {
+pub struct LoopScope<'tcx> {
     /// Extent of the loop
     pub extent: CodeExtent,
     /// Where the body of the loop begins
@@ -185,8 +185,9 @@ pub struct LoopScope {
     /// Block to branch into when the loop terminates (either by being `break`-en out from, or by
     /// having its condition to become false)
     pub break_block: BasicBlock,
-    /// Indicates the reachability of the break_block for this loop
-    pub might_break: bool
+    /// The destination of the loop expression itself (i.e. where to put the result of a `break`
+    /// expression)
+    pub break_destination: Lvalue<'tcx>,
 }
 
 impl<'tcx> Scope<'tcx> {
@@ -246,10 +247,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     ///
     /// Returns the might_break attribute of the LoopScope used.
     pub fn in_loop_scope<F>(&mut self,
-                               loop_block: BasicBlock,
-                               break_block: BasicBlock,
-                               f: F)
-                               -> bool
+                            loop_block: BasicBlock,
+                            break_block: BasicBlock,
+                            break_destination: Lvalue<'tcx>,
+                            f: F)
         where F: FnOnce(&mut Builder<'a, 'gcx, 'tcx>)
     {
         let extent = self.extent_of_innermost_scope();
@@ -257,13 +258,12 @@ pub fn in_loop_scope<F>(&mut self,
             extent: extent.clone(),
             continue_block: loop_block,
             break_block: break_block,
-            might_break: false
+            break_destination: break_destination,
         };
         self.loop_scopes.push(loop_scope);
         f(self);
         let loop_scope = self.loop_scopes.pop().unwrap();
         assert!(loop_scope.extent == extent);
-        loop_scope.might_break
     }
 
     /// Convenience wrapper that pushes a scope and then executes `f`
@@ -386,7 +386,7 @@ pub fn new_visibility_scope(&mut self, span: Span) -> VisibilityScope {
     pub fn find_loop_scope(&mut self,
                            span: Span,
                            label: Option<CodeExtent>)
-                           -> &mut LoopScope {
+                           -> &mut LoopScope<'tcx> {
         let loop_scopes = &mut self.loop_scopes;
         match label {
             None => {
index 8a434cdff17e173a5e42dbc44833a6976cd233b3..6fa2672593587b2f0885fa08f4e1cc73e67ff58b 100644 (file)
@@ -558,8 +558,9 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         },
         hir::ExprRet(ref v) =>
             ExprKind::Return { value: v.to_ref() },
-        hir::ExprBreak(label) =>
-            ExprKind::Break { label: label.map(|_| loop_label(cx, expr)) },
+        hir::ExprBreak(label, ref value) =>
+            ExprKind::Break { label: label.map(|_| loop_label(cx, expr)),
+                              value: value.to_ref() },
         hir::ExprAgain(label) =>
             ExprKind::Continue { label: label.map(|_| loop_label(cx, expr)) },
         hir::ExprMatch(ref discr, ref arms, _) =>
@@ -572,7 +573,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         hir::ExprWhile(ref cond, ref body, _) =>
             ExprKind::Loop { condition: Some(cond.to_ref()),
                              body: block::to_expr_ref(cx, body) },
-        hir::ExprLoop(ref body, _) =>
+        hir::ExprLoop(ref body, _, _) =>
             ExprKind::Loop { condition: None,
                              body: block::to_expr_ref(cx, body) },
         hir::ExprField(ref source, name) => {
index e211334e5473ae5e43616916de6a189dc64f724e..50eee7723964e0cc18b346b9ba12e6420eb518dd 100644 (file)
@@ -202,6 +202,7 @@ pub enum ExprKind<'tcx> {
     },
     Break {
         label: Option<CodeExtent>,
+        value: Option<ExprRef<'tcx>>,
     },
     Continue {
         label: Option<CodeExtent>,
index 89c3efaafcdcc912af23a799d47c09b756b6eff9..a3916e7eca35104b8bbd246630ec45db25e85c06 100644 (file)
@@ -106,7 +106,7 @@ fn visit_expr(&mut self, expr: &Expr) {
             ExprKind::Loop(_, Some(ident)) |
             ExprKind::WhileLet(.., Some(ident)) |
             ExprKind::ForLoop(.., Some(ident)) |
-            ExprKind::Break(Some(ident)) |
+            ExprKind::Break(Some(ident), _) |
             ExprKind::Continue(Some(ident)) => {
                 self.check_label(ident.node, ident.span, expr.id);
             }
@@ -207,6 +207,13 @@ fn visit_item(&mut self, item: &Item) {
             ItemKind::Mod(_) => {
                 // Ensure that `path` attributes on modules are recorded as used (c.f. #35584).
                 attr::first_attr_value_str_by_name(&item.attrs, "path");
+                if let Some(attr) =
+                        item.attrs.iter().find(|attr| attr.name() == "warn_directory_ownership") {
+                    let lint = lint::builtin::LEGACY_DIRECTORY_OWNERSHIP;
+                    let msg = "cannot declare a new module at this location";
+                    self.session.add_lint(lint, item.id, item.span, msg.to_string());
+                    attr::mark_used(attr);
+                }
             }
             ItemKind::Union(ref vdata, _) => {
                 if !vdata.is_struct() {
index 5df8accd8cef13d024cf039be3a2b176e578c785..4d8520ed0440a1259fc0124ad9160bf27c2da03b 100644 (file)
@@ -610,7 +610,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node
         hir::ExprLoop(..) |
 
         // More control flow (also not very meaningful).
-        hir::ExprBreak(_) |
+        hir::ExprBreak(..) |
         hir::ExprAgain(_) |
         hir::ExprRet(_) |
 
index 89b8aa81411b381ed7b1de79470440acb81e2be0..b2ef1abd2a4e78eca2c7f6ad44737a4538bfefff 100644 (file)
@@ -228,4 +228,5 @@ pub fn foo() {}
 register_diagnostics! {
     E0472, // asm! is unsupported on this target
     E0561, // patterns aren't allowed in function pointer types
+    E0571, // `break` with a value in a non-`loop`-loop
 }
index 724100e02237f74304c0f79ab1188df519e37b58..c909e75afc1f579c5328a528266d3dbd035005e3 100644 (file)
 use rustc::session::Session;
 
 use rustc::dep_graph::DepNode;
+use rustc::hir::def::{Def, DefMap};
 use rustc::hir::map::Map;
 use rustc::hir::intravisit::{self, Visitor};
 use rustc::hir;
 use syntax_pos::Span;
 
+#[derive(Clone, Copy, PartialEq)]
+enum LoopKind {
+    Loop(hir::LoopSource),
+    WhileLoop,
+}
+
+impl LoopKind {
+    fn name(self) -> &'static str {
+        match self {
+            LoopKind::Loop(hir::LoopSource::Loop) => "loop",
+            LoopKind::Loop(hir::LoopSource::WhileLet) => "while let",
+            LoopKind::Loop(hir::LoopSource::ForLoop) => "for",
+            LoopKind::WhileLoop => "while",
+        }
+    }
+}
+
 #[derive(Clone, Copy, PartialEq)]
 enum Context {
     Normal,
-    Loop,
+    Loop(LoopKind),
     Closure,
 }
 
 #[derive(Copy, Clone)]
-struct CheckLoopVisitor<'a> {
+struct CheckLoopVisitor<'a, 'ast: 'a> {
     sess: &'a Session,
+    def_map: &'a DefMap,
+    hir_map: &'a Map<'ast>,
     cx: Context,
 }
 
-pub fn check_crate(sess: &Session, map: &Map) {
+pub fn check_crate(sess: &Session, def_map: &DefMap, map: &Map) {
     let _task = map.dep_graph.in_task(DepNode::CheckLoops);
     let krate = map.krate();
     krate.visit_all_item_likes(&mut CheckLoopVisitor {
         sess: sess,
+        def_map: def_map,
+        hir_map: map,
         cx: Normal,
     }.as_deep_visitor());
 }
 
-impl<'a, 'v> Visitor<'v> for CheckLoopVisitor<'a> {
+impl<'a, 'ast, 'v> Visitor<'v> for CheckLoopVisitor<'a, 'ast> {
     fn visit_item(&mut self, i: &hir::Item) {
         self.with_context(Normal, |v| intravisit::walk_item(v, i));
     }
@@ -51,25 +73,62 @@ fn visit_impl_item(&mut self, i: &hir::ImplItem) {
     fn visit_expr(&mut self, e: &hir::Expr) {
         match e.node {
             hir::ExprWhile(ref e, ref b, _) => {
-                self.visit_expr(&e);
-                self.with_context(Loop, |v| v.visit_block(&b));
+                self.with_context(Loop(LoopKind::WhileLoop), |v| {
+                    v.visit_expr(&e);
+                    v.visit_block(&b);
+                });
             }
-            hir::ExprLoop(ref b, _) => {
-                self.with_context(Loop, |v| v.visit_block(&b));
+            hir::ExprLoop(ref b, _, source) => {
+                self.with_context(Loop(LoopKind::Loop(source)), |v| v.visit_block(&b));
             }
             hir::ExprClosure(.., ref b, _) => {
                 self.with_context(Closure, |v| v.visit_expr(&b));
             }
-            hir::ExprBreak(_) => self.require_loop("break", e.span),
+            hir::ExprBreak(ref opt_label, ref opt_expr) => {
+                if opt_expr.is_some() {
+                    let loop_kind = if opt_label.is_some() {
+                        let loop_def = self.def_map.get(&e.id).unwrap().full_def();
+                        if loop_def == Def::Err {
+                            None
+                        } else if let Def::Label(loop_id) = loop_def {
+                            Some(match self.hir_map.expect_expr(loop_id).node {
+                                hir::ExprWhile(..) => LoopKind::WhileLoop,
+                                hir::ExprLoop(_, _, source) => LoopKind::Loop(source),
+                                ref r => span_bug!(e.span,
+                                                   "break label resolved to a non-loop: {:?}", r),
+                            })
+                        } else {
+                            span_bug!(e.span, "break resolved to a non-label")
+                        }
+                    } else if let Loop(kind) = self.cx {
+                        Some(kind)
+                    } else {
+                        // `break` outside a loop - caught below
+                        None
+                    };
+                    match loop_kind {
+                        None | Some(LoopKind::Loop(hir::LoopSource::Loop)) => (),
+                        Some(kind) => {
+                            struct_span_err!(self.sess, e.span, E0571,
+                                             "`break` with value from a `{}` loop",
+                                             kind.name())
+                                .span_label(e.span,
+                                            &format!("can only break with a value inside `loop`"))
+                                .emit();
+                        }
+                    }
+                }
+                self.require_loop("break", e.span);
+            }
             hir::ExprAgain(_) => self.require_loop("continue", e.span),
             _ => intravisit::walk_expr(self, e),
         }
     }
 }
 
-impl<'a> CheckLoopVisitor<'a> {
+impl<'a, 'ast> CheckLoopVisitor<'a, 'ast> {
     fn with_context<F>(&mut self, cx: Context, f: F)
-        where F: FnOnce(&mut CheckLoopVisitor<'a>)
+        where F: FnOnce(&mut CheckLoopVisitor<'a, 'ast>)
     {
         let old_cx = self.cx;
         self.cx = cx;
@@ -79,7 +138,7 @@ fn with_context<F>(&mut self, cx: Context, f: F)
 
     fn require_loop(&self, name: &str, span: Span) {
         match self.cx {
-            Loop => {}
+            Loop(_) => {}
             Closure => {
                 struct_span_err!(self.sess, span, E0267, "`{}` inside of a closure", name)
                 .span_label(span, &format!("cannot break inside of a closure"))
index f30304f2ea42bea61c4ca4e105c273d15f91400d..30d25c7ccecdd162a17933e456d7a03bb29fd660 100644 (file)
@@ -3074,22 +3074,25 @@ fn resolve_expr(&mut self, expr: &Expr, parent: Option<&Expr>) {
                 visit::walk_expr(self, expr);
             }
 
-            ExprKind::Break(Some(label)) | ExprKind::Continue(Some(label)) => {
+            ExprKind::Break(Some(label), _) | ExprKind::Continue(Some(label)) => {
                 match self.search_label(label.node) {
                     None => {
                         self.record_def(expr.id, err_path_resolution());
                         resolve_error(self,
                                       label.span,
-                                      ResolutionError::UndeclaredLabel(&label.node.name.as_str()))
+                                      ResolutionError::UndeclaredLabel(&label.node.name.as_str()));
                     }
                     Some(def @ Def::Label(_)) => {
                         // Since this def is a label, it is never read.
-                        self.record_def(expr.id, PathResolution::new(def))
+                        self.record_def(expr.id, PathResolution::new(def));
                     }
                     Some(_) => {
-                        span_bug!(expr.span, "label wasn't mapped to a label def!")
+                        span_bug!(expr.span, "label wasn't mapped to a label def!");
                     }
                 }
+
+                // visit `break` argument if any
+                visit::walk_expr(self, expr);
             }
 
             ExprKind::IfLet(ref pattern, ref subexpression, ref if_block, ref optional_else) => {
index 87b2b88fe33fccb7dac9494aecc7a86ac805cf97..53b05051deb6e78a6f2f85c2acb01b1815e92a00 100644 (file)
@@ -276,7 +276,7 @@ fn write_sub_path_trait_truncated(&mut self, path: &ast::Path) {
     fn lookup_def_id(&self, ref_id: NodeId) -> Option<DefId> {
         self.tcx.expect_def_or_none(ref_id).and_then(|def| {
             match def {
-                Def::PrimTy(..) | Def::SelfTy(..) => None,
+                Def::Label(..) | Def::PrimTy(..) | Def::SelfTy(..) | Def::Err => None,
                 def => Some(def.def_id()),
             }
         })
@@ -358,7 +358,10 @@ fn process_formals(&mut self, formals: &Vec<ast::Arg>, qualname: &str) {
             collector.visit_pat(&arg.pat);
             let span_utils = self.span.clone();
             for &(id, ref p, ..) in &collector.collected_paths {
-                let typ = self.tcx.tables().node_types.get(&id).unwrap().to_string();
+                let typ = match self.tcx.tables().node_types.get(&id) {
+                    Some(s) => s.to_string(),
+                    None => continue,
+                };
                 // 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 = span_utils.span_for_last_ident(p.span);
@@ -988,7 +991,13 @@ fn process_pat(&mut self, p: &ast::Pat) {
         match p.node {
             PatKind::Struct(ref path, ref fields, _) => {
                 visit::walk_path(self, path);
-                let adt = self.tcx.tables().node_id_to_type(p.id).ty_adt_def().unwrap();
+                let adt = match self.tcx.tables().node_id_to_type_opt(p.id) {
+                    Some(ty) => ty.ty_adt_def().unwrap(),
+                    None => {
+                        visit::walk_pat(self, p);
+                        return;
+                    }
+                };
                 let variant = adt.variant_of_def(self.tcx.expect_def(p.id));
 
                 for &Spanned { node: ref field, span } in fields {
@@ -1354,7 +1363,13 @@ fn visit_expr(&mut self, ex: &ast::Expr) {
             }
             ast::ExprKind::Struct(ref path, ref fields, ref base) => {
                 let hir_expr = self.save_ctxt.tcx.map.expect_expr(ex.id);
-                let adt = self.tcx.tables().expr_ty(&hir_expr).ty_adt_def().unwrap();
+                let adt = match self.tcx.tables().expr_ty_opt(&hir_expr) {
+                    Some(ty) => ty.ty_adt_def().unwrap(),
+                    None => {
+                        visit::walk_expr(self, ex);
+                        return;
+                    }
+                };
                 let def = self.tcx.expect_def(hir_expr.id);
                 self.process_struct_lit(ex, path, fields, adt.variant_of_def(def), base)
             }
@@ -1380,7 +1395,13 @@ fn visit_expr(&mut self, ex: &ast::Expr) {
                         return;
                     }
                 };
-                let ty = &self.tcx.tables().expr_ty_adjusted(&hir_node).sty;
+                let ty = match self.tcx.tables().expr_ty_adjusted_opt(&hir_node) {
+                    Some(ty) => &ty.sty,
+                    None => {
+                        visit::walk_expr(self, ex);
+                        return;
+                    }
+                };
                 match *ty {
                     ty::TyAdt(def, _) => {
                         let sub_span = self.span.sub_span_after_token(ex.span, token::Dot);
index bd5da588a864d2228f91eccabfc43e4000b9d2aa..3c6f67f0c88e1837a3767534bd88cbab11e4e6d7 100644 (file)
@@ -498,7 +498,12 @@ pub fn get_expr_data(&self, expr: &ast::Expr) -> Option<Data> {
     }
 
     pub fn get_path_data(&self, id: NodeId, path: &ast::Path) -> Option<Data> {
-        let def = self.tcx.expect_def(id);
+        let resolution = self.tcx.expect_resolution(id);
+        if resolution.depth != 0 {
+            return None;
+        }
+        let def = resolution.base_def;
+
         let sub_span = self.span_utils.span_for_last_ident(path.span);
         filter!(self.span_utils, sub_span, path.span, None);
         match def {
index c3340281d073254a08a9420dc5e34df0191e23cd..e091ba07d4feaffd7f76dae85eedb3934f8e362c 100644 (file)
@@ -247,6 +247,7 @@ fn generic_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
             // of the size.
             let size = size.bytes();
             let align = align.abi();
+            assert!(align <= std::u32::MAX as u64);
             let discr_ty = Type::from_integer(cx, discr);
             let discr_size = discr.size().bytes();
             let padded_discr_size = roundup(discr_size, align as u32);
index df8dd7750ae0ca69a7bffb994c91be56acf36097..11ab6dcaa87f99fa02a99fac8d9068d8c462d2c1 100644 (file)
@@ -231,7 +231,7 @@ pub fn build(&mut self) {
     }
 
     fn llvm_archive_kind(&self) -> Result<ArchiveKind, &str> {
-        let kind = &self.config.sess.target.target.options.archive_format[..];
+        let kind = &*self.config.sess.target.target.options.archive_format;
         kind.parse().map_err(|_| kind)
     }
 
index d0339775a78a1e7f72c09b60a67f100038781aca..648dc4c24c9a658c79426f2b53d2f5c707ca7f6a 100644 (file)
@@ -19,7 +19,7 @@
 use session::filesearch;
 use session::search_paths::PathKind;
 use session::Session;
-use middle::cstore::{self, LinkMeta, NativeLibrary};
+use middle::cstore::{self, LinkMeta, NativeLibrary, LibSource};
 use middle::cstore::{LinkagePreference, NativeLibraryKind};
 use middle::dependency_format::Linkage;
 use CrateTranslation;
@@ -124,7 +124,6 @@ pub fn find_crate_name(sess: Option<&Session>,
     }
 
     "rust_out".to_string()
-
 }
 
 pub fn build_link_meta(incremental_hashes_map: &IncrementalHashesMap,
@@ -264,6 +263,9 @@ pub fn filename_for_input(sess: &Session,
         config::CrateTypeRlib => {
             outputs.out_directory.join(&format!("lib{}.rlib", libname))
         }
+        config::CrateTypeMetadata => {
+            outputs.out_directory.join(&format!("lib{}.rmeta", libname))
+        }
         config::CrateTypeCdylib |
         config::CrateTypeProcMacro |
         config::CrateTypeDylib => {
@@ -299,7 +301,7 @@ pub fn each_linked_rlib(sess: &Session,
                    .or_else(|| fmts.get(&config::CrateTypeCdylib))
                    .or_else(|| fmts.get(&config::CrateTypeProcMacro));
     let fmts = fmts.unwrap_or_else(|| {
-        bug!("could not find formats for rlibs")
+        bug!("could not find formats for rlibs");
     });
     for (cnum, path) in crates {
         match fmts[cnum.as_usize() - 1] {
@@ -308,8 +310,12 @@ pub fn each_linked_rlib(sess: &Session,
         }
         let name = sess.cstore.crate_name(cnum).clone();
         let path = match path {
-            Some(p) => p,
-            None => {
+            LibSource::Some(p) => p,
+            LibSource::MetadataOnly => {
+                sess.fatal(&format!("could not find rlib for: `{}`, found rmeta (metadata) file",
+                                    name));
+            }
+            LibSource::None => {
                 sess.fatal(&format!("could not find rlib for: `{}`", name));
             }
         };
@@ -353,6 +359,9 @@ fn link_binary_output(sess: &Session,
         config::CrateTypeStaticlib => {
             link_staticlib(sess, &objects, &out_filename, tmpdir.path());
         }
+        config::CrateTypeMetadata => {
+            emit_metadata(sess, trans, &out_filename);
+        }
         _ => {
             link_natively(sess, crate_type, &objects, &out_filename, trans,
                           outputs, tmpdir.path());
@@ -391,6 +400,13 @@ fn archive_config<'a>(sess: &'a Session,
     }
 }
 
+fn emit_metadata<'a>(sess: &'a Session, trans: &CrateTranslation, out_filename: &Path) {
+    let result = fs::File::create(out_filename).and_then(|mut f| f.write_all(&trans.metadata));
+    if let Err(e) = result {
+        sess.fatal(&format!("failed to write {}: {}", out_filename.display(), e));
+    }
+}
+
 // Create an 'rlib'
 //
 // An rlib in its current incarnation is essentially a renamed .a file. The
@@ -404,6 +420,7 @@ fn link_rlib<'a>(sess: &'a Session,
                  tmpdir: &Path) -> ArchiveBuilder<'a> {
     info!("preparing rlib from {:?} to {:?}", objects, out_filename);
     let mut ab = ArchiveBuilder::new(archive_config(sess, out_filename, None));
+
     for obj in objects {
         ab.add_file(obj);
     }
@@ -465,15 +482,7 @@ fn link_rlib<'a>(sess: &'a Session,
             // here so concurrent builds in the same directory don't try to use
             // the same filename for metadata (stomping over one another)
             let metadata = tmpdir.join(sess.cstore.metadata_filename());
-            match fs::File::create(&metadata).and_then(|mut f| {
-                f.write_all(&trans.metadata)
-            }) {
-                Ok(..) => {}
-                Err(e) => {
-                    sess.fatal(&format!("failed to write {}: {}",
-                                        metadata.display(), e));
-                }
-            }
+            emit_metadata(sess, trans, &metadata);
             ab.add_file(&metadata);
 
             // For LTO purposes, the bytecode of this library is also inserted
index 8758cdcf9d0ab63928ef1100381060561773bb1f..ccaa0d4e1b1b059de8214d48454ea049d7897eac 100644 (file)
 use std::fs;
 
 use rustc::hir::def_id::CrateNum;
+use rustc::middle::cstore::LibSource;
 
 pub struct RPathConfig<'a> {
-    pub used_crates: Vec<(CrateNum, Option<PathBuf>)>,
+    pub used_crates: Vec<(CrateNum, LibSource)>,
     pub out_filename: PathBuf,
     pub is_like_osx: bool,
     pub has_rpath: bool,
@@ -35,7 +36,7 @@ pub fn get_rpath_flags(config: &mut RPathConfig) -> Vec<String> {
     debug!("preparing the RPATH!");
 
     let libs = config.used_crates.clone();
-    let libs = libs.into_iter().filter_map(|(_, l)| l).collect::<Vec<_>>();
+    let libs = libs.into_iter().filter_map(|(_, l)| l.option()).collect::<Vec<_>>();
     let rpaths = get_rpaths(config, &libs[..]);
     flags.extend_from_slice(&rpaths_to_flags(&rpaths[..]));
 
index 78a676d30337c1e113c440ffc0ad6d1a8cdb8114..d697a5bafb79ed5a6d9503fb88269c5fdb6fabab 100644 (file)
@@ -47,7 +47,7 @@
 use rustc::util::common::time;
 use session::config::{self, NoDebugInfo};
 use rustc_incremental::IncrementalHashesMap;
-use session::Session;
+use session::{self, DataTypeKind, Session};
 use abi::{self, Abi, FnType};
 use adt;
 use attributes;
@@ -93,6 +93,7 @@
 use syntax_pos::{Span, DUMMY_SP};
 use syntax::attr;
 use rustc::hir;
+use rustc::ty::layout::{self, Layout};
 use syntax::ast;
 
 thread_local! {
@@ -1260,7 +1261,8 @@ enum MetadataKind {
             config::CrateTypeStaticlib |
             config::CrateTypeCdylib => MetadataKind::None,
 
-            config::CrateTypeRlib => MetadataKind::Uncompressed,
+            config::CrateTypeRlib |
+            config::CrateTypeMetadata => MetadataKind::Uncompressed,
 
             config::CrateTypeDylib |
             config::CrateTypeProcMacro => MetadataKind::Compressed,
@@ -1600,7 +1602,8 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     assert_module_sources::assert_module_sources(tcx, &modules);
 
     // Skip crate items and just output metadata in -Z no-trans mode.
-    if tcx.sess.opts.debugging_opts.no_trans {
+    if tcx.sess.opts.debugging_opts.no_trans ||
+       tcx.sess.crate_types.borrow().iter().all(|ct| ct == &config::CrateTypeMetadata) {
         let linker_info = LinkerInfo::new(&shared_ccx, &[]);
         return CrateTranslation {
             modules: modules,
@@ -1739,6 +1742,10 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                               .collect())
     });
 
+    if tcx.sess.opts.debugging_opts.print_type_sizes {
+        gather_type_sizes(tcx);
+    }
+
     if sess.target.target.options.is_like_msvc &&
        sess.crate_types.borrow().iter().any(|ct| *ct == config::CrateTypeRlib) {
         create_imps(&crate_context_list);
@@ -1769,6 +1776,192 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     }
 }
 
+fn gather_type_sizes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
+    let layout_cache = tcx.layout_cache.borrow();
+    for (ty, layout) in layout_cache.iter() {
+
+        // (delay format until we actually need it)
+        let record = |kind, opt_discr_size, variants| {
+            let type_desc = format!("{:?}", ty);
+            let overall_size = layout.size(&tcx.data_layout);
+            let align = layout.align(&tcx.data_layout);
+            tcx.sess.code_stats.borrow_mut().record_type_size(kind,
+                                                              type_desc,
+                                                              align,
+                                                              overall_size,
+                                                              opt_discr_size,
+                                                              variants);
+        };
+
+        let (adt_def, substs) = match ty.sty {
+            ty::TyAdt(ref adt_def, substs) => {
+                debug!("print-type-size t: `{:?}` process adt", ty);
+                (adt_def, substs)
+            }
+
+            ty::TyClosure(..) => {
+                debug!("print-type-size t: `{:?}` record closure", ty);
+                record(DataTypeKind::Closure, None, vec![]);
+                continue;
+            }
+
+            _ => {
+                debug!("print-type-size t: `{:?}` skip non-nominal", ty);
+                continue;
+            }
+        };
+
+        let adt_kind = adt_def.adt_kind();
+
+        let build_field_info = |(field_name, field_ty): (ast::Name, Ty), offset: &layout::Size| {
+            match layout_cache.get(&field_ty) {
+                None => bug!("no layout found for field {} type: `{:?}`", field_name, field_ty),
+                Some(field_layout) => {
+                    session::FieldInfo {
+                        name: field_name.to_string(),
+                        offset: offset.bytes(),
+                        size: field_layout.size(&tcx.data_layout).bytes(),
+                        align: field_layout.align(&tcx.data_layout).abi(),
+                    }
+                }
+            }
+        };
+
+        let build_primitive_info = |name: ast::Name, value: &layout::Primitive| {
+            session::VariantInfo {
+                name: Some(name.to_string()),
+                kind: session::SizeKind::Exact,
+                align: value.align(&tcx.data_layout).abi(),
+                size: value.size(&tcx.data_layout).bytes(),
+                fields: vec![],
+            }
+        };
+
+        enum Fields<'a> {
+            WithDiscrim(&'a layout::Struct),
+            NoDiscrim(&'a layout::Struct),
+        }
+
+        let build_variant_info = |n: Option<ast::Name>, flds: &[(ast::Name, Ty)], layout: Fields| {
+            let (s, field_offsets) = match layout {
+                Fields::WithDiscrim(s) => (s, &s.offsets[1..]),
+                Fields::NoDiscrim(s) => (s, &s.offsets[0..]),
+            };
+            let field_info: Vec<_> = flds.iter()
+                .zip(field_offsets.iter())
+                .map(|(&field_name_ty, offset)| build_field_info(field_name_ty, offset))
+                .collect();
+
+            session::VariantInfo {
+                name: n.map(|n|n.to_string()),
+                kind: if s.sized {
+                    session::SizeKind::Exact
+                } else {
+                    session::SizeKind::Min
+                },
+                align: s.align.abi(),
+                size: s.min_size.bytes(),
+                fields: field_info,
+            }
+        };
+
+        match **layout {
+            Layout::StructWrappedNullablePointer { nonnull: ref variant_layout,
+                                                   nndiscr,
+                                                   discrfield: _ } => {
+                debug!("print-type-size t: `{:?}` adt struct-wrapped nullable nndiscr {} is {:?}",
+                       ty, nndiscr, variant_layout);
+                let variant_def = &adt_def.variants[nndiscr as usize];
+                let fields: Vec<_> = variant_def.fields.iter()
+                    .map(|field_def| (field_def.name, field_def.ty(tcx, substs)))
+                    .collect();
+                record(adt_kind.into(),
+                       None,
+                       vec![build_variant_info(Some(variant_def.name),
+                                               &fields,
+                                               Fields::NoDiscrim(variant_layout))]);
+            }
+            Layout::RawNullablePointer { nndiscr, value } => {
+                debug!("print-type-size t: `{:?}` adt raw nullable nndiscr {} is {:?}",
+                       ty, nndiscr, value);
+                let variant_def = &adt_def.variants[nndiscr as usize];
+                record(adt_kind.into(), None,
+                       vec![build_primitive_info(variant_def.name, &value)]);
+            }
+            Layout::Univariant { variant: ref variant_layout, non_zero: _ } => {
+                let variant_names = || {
+                    adt_def.variants.iter().map(|v|format!("{}", v.name)).collect::<Vec<_>>()
+                };
+                debug!("print-type-size t: `{:?}` adt univariant {:?} variants: {:?}",
+                       ty, variant_layout, variant_names());
+                assert!(adt_def.variants.len() <= 1,
+                        "univariant with variants {:?}", variant_names());
+                if adt_def.variants.len() == 1 {
+                    let variant_def = &adt_def.variants[0];
+                    let fields: Vec<_> = variant_def.fields.iter()
+                        .map(|field_def| (field_def.name, field_def.ty(tcx, substs)))
+                        .collect();
+                    record(adt_kind.into(),
+                           None,
+                           vec![build_variant_info(Some(variant_def.name),
+                                                   &fields,
+                                                   Fields::NoDiscrim(variant_layout))]);
+                } else {
+                    // (This case arises for *empty* enums; so give it
+                    // zero variants.)
+                    record(adt_kind.into(), None, vec![]);
+                }
+            }
+
+            Layout::General { ref variants, discr, .. } => {
+                debug!("print-type-size t: `{:?}` adt general variants def {} layouts {} {:?}",
+                       ty, adt_def.variants.len(), variants.len(), variants);
+                let variant_infos: Vec<_> = adt_def.variants.iter()
+                    .zip(variants.iter())
+                    .map(|(variant_def, variant_layout)| {
+                        let fields: Vec<_> = variant_def.fields.iter()
+                            .map(|field_def| (field_def.name, field_def.ty(tcx, substs)))
+                            .collect();
+                        build_variant_info(Some(variant_def.name),
+                                           &fields,
+                                           Fields::WithDiscrim(variant_layout))
+                    })
+                    .collect();
+                record(adt_kind.into(), Some(discr.size()), variant_infos);
+            }
+
+            Layout::UntaggedUnion { ref variants } => {
+                debug!("print-type-size t: `{:?}` adt union variants {:?}",
+                       ty, variants);
+                // layout does not currently store info about each
+                // variant...
+                record(adt_kind.into(), None, Vec::new());
+            }
+
+            Layout::CEnum { discr, .. } => {
+                debug!("print-type-size t: `{:?}` adt c-like enum", ty);
+                let variant_infos: Vec<_> = adt_def.variants.iter()
+                    .map(|variant_def| {
+                        build_primitive_info(variant_def.name,
+                                             &layout::Primitive::Int(discr))
+                    })
+                    .collect();
+                record(adt_kind.into(), Some(discr.size()), variant_infos);
+            }
+
+            // other cases provide little interesting (i.e. adjustable
+            // via representation tweaks) size info beyond total size.
+            Layout::Scalar { .. } |
+            Layout::Vector { .. } |
+            Layout::Array { .. } |
+            Layout::FatPointer { .. } => {
+                debug!("print-type-size t: `{:?}` adt other", ty);
+                record(adt_kind.into(), None, Vec::new())
+            }
+        }
+    }
+}
+
 /// For each CGU, identify if we can reuse an existing object file (or
 /// maybe other context).
 fn trans_reuse_previous_work_products(tcx: TyCtxt,
index 548f37cea06bcf9a2415c62a3533e4d091804b4c..3ffbbd1be80160acae8a304f4972be13661faba2 100644 (file)
@@ -17,7 +17,6 @@
 use rustc::{infer, traits};
 use rustc::ty::{self, LvaluePreference, Ty};
 use syntax::symbol::Symbol;
-use syntax::ptr::P;
 use syntax_pos::Span;
 
 use rustc::hir;
@@ -46,7 +45,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     pub fn check_call(&self,
                       call_expr: &'gcx hir::Expr,
                       callee_expr: &'gcx hir::Expr,
-                      arg_exprs: &'gcx [P<hir::Expr>],
+                      arg_exprs: &'gcx [hir::Expr],
                       expected: Expectation<'tcx>)
                       -> Ty<'tcx> {
         let original_callee_ty = self.check_expr(callee_expr);
@@ -189,7 +188,7 @@ fn try_overloaded_call_traits(&self,
     fn confirm_builtin_call(&self,
                             call_expr: &hir::Expr,
                             callee_ty: Ty<'tcx>,
-                            arg_exprs: &'gcx [P<hir::Expr>],
+                            arg_exprs: &'gcx [hir::Expr],
                             expected: Expectation<'tcx>)
                             -> Ty<'tcx> {
         let error_fn_sig;
@@ -272,7 +271,7 @@ fn confirm_builtin_call(&self,
 
     fn confirm_deferred_closure_call(&self,
                                      call_expr: &hir::Expr,
-                                     arg_exprs: &'gcx [P<hir::Expr>],
+                                     arg_exprs: &'gcx [hir::Expr],
                                      expected: Expectation<'tcx>,
                                      fn_sig: ty::FnSig<'tcx>)
                                      -> Ty<'tcx> {
@@ -299,7 +298,7 @@ fn confirm_deferred_closure_call(&self,
     fn confirm_overloaded_call(&self,
                                call_expr: &hir::Expr,
                                callee_expr: &'gcx hir::Expr,
-                               arg_exprs: &'gcx [P<hir::Expr>],
+                               arg_exprs: &'gcx [hir::Expr],
                                expected: Expectation<'tcx>,
                                method_callee: ty::MethodCallee<'tcx>)
                                -> Ty<'tcx> {
index 4edf0011cb39044d8ed60620ab41a82967879095..5839c606566c31c73ea834d54d3615d7f840a755 100644 (file)
@@ -102,6 +102,7 @@ enum CastError {
     /// Cast of thin to fat raw ptr (eg. `*const () as *const [u8]`)
     SizedUnsizedCast,
     IllegalCast,
+    NeedDeref,
     NeedViaPtr,
     NeedViaThinPtr,
     NeedViaInt,
@@ -138,6 +139,25 @@ pub fn new(fcx: &FnCtxt<'a, 'gcx, 'tcx>,
 
     fn report_cast_error(&self, fcx: &FnCtxt<'a, 'gcx, 'tcx>, e: CastError) {
         match e {
+            CastError::NeedDeref => {
+                let cast_ty = fcx.ty_to_string(self.cast_ty);
+                let mut err = fcx.type_error_struct(self.cast_span,
+                                       |actual| {
+                                           format!("casting `{}` as `{}` is invalid",
+                                                   actual,
+                                                   cast_ty)
+                                       },
+                                       self.expr_ty);
+                err.span_label(self.expr.span,
+                               &format!("cannot cast `{}` as `{}`",
+                                        fcx.ty_to_string(self.expr_ty),
+                                        cast_ty));
+                if let Ok(snippet) = fcx.sess().codemap().span_to_snippet(self.expr.span) {
+                    err.span_label(self.expr.span,
+                                   &format!("did you mean `*{}`?", snippet));
+                }
+                err.emit();
+            }
             CastError::NeedViaThinPtr |
             CastError::NeedViaPtr => {
                 let mut err = fcx.type_error_struct(self.span,
@@ -390,8 +410,28 @@ fn do_check(&self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) -> Result<CastKind, CastError>
             (Ptr(m_e), Ptr(m_c)) => self.check_ptr_ptr_cast(fcx, m_e, m_c), // ptr-ptr-cast
             (Ptr(m_expr), Int(_)) => self.check_ptr_addr_cast(fcx, m_expr), // ptr-addr-cast
             (FnPtr, Int(_)) => Ok(CastKind::FnPtrAddrCast),
-            (RPtr(_), Int(_)) |
-            (RPtr(_), Float) => Err(CastError::NeedViaPtr),
+            (RPtr(p), Int(_)) |
+            (RPtr(p), Float) => {
+                match p.ty.sty {
+                    ty::TypeVariants::TyInt(_) |
+                    ty::TypeVariants::TyUint(_) |
+                    ty::TypeVariants::TyFloat(_) => {
+                        Err(CastError::NeedDeref)
+                    }
+                    ty::TypeVariants::TyInfer(t) => {
+                        match t {
+                            ty::InferTy::IntVar(_) |
+                            ty::InferTy::FloatVar(_) |
+                            ty::InferTy::FreshIntTy(_) |
+                            ty::InferTy::FreshFloatTy(_) => {
+                                Err(CastError::NeedDeref)
+                            }
+                            _ => Err(CastError::NeedViaPtr),
+                        }
+                    }
+                    _ => Err(CastError::NeedViaPtr),
+                }
+            }
             // * -> ptr
             (Int(_), Ptr(mt)) => self.check_addr_ptr_cast(fcx, mt), // addr-ptr-cast
             (FnPtr, Ptr(mt)) => self.check_fptr_ptr_cast(fcx, mt),
index 734aa99dbeafafb99582f6880c72fae5b63f0b22..eeb7bb287002f7ffb32a93718ff8b2943a667a37 100644 (file)
 use CrateCtxt;
 use TypeAndSubsts;
 use lint;
-use util::common::{block_query, ErrorReported, indenter, loop_query};
+use util::common::{ErrorReported, indenter};
 use util::nodemap::{DefIdMap, FxHashMap, FxHashSet, NodeMap};
 
 use std::cell::{Cell, Ref, RefCell};
@@ -407,6 +407,34 @@ fn always(self) -> bool {
     }
 }
 
+#[derive(Clone)]
+pub struct LoopCtxt<'gcx, 'tcx> {
+    unified: Ty<'tcx>,
+    coerce_to: Ty<'tcx>,
+    break_exprs: Vec<&'gcx hir::Expr>,
+    may_break: bool,
+}
+
+#[derive(Clone)]
+pub struct EnclosingLoops<'gcx, 'tcx> {
+    stack: Vec<LoopCtxt<'gcx, 'tcx>>,
+    by_id: NodeMap<usize>,
+}
+
+impl<'gcx, 'tcx> EnclosingLoops<'gcx, 'tcx> {
+    fn find_loop(&mut self, id: Option<ast::NodeId>) -> Option<&mut LoopCtxt<'gcx, 'tcx>> {
+        if let Some(id) = id {
+            if let Some(ix) = self.by_id.get(&id).cloned() {
+                Some(&mut self.stack[ix])
+            } else {
+                None
+            }
+        } else {
+            self.stack.last_mut()
+        }
+    }
+}
+
 #[derive(Clone)]
 pub struct FnCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     ast_ty_to_ty_cache: RefCell<NodeMap<Ty<'tcx>>>,
@@ -433,6 +461,8 @@ pub struct FnCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     /// Whether any child nodes have any type errors.
     has_errors: Cell<bool>,
 
+    enclosing_loops: RefCell<EnclosingLoops<'gcx, 'tcx>>,
+
     inh: &'a Inherited<'a, 'gcx, 'tcx>,
 }
 
@@ -1503,6 +1533,10 @@ pub fn new(inh: &'a Inherited<'a, 'gcx, 'tcx>,
                                                      ast::CRATE_NODE_ID)),
             diverges: Cell::new(Diverges::Maybe),
             has_errors: Cell::new(false),
+            enclosing_loops: RefCell::new(EnclosingLoops {
+                stack: Vec::new(),
+                by_id: NodeMap(),
+            }),
             inh: inh,
         }
     }
@@ -2409,7 +2443,7 @@ fn check_method_argument_types(&self,
                                    sp: Span,
                                    method_fn_ty: Ty<'tcx>,
                                    callee_expr: &'gcx hir::Expr,
-                                   args_no_rcvr: &'gcx [P<hir::Expr>],
+                                   args_no_rcvr: &'gcx [hir::Expr],
                                    tuple_arguments: TupleArgumentsFlag,
                                    expected: Expectation<'tcx>)
                                    -> Ty<'tcx> {
@@ -2448,7 +2482,7 @@ fn check_argument_types(&self,
                             sp: Span,
                             fn_inputs: &[Ty<'tcx>],
                             expected_arg_tys: &[Ty<'tcx>],
-                            args: &'gcx [P<hir::Expr>],
+                            args: &'gcx [hir::Expr],
                             variadic: bool,
                             tuple_arguments: TupleArgumentsFlag) {
         let tcx = self.tcx;
@@ -2822,7 +2856,7 @@ fn expected_types_for_fn_args(&self,
     fn check_method_call(&self,
                          expr: &'gcx hir::Expr,
                          method_name: Spanned<ast::Name>,
-                         args: &'gcx [P<hir::Expr>],
+                         args: &'gcx [hir::Expr],
                          tps: &[P<hir::Ty>],
                          expected: Expectation<'tcx>,
                          lvalue_pref: LvaluePreference) -> Ty<'tcx> {
@@ -3584,7 +3618,74 @@ fn check_expr_kind(&self,
               }
               tcx.mk_nil()
           }
-          hir::ExprBreak(_) => { tcx.types.never }
+          hir::ExprBreak(ref label_opt, ref expr_opt) => {
+            let loop_id = if label_opt.is_some() {
+                let loop_def = tcx.expect_def(expr.id);
+                if let Def::Label(loop_id) = loop_def {
+                    Some(Some(loop_id))
+                } else if loop_def == Def::Err {
+                    // an error was already printed, so just ignore it
+                    None
+                } else {
+                    span_bug!(expr.span, "break label resolved to a non-label");
+                }
+            } else {
+                Some(None)
+            };
+            if let Some(loop_id) = loop_id {
+                let coerce_to = {
+                    let mut enclosing_loops = self.enclosing_loops.borrow_mut();
+                    enclosing_loops.find_loop(loop_id).map(|ctxt| ctxt.coerce_to)
+                };
+                if let Some(coerce_to) = coerce_to {
+                    let e_ty;
+                    let cause;
+                    if let Some(ref e) = *expr_opt {
+                        // Recurse without `enclosing_loops` borrowed.
+                        e_ty = self.check_expr_with_hint(e, coerce_to);
+                        cause = self.misc(e.span);
+                        // Notably, the recursive call may alter coerce_to - must not keep using it!
+                    } else {
+                        // `break` without argument acts like `break ()`.
+                        e_ty = tcx.mk_nil();
+                        cause = self.misc(expr.span);
+                    }
+                    let mut enclosing_loops = self.enclosing_loops.borrow_mut();
+                    let ctxt = enclosing_loops.find_loop(loop_id).unwrap();
+
+                    let result = if let Some(ref e) = *expr_opt {
+                        // Special-case the first element, as it has no "previous expressions".
+                        let result = if !ctxt.may_break {
+                            self.try_coerce(e, e_ty, ctxt.coerce_to)
+                        } else {
+                            self.try_find_coercion_lub(&cause, || ctxt.break_exprs.iter().cloned(),
+                                                       ctxt.unified, e, e_ty)
+                        };
+
+                        ctxt.break_exprs.push(e);
+                        result
+                    } else {
+                        self.eq_types(true, &cause, e_ty, ctxt.unified)
+                            .map(|InferOk { obligations, .. }| {
+                                // FIXME(#32730) propagate obligations
+                                assert!(obligations.is_empty());
+                                e_ty
+                            })
+                    };
+                    match result {
+                        Ok(ty) => ctxt.unified = ty,
+                        Err(err) => {
+                            self.report_mismatched_types(&cause, ctxt.unified, e_ty, err);
+                        }
+                    }
+
+                    ctxt.may_break = true;
+                }
+                // Otherwise, we failed to find the enclosing loop; this can only happen if the
+                // `break` was not inside a loop at all, which is caught by the loop-checking pass.
+            }
+            tcx.types.never
+          }
           hir::ExprAgain(_) => { tcx.types.never }
           hir::ExprRet(ref expr_opt) => {
             if let Some(ref e) = *expr_opt {
@@ -3635,12 +3736,22 @@ fn check_expr_kind(&self,
                                  expr.span, expected)
           }
           hir::ExprWhile(ref cond, ref body, _) => {
-            self.check_expr_has_type(&cond, tcx.types.bool);
-            let cond_diverging = self.diverges.get();
-            self.check_block_no_value(&body);
+            let unified = self.tcx.mk_nil();
+            let coerce_to = unified;
+            let ctxt = LoopCtxt {
+                unified: unified,
+                coerce_to: coerce_to,
+                break_exprs: vec![],
+                may_break: true,
+            };
+            self.with_loop_ctxt(expr.id, ctxt, || {
+                self.check_expr_has_type(&cond, tcx.types.bool);
+                let cond_diverging = self.diverges.get();
+                self.check_block_no_value(&body);
 
-            // We may never reach the body so it diverging means nothing.
-            self.diverges.set(cond_diverging);
+                // We may never reach the body so it diverging means nothing.
+                self.diverges.set(cond_diverging);
+            });
 
             if self.has_errors.get() {
                 tcx.types.err
@@ -3648,14 +3759,25 @@ fn check_expr_kind(&self,
                 tcx.mk_nil()
             }
           }
-          hir::ExprLoop(ref body, _) => {
-            self.check_block_no_value(&body);
-            if may_break(tcx, expr.id, &body) {
+          hir::ExprLoop(ref body, _, _) => {
+            let unified = self.next_ty_var();
+            let coerce_to = expected.only_has_type(self).unwrap_or(unified);
+            let ctxt = LoopCtxt {
+                unified: unified,
+                coerce_to: coerce_to,
+                break_exprs: vec![],
+                may_break: false,
+            };
+
+            let ctxt = self.with_loop_ctxt(expr.id, ctxt, || {
+                self.check_block_no_value(&body);
+            });
+            if ctxt.may_break {
                 // No way to know whether it's diverging because
                 // of a `break` or an outer `break` or `return.
                 self.diverges.set(Diverges::Maybe);
 
-                tcx.mk_nil()
+                ctxt.unified
             } else {
                 tcx.types.never
             }
@@ -3670,10 +3792,10 @@ fn check_expr_kind(&self,
             self.check_block_with_expected(&b, expected)
           }
           hir::ExprCall(ref callee, ref args) => {
-              self.check_call(expr, &callee, &args[..], expected)
+              self.check_call(expr, &callee, args, expected)
           }
           hir::ExprMethodCall(name, ref tps, ref args) => {
-              self.check_method_call(expr, name, &args[..], &tps[..], expected, lvalue_pref)
+              self.check_method_call(expr, name, args, &tps[..], expected, lvalue_pref)
           }
           hir::ExprCast(ref e, ref t) => {
             if let hir::TyArray(_, ref count_expr) = t.node {
@@ -3728,7 +3850,7 @@ fn check_expr_kind(&self,
                 let result = if i == 0 {
                     self.try_coerce(e, e_ty, coerce_to)
                 } else {
-                    let prev_elems = || args[..i].iter().map(|e| &**e);
+                    let prev_elems = || args[..i].iter().map(|e| &*e);
                     self.try_find_coercion_lub(&cause, prev_elems, unified, e, e_ty)
                 };
 
@@ -4531,27 +4653,24 @@ pub fn structurally_resolved_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> {
             self.tcx.types.err
         })
     }
-}
 
-// Returns true if b contains a break that can exit from b
-pub fn may_break(tcx: TyCtxt, id: ast::NodeId, b: &hir::Block) -> bool {
-    // First: is there an unlabeled break immediately
-    // inside the loop?
-    (loop_query(&b, |e| {
-        match *e {
-            hir::ExprBreak(None) => true,
-            _ => false
+    fn with_loop_ctxt<F: FnOnce()>(&self, id: ast::NodeId, ctxt: LoopCtxt<'gcx, 'tcx>, f: F)
+                                   -> LoopCtxt<'gcx, 'tcx> {
+        let index;
+        {
+            let mut enclosing_loops = self.enclosing_loops.borrow_mut();
+            index = enclosing_loops.stack.len();
+            enclosing_loops.by_id.insert(id, index);
+            enclosing_loops.stack.push(ctxt);
         }
-    })) ||
-    // Second: is there a labeled break with label
-    // <id> nested anywhere inside the loop?
-    (block_query(b, |e| {
-        if let hir::ExprBreak(Some(_)) = e.node {
-            tcx.expect_def(e.id) == Def::Label(id)
-        } else {
-            false
+        f();
+        {
+            let mut enclosing_loops = self.enclosing_loops.borrow_mut();
+            debug_assert!(enclosing_loops.stack.len() == index + 1);
+            enclosing_loops.by_id.remove(&id).expect("missing loop context");
+            (enclosing_loops.stack.pop().expect("missing loop context"))
         }
-    }))
+    }
 }
 
 pub fn check_bounds_are_used<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
index a280001d5e99d24f511781532dfb8948bf5293e4..c613b62bf2d82b4a3589f01d6f909986588d58b8 100644 (file)
@@ -613,11 +613,11 @@ fn visit_expr(&mut self, expr: &hir::Expr) {
             hir::ExprCall(ref callee, ref args) => {
                 if has_method_map {
                     self.constrain_call(expr, Some(&callee),
-                                        args.iter().map(|e| &**e), false);
+                                        args.iter().map(|e| &*e), false);
                 } else {
                     self.constrain_callee(callee.id, expr, &callee);
                     self.constrain_call(expr, None,
-                                        args.iter().map(|e| &**e), false);
+                                        args.iter().map(|e| &*e), false);
                 }
 
                 intravisit::walk_expr(self, expr);
@@ -625,7 +625,7 @@ fn visit_expr(&mut self, expr: &hir::Expr) {
 
             hir::ExprMethodCall(.., ref args) => {
                 self.constrain_call(expr, Some(&args[0]),
-                                    args[1..].iter().map(|e| &**e), false);
+                                    args[1..].iter().map(|e| &*e), false);
 
                 intravisit::walk_expr(self, expr);
             }
@@ -742,7 +742,7 @@ fn visit_expr(&mut self, expr: &hir::Expr) {
                 self.check_expr_fn_block(expr, &body);
             }
 
-            hir::ExprLoop(ref body, _) => {
+            hir::ExprLoop(ref body, _, _) => {
                 let repeating_scope = self.set_repeating_scope(body.id);
                 intravisit::walk_expr(self, expr);
                 self.set_repeating_scope(repeating_scope);
index 185f897c1baa1cfb82226cb4d59e3abe8204e382..c5562ae3b7febf5753f6a649a011ccc824847e1c 100644 (file)
@@ -18,7 +18,7 @@
 use rustc::hir::def::{Def, CtorKind};
 use rustc::hir::def_id::DefId;
 use rustc::hir::print as pprust;
-use rustc::ty::{self, TyCtxt};
+use rustc::ty;
 use rustc::util::nodemap::FxHashSet;
 
 use rustc_const_eval::lookup_const_by_id;
 /// of a vector of items if it was successfully expanded.
 pub fn try_inline(cx: &DocContext, id: ast::NodeId, into: Option<ast::Name>)
                   -> Option<Vec<clean::Item>> {
-    let tcx = match cx.tcx_opt() {
-        Some(tcx) => tcx,
-        None => return None,
-    };
-    let def = match tcx.expect_def_or_none(id) {
+    let def = match cx.tcx.expect_def_or_none(id) {
         Some(def) => def,
         None => return None,
     };
     let did = def.def_id();
     if did.is_local() { return None }
-    try_inline_def(cx, tcx, def).map(|vec| {
+    try_inline_def(cx, def).map(|vec| {
         vec.into_iter().map(|mut item| {
             match into {
                 Some(into) if item.name.is_some() => {
@@ -66,39 +62,38 @@ pub fn try_inline(cx: &DocContext, id: ast::NodeId, into: Option<ast::Name>)
     })
 }
 
-fn try_inline_def<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                            def: Def) -> Option<Vec<clean::Item>> {
+fn try_inline_def(cx: &DocContext, def: Def) -> Option<Vec<clean::Item>> {
+    let tcx = cx.tcx;
     let mut ret = Vec::new();
-    let did = def.def_id();
     let inner = match def {
         Def::Trait(did) => {
             record_extern_fqn(cx, did, clean::TypeKind::Trait);
-            ret.extend(build_impls(cx, tcx, did));
-            clean::TraitItem(build_external_trait(cx, tcx, did))
+            ret.extend(build_impls(cx, did));
+            clean::TraitItem(build_external_trait(cx, did))
         }
         Def::Fn(did) => {
             record_extern_fqn(cx, did, clean::TypeKind::Function);
-            clean::FunctionItem(build_external_function(cx, tcx, did))
+            clean::FunctionItem(build_external_function(cx, did))
         }
         Def::Struct(did) => {
             record_extern_fqn(cx, did, clean::TypeKind::Struct);
-            ret.extend(build_impls(cx, tcx, did));
-            clean::StructItem(build_struct(cx, tcx, did))
+            ret.extend(build_impls(cx, did));
+            clean::StructItem(build_struct(cx, did))
         }
         Def::Union(did) => {
             record_extern_fqn(cx, did, clean::TypeKind::Union);
-            ret.extend(build_impls(cx, tcx, did));
-            clean::UnionItem(build_union(cx, tcx, did))
+            ret.extend(build_impls(cx, did));
+            clean::UnionItem(build_union(cx, did))
         }
         Def::TyAlias(did) => {
             record_extern_fqn(cx, did, clean::TypeKind::Typedef);
-            ret.extend(build_impls(cx, tcx, did));
-            clean::TypedefItem(build_type_alias(cx, tcx, did), false)
+            ret.extend(build_impls(cx, did));
+            clean::TypedefItem(build_type_alias(cx, did), false)
         }
         Def::Enum(did) => {
             record_extern_fqn(cx, did, clean::TypeKind::Enum);
-            ret.extend(build_impls(cx, tcx, did));
-            clean::EnumItem(build_enum(cx, tcx, did))
+            ret.extend(build_impls(cx, did));
+            clean::EnumItem(build_enum(cx, did))
         }
         // Assume that the enum type is reexported next to the variant, and
         // variants don't show up in documentation specially.
@@ -108,23 +103,24 @@ fn try_inline_def<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>,
         Def::StructCtor(..) => return Some(Vec::new()),
         Def::Mod(did) => {
             record_extern_fqn(cx, did, clean::TypeKind::Module);
-            clean::ModuleItem(build_module(cx, tcx, did))
+            clean::ModuleItem(build_module(cx, did))
         }
         Def::Static(did, mtbl) => {
             record_extern_fqn(cx, did, clean::TypeKind::Static);
-            clean::StaticItem(build_static(cx, tcx, did, mtbl))
+            clean::StaticItem(build_static(cx, did, mtbl))
         }
         Def::Const(did) => {
             record_extern_fqn(cx, did, clean::TypeKind::Const);
-            clean::ConstantItem(build_const(cx, tcx, did))
+            clean::ConstantItem(build_const(cx, did))
         }
         _ => return None,
     };
+    let did = def.def_id();
     cx.renderinfo.borrow_mut().inlined.insert(did);
     ret.push(clean::Item {
         source: clean::Span::empty(),
         name: Some(tcx.item_name(did).to_string()),
-        attrs: load_attrs(cx, tcx, did),
+        attrs: load_attrs(cx, did),
         inner: inner,
         visibility: Some(clean::Public),
         stability: tcx.lookup_stability(did).clean(cx),
@@ -134,9 +130,8 @@ fn try_inline_def<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>,
     Some(ret)
 }
 
-pub fn load_attrs<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                            did: DefId) -> Vec<clean::Attribute> {
-    tcx.get_attrs(did).iter().map(|a| a.clean(cx)).collect()
+pub fn load_attrs(cx: &DocContext, did: DefId) -> clean::Attributes {
+    cx.tcx.get_attrs(did).clean(cx)
 }
 
 /// Record an external fully qualified name in the external_paths cache.
@@ -144,27 +139,24 @@ pub fn load_attrs<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>,
 /// These names are used later on by HTML rendering to generate things like
 /// source links back to the original item.
 pub fn record_extern_fqn(cx: &DocContext, did: DefId, kind: clean::TypeKind) {
-    if let Some(tcx) = cx.tcx_opt() {
-        let crate_name = tcx.sess.cstore.crate_name(did.krate).to_string();
-        let relative = tcx.def_path(did).data.into_iter().filter_map(|elem| {
-            // extern blocks have an empty name
-            let s = elem.data.to_string();
-            if !s.is_empty() {
-                Some(s)
-            } else {
-                None
-            }
-        });
-        let fqn = once(crate_name).chain(relative).collect();
-        cx.renderinfo.borrow_mut().external_paths.insert(did, (fqn, kind));
-    }
+    let crate_name = cx.tcx.sess.cstore.crate_name(did.krate).to_string();
+    let relative = cx.tcx.def_path(did).data.into_iter().filter_map(|elem| {
+        // extern blocks have an empty name
+        let s = elem.data.to_string();
+        if !s.is_empty() {
+            Some(s)
+        } else {
+            None
+        }
+    });
+    let fqn = once(crate_name).chain(relative).collect();
+    cx.renderinfo.borrow_mut().external_paths.insert(did, (fqn, kind));
 }
 
-pub fn build_external_trait<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                      did: DefId) -> clean::Trait {
-    let def = tcx.lookup_trait_def(did);
-    let trait_items = tcx.associated_items(did).map(|item| item.clean(cx)).collect();
-    let predicates = tcx.item_predicates(did);
+pub fn build_external_trait(cx: &DocContext, did: DefId) -> clean::Trait {
+    let def = cx.tcx.lookup_trait_def(did);
+    let trait_items = cx.tcx.associated_items(did).map(|item| item.clean(cx)).collect();
+    let predicates = cx.tcx.item_predicates(did);
     let generics = (def.generics, &predicates).clean(cx);
     let generics = filter_non_trait_generics(did, generics);
     let (generics, supertrait_bounds) = separate_supertrait_bounds(generics);
@@ -176,45 +168,42 @@ pub fn build_external_trait<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tc
     }
 }
 
-fn build_external_function<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                     did: DefId) -> clean::Function {
-    let ty = tcx.item_type(did);
+fn build_external_function(cx: &DocContext, did: DefId) -> clean::Function {
+    let ty = cx.tcx.item_type(did);
     let (decl, style, abi) = match ty.sty {
         ty::TyFnDef(.., ref f) => ((did, &f.sig).clean(cx), f.unsafety, f.abi),
         _ => panic!("bad function"),
     };
 
-    let constness = if tcx.sess.cstore.is_const_fn(did) {
+    let constness = if cx.tcx.sess.cstore.is_const_fn(did) {
         hir::Constness::Const
     } else {
         hir::Constness::NotConst
     };
 
-    let predicates = tcx.item_predicates(did);
+    let predicates = cx.tcx.item_predicates(did);
     clean::Function {
         decl: decl,
-        generics: (tcx.item_generics(did), &predicates).clean(cx),
+        generics: (cx.tcx.item_generics(did), &predicates).clean(cx),
         unsafety: style,
         constness: constness,
         abi: abi,
     }
 }
 
-fn build_enum<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                        did: DefId) -> clean::Enum {
-    let predicates = tcx.item_predicates(did);
+fn build_enum(cx: &DocContext, did: DefId) -> clean::Enum {
+    let predicates = cx.tcx.item_predicates(did);
 
     clean::Enum {
-        generics: (tcx.item_generics(did), &predicates).clean(cx),
+        generics: (cx.tcx.item_generics(did), &predicates).clean(cx),
         variants_stripped: false,
-        variants: tcx.lookup_adt_def(did).variants.clean(cx),
+        variants: cx.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 predicates = tcx.item_predicates(did);
-    let variant = tcx.lookup_adt_def(did).struct_variant();
+fn build_struct(cx: &DocContext, did: DefId) -> clean::Struct {
+    let predicates = cx.tcx.item_predicates(did);
+    let variant = cx.tcx.lookup_adt_def(did).struct_variant();
 
     clean::Struct {
         struct_type: match variant.ctor_kind {
@@ -222,44 +211,41 @@ fn build_struct<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>,
             CtorKind::Fn => doctree::Tuple,
             CtorKind::Const => doctree::Unit,
         },
-        generics: (tcx.item_generics(did), &predicates).clean(cx),
+        generics: (cx.tcx.item_generics(did), &predicates).clean(cx),
         fields: variant.fields.clean(cx),
         fields_stripped: false,
     }
 }
 
-fn build_union<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                          did: DefId) -> clean::Union {
-    let predicates = tcx.item_predicates(did);
-    let variant = tcx.lookup_adt_def(did).struct_variant();
+fn build_union(cx: &DocContext, did: DefId) -> clean::Union {
+    let predicates = cx.tcx.item_predicates(did);
+    let variant = cx.tcx.lookup_adt_def(did).struct_variant();
 
     clean::Union {
         struct_type: doctree::Plain,
-        generics: (tcx.item_generics(did), &predicates).clean(cx),
+        generics: (cx.tcx.item_generics(did), &predicates).clean(cx),
         fields: variant.fields.clean(cx),
         fields_stripped: false,
     }
 }
 
-fn build_type_alias<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                              did: DefId) -> clean::Typedef {
-    let predicates = tcx.item_predicates(did);
+fn build_type_alias(cx: &DocContext, did: DefId) -> clean::Typedef {
+    let predicates = cx.tcx.item_predicates(did);
 
     clean::Typedef {
-        type_: tcx.item_type(did).clean(cx),
-        generics: (tcx.item_generics(did), &predicates).clean(cx),
+        type_: cx.tcx.item_type(did).clean(cx),
+        generics: (cx.tcx.item_generics(did), &predicates).clean(cx),
     }
 }
 
-pub fn build_impls<'a, 'tcx>(cx: &DocContext,
-                             tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                             did: DefId) -> Vec<clean::Item> {
+pub fn build_impls(cx: &DocContext, did: DefId) -> Vec<clean::Item> {
+    let tcx = cx.tcx;
     tcx.populate_inherent_implementations_for_type_if_necessary(did);
     let mut impls = Vec::new();
 
     if let Some(i) = tcx.inherent_impls.borrow().get(&did) {
         for &did in i.iter() {
-            build_impl(cx, tcx, did, &mut impls);
+            build_impl(cx, did, &mut impls);
         }
     }
     // If this is the first time we've inlined something from another crate, then
@@ -277,7 +263,7 @@ pub fn build_impls<'a, 'tcx>(cx: &DocContext,
     cx.populated_all_crate_impls.set(true);
 
     for did in tcx.sess.cstore.implementations_of_trait(None) {
-        build_impl(cx, tcx, did, &mut impls);
+        build_impl(cx, did, &mut impls);
     }
 
     // Also try to inline primitive impls from other crates.
@@ -303,22 +289,20 @@ pub fn build_impls<'a, 'tcx>(cx: &DocContext,
 
     for def_id in primitive_impls.iter().filter_map(|&def_id| def_id) {
         if !def_id.is_local() {
-            build_impl(cx, tcx, def_id, &mut impls);
+            build_impl(cx, def_id, &mut impls);
         }
     }
 
     impls
 }
 
-pub fn build_impl<'a, 'tcx>(cx: &DocContext,
-                            tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                            did: DefId,
-                            ret: &mut Vec<clean::Item>) {
+pub fn build_impl(cx: &DocContext, did: DefId, ret: &mut Vec<clean::Item>) {
     if !cx.renderinfo.borrow_mut().inlined.insert(did) {
         return
     }
 
-    let attrs = load_attrs(cx, tcx, did);
+    let attrs = load_attrs(cx, did);
+    let tcx = cx.tcx;
     let associated_trait = tcx.impl_trait_ref(did);
 
     // Only inline impl if the implemented trait is
@@ -377,7 +361,7 @@ pub fn build_impl<'a, 'tcx>(cx: &DocContext,
                         default,
                     ),
                     source: clean::Span::empty(),
-                    attrs: vec![],
+                    attrs: clean::Attributes::default(),
                     visibility: None,
                     stability: tcx.lookup_stability(item.def_id).clean(cx),
                     deprecation: tcx.lookup_deprecation(item.def_id).clean(cx),
@@ -424,7 +408,7 @@ pub fn build_impl<'a, 'tcx>(cx: &DocContext,
                     name: Some(item.name.clean(cx)),
                     inner: clean::TypedefItem(typedef, true),
                     source: clean::Span::empty(),
-                    attrs: vec![],
+                    attrs: clean::Attributes::default(),
                     visibility: None,
                     stability: tcx.lookup_stability(item.def_id).clean(cx),
                     deprecation: tcx.lookup_deprecation(item.def_id).clean(cx),
@@ -440,15 +424,15 @@ pub fn build_impl<'a, 'tcx>(cx: &DocContext,
             clean::RegionBound(..) => unreachable!(),
         }
     });
-    if trait_.def_id() == cx.deref_trait_did.get() {
+    if trait_.def_id() == tcx.lang_items.deref_trait() {
         super::build_deref_target_impls(cx, &trait_items, ret);
     }
 
     let provided = trait_.def_id().map(|did| {
-        cx.tcx().provided_trait_methods(did)
-                .into_iter()
-                .map(|meth| meth.name.to_string())
-                .collect()
+        tcx.provided_trait_methods(did)
+            .into_iter()
+            .map(|meth| meth.name.to_string())
+            .collect()
     }).unwrap_or(FxHashSet());
 
     ret.push(clean::Item {
@@ -471,26 +455,24 @@ pub fn build_impl<'a, 'tcx>(cx: &DocContext,
     });
 }
 
-fn build_module<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                          did: DefId) -> clean::Module {
+fn build_module(cx: &DocContext, did: DefId) -> clean::Module {
     let mut items = Vec::new();
-    fill_in(cx, tcx, did, &mut items);
+    fill_in(cx, did, &mut items);
     return clean::Module {
         items: items,
         is_crate: false,
     };
 
-    fn fill_in<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                         did: DefId, items: &mut Vec<clean::Item>) {
+    fn fill_in(cx: &DocContext, did: DefId, items: &mut Vec<clean::Item>) {
         // If we're reexporting a reexport it may actually reexport something in
         // two namespaces, so the target may be listed twice. Make sure we only
         // visit each node at most once.
         let mut visited = FxHashSet();
-        for item in tcx.sess.cstore.item_children(did) {
+        for item in cx.tcx.sess.cstore.item_children(did) {
             let def_id = item.def.def_id();
-            if tcx.sess.cstore.visibility(def_id) == ty::Visibility::Public {
+            if cx.tcx.sess.cstore.visibility(def_id) == ty::Visibility::Public {
                 if !visited.insert(def_id) { continue }
-                if let Some(i) = try_inline_def(cx, tcx, item.def) {
+                if let Some(i) = try_inline_def(cx, item.def) {
                     items.extend(i)
                 }
             }
@@ -498,9 +480,8 @@ fn fill_in<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>,
     }
 }
 
-fn build_const<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                         did: DefId) -> clean::Constant {
-    let (expr, ty) = lookup_const_by_id(tcx, did, None).unwrap_or_else(|| {
+fn build_const(cx: &DocContext, did: DefId) -> clean::Constant {
+    let (expr, ty) = lookup_const_by_id(cx.tcx, did, None).unwrap_or_else(|| {
         panic!("expected lookup_const_by_id to succeed for {:?}", did);
     });
     debug!("converting constant expr {:?} to snippet", expr);
@@ -508,16 +489,14 @@ fn build_const<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>,
     debug!("got snippet {}", sn);
 
     clean::Constant {
-        type_: ty.map(|t| t.clean(cx)).unwrap_or_else(|| tcx.item_type(did).clean(cx)),
+        type_: ty.map(|t| t.clean(cx)).unwrap_or_else(|| cx.tcx.item_type(did).clean(cx)),
         expr: sn
     }
 }
 
-fn build_static<'a, 'tcx>(cx: &DocContext, tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                          did: DefId,
-                          mutable: bool) -> clean::Static {
+fn build_static(cx: &DocContext, did: DefId, mutable: bool) -> clean::Static {
     clean::Static {
-        type_: tcx.item_type(did).clean(cx),
+        type_: cx.tcx.item_type(did).clean(cx),
         mutability: if mutable {clean::Mutable} else {clean::Immutable},
         expr: "\n\n\n".to_string(), // trigger the "[definition]" links
     }
index 2cc1882ce3eae3411adaf179d03132f1127d51af..a19ec4e8b5edbf6bd57d71163b324764f2f7db5b 100644 (file)
@@ -14,7 +14,6 @@
 pub use self::Type::*;
 pub use self::Mutability::*;
 pub use self::ItemEnum::*;
-pub use self::Attribute::*;
 pub use self::TyParamBound::*;
 pub use self::SelfTy::*;
 pub use self::FunctionRetTy::*;
@@ -25,7 +24,6 @@
 use syntax::attr;
 use syntax::codemap::Spanned;
 use syntax::ptr::P;
-use syntax::print::pprust as syntax_pprust;
 use syntax::symbol::keywords;
 use syntax_pos::{self, DUMMY_SP, Pos};
 
@@ -44,6 +42,7 @@
 
 use std::path::PathBuf;
 use std::rc::Rc;
+use std::slice;
 use std::sync::Arc;
 use std::u32;
 use std::env::current_dir;
 
 // extract the stability index for a node from tcx, if possible
 fn get_stability(cx: &DocContext, def_id: DefId) -> Option<Stability> {
-    cx.tcx_opt().and_then(|tcx| tcx.lookup_stability(def_id)).clean(cx)
+    cx.tcx.lookup_stability(def_id).clean(cx)
 }
 
 fn get_deprecation(cx: &DocContext, def_id: DefId) -> Option<Deprecation> {
-    cx.tcx_opt().and_then(|tcx| tcx.lookup_deprecation(def_id)).clean(cx)
+    cx.tcx.lookup_deprecation(def_id).clean(cx)
 }
 
 pub trait Clean<T> {
@@ -126,20 +125,17 @@ fn clean(&self, cx: &DocContext) -> Crate {
         use rustc::session::config::Input;
         use ::visit_lib::LibEmbargoVisitor;
 
-        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 r = cx.renderinfo.borrow_mut();
+            r.deref_trait_did = cx.tcx.lang_items.deref_trait();
+            r.deref_mut_trait_did = cx.tcx.lang_items.deref_mut_trait();
         }
 
         let mut externs = Vec::new();
         for cnum in cx.sess().cstore.crates() {
             externs.push((cnum, CrateNum(cnum).clean(cx)));
-            if cx.tcx_opt().is_some() {
-                // Analyze doc-reachability for extern items
-                LibEmbargoVisitor::new(cx).visit_lib(cnum);
-            }
+            // Analyze doc-reachability for extern items
+            LibEmbargoVisitor::new(cx).visit_lib(cnum);
         }
         externs.sort_by(|&(a, _), &(b, _)| a.cmp(&b));
 
@@ -227,7 +223,7 @@ fn clean(&self, cx: &DocContext) -> Crate {
 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
 pub struct ExternalCrate {
     pub name: String,
-    pub attrs: Vec<Attribute>,
+    pub attrs: Attributes,
     pub primitives: Vec<PrimitiveType>,
 }
 
@@ -235,12 +231,10 @@ impl Clean<ExternalCrate> 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| {
-            for item in tcx.sess.cstore.item_children(root) {
-                let attrs = inline::load_attrs(cx, tcx, item.def.def_id());
-                PrimitiveType::find(&attrs).map(|prim| primitives.push(prim));
-            }
-        });
+        for item in cx.tcx.sess.cstore.item_children(root) {
+            let attrs = inline::load_attrs(cx, item.def.def_id());
+            PrimitiveType::find(&attrs).map(|prim| primitives.push(prim));
+        }
         ExternalCrate {
             name: cx.sess().cstore.crate_name(self.0).to_string(),
             attrs: cx.sess().cstore.item_attrs(root).clean(cx),
@@ -258,7 +252,7 @@ pub struct Item {
     pub source: Span,
     /// Not everything has a name. E.g., impls
     pub name: Option<String>,
-    pub attrs: Vec<Attribute>,
+    pub attrs: Attributes,
     pub inner: ItemEnum,
     pub visibility: Option<Visibility>,
     pub def_id: DefId,
@@ -270,7 +264,7 @@ impl Item {
     /// Finds the `doc` attribute as a NameValue and returns the corresponding
     /// value found.
     pub fn doc_value<'a>(&'a self) -> Option<&'a str> {
-        self.attrs.value("doc")
+        self.attrs.doc_value()
     }
     pub fn is_crate(&self) -> bool {
         match self.inner {
@@ -450,7 +444,7 @@ fn clean(&self, cx: &DocContext) -> Item {
             visibility: self.vis.clean(cx),
             stability: self.stab.clean(cx),
             deprecation: self.depr.clean(cx),
-            def_id: cx.map.local_def_id(self.id),
+            def_id: cx.tcx.map.local_def_id(self.id),
             inner: ModuleItem(Module {
                is_crate: self.is_crate,
                items: items
@@ -459,86 +453,104 @@ fn clean(&self, cx: &DocContext) -> Item {
     }
 }
 
-pub trait Attributes {
-    fn has_word(&self, &str) -> bool;
-    fn value<'a>(&'a self, &str) -> Option<&'a str>;
-    fn list<'a>(&'a self, &str) -> &'a [Attribute];
+pub struct ListAttributesIter<'a> {
+    attrs: slice::Iter<'a, ast::Attribute>,
+    current_list: slice::Iter<'a, ast::NestedMetaItem>,
+    name: &'a str
 }
 
-impl Attributes for [Attribute] {
-    /// Returns whether the attribute list contains a specific `Word`
-    fn has_word(&self, word: &str) -> bool {
-        for attr in self {
-            if let Word(ref w) = *attr {
-                if word == *w {
-                    return true;
-                }
-            }
+impl<'a> Iterator for ListAttributesIter<'a> {
+    type Item = &'a ast::NestedMetaItem;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        if let Some(nested) = self.current_list.next() {
+            return Some(nested);
         }
-        false
-    }
 
-    /// Finds an attribute as NameValue and returns the corresponding value found.
-    fn value<'a>(&'a self, name: &str) -> Option<&'a str> {
-        for attr in self {
-            if let NameValue(ref x, ref v) = *attr {
-                if name == *x {
-                    return Some(v);
+        for attr in &mut self.attrs {
+            if let Some(ref list) = attr.meta_item_list() {
+                if attr.check_name(self.name) {
+                    self.current_list = list.iter();
+                    if let Some(nested) = self.current_list.next() {
+                        return Some(nested);
+                    }
                 }
             }
         }
+
         None
     }
+}
 
+pub trait AttributesExt {
     /// Finds an attribute as List and returns the list of attributes nested inside.
-    fn list<'a>(&'a self, name: &str) -> &'a [Attribute] {
-        for attr in self {
-            if let List(ref x, ref list) = *attr {
-                if name == *x {
-                    return &list[..];
-                }
-            }
+    fn lists<'a>(&'a self, &'a str) -> ListAttributesIter<'a>;
+}
+
+impl AttributesExt for [ast::Attribute] {
+    fn lists<'a>(&'a self, name: &'a str) -> ListAttributesIter<'a> {
+        ListAttributesIter {
+            attrs: self.iter(),
+            current_list: [].iter(),
+            name: name
         }
-        &[]
     }
 }
 
-/// This is a flattened version of the AST's Attribute + MetaItem.
-#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
-pub enum Attribute {
-    Word(String),
-    List(String, Vec<Attribute>),
-    NameValue(String, String),
-    Literal(String),
+pub trait NestedAttributesExt {
+    /// Returns whether the attribute list contains a specific `Word`
+    fn has_word(self, &str) -> bool;
+}
+
+impl<'a, I: IntoIterator<Item=&'a ast::NestedMetaItem>> NestedAttributesExt for I {
+    fn has_word(self, word: &str) -> bool {
+        self.into_iter().any(|attr| attr.is_word() && attr.check_name(word))
+    }
+}
+
+#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug, Default)]
+pub struct Attributes {
+    pub doc_strings: Vec<String>,
+    pub other_attrs: Vec<ast::Attribute>
 }
 
-impl Clean<Attribute> for ast::NestedMetaItem {
-    fn clean(&self, cx: &DocContext) -> Attribute {
-        if let Some(mi) = self.meta_item() {
-            mi.clean(cx)
-        } else { // must be a literal
-            let lit = self.literal().unwrap();
-            Literal(syntax_pprust::lit_to_string(lit))
+impl Attributes {
+    pub fn from_ast(attrs: &[ast::Attribute]) -> Attributes {
+        let mut doc_strings = vec![];
+        let other_attrs = attrs.iter().filter_map(|attr| {
+            attr.with_desugared_doc(|attr| {
+                if let Some(value) = attr.value_str() {
+                    if attr.check_name("doc") {
+                        doc_strings.push(value.to_string());
+                        return None;
+                    }
+                }
+
+                Some(attr.clone())
+            })
+        }).collect();
+        Attributes {
+            doc_strings: doc_strings,
+            other_attrs: other_attrs
         }
     }
+
+    /// Finds the `doc` attribute as a NameValue and returns the corresponding
+    /// value found.
+    pub fn doc_value<'a>(&'a self) -> Option<&'a str> {
+        self.doc_strings.first().map(|s| &s[..])
+    }
 }
 
-impl Clean<Attribute> for ast::MetaItem {
-    fn clean(&self, cx: &DocContext) -> Attribute {
-        if self.is_word() {
-            Word(self.name().to_string())
-        } else if let Some(v) = self.value_str() {
-            NameValue(self.name().to_string(), v.to_string())
-        } else { // must be a list
-            let l = self.meta_item_list().unwrap();
-            List(self.name().to_string(), l.clean(cx))
-       }
+impl AttributesExt for Attributes {
+    fn lists<'a>(&'a self, name: &'a str) -> ListAttributesIter<'a> {
+        self.other_attrs.lists(name)
     }
 }
 
-impl Clean<Attribute> for ast::Attribute {
-    fn clean(&self, cx: &DocContext) -> Attribute {
-        self.with_desugared_doc(|a| a.meta().clean(cx))
+impl Clean<Attributes> for [ast::Attribute] {
+    fn clean(&self, _cx: &DocContext) -> Attributes {
+        Attributes::from_ast(self)
     }
 }
 
@@ -554,7 +566,7 @@ impl Clean<TyParam> for hir::TyParam {
     fn clean(&self, cx: &DocContext) -> TyParam {
         TyParam {
             name: self.name.clean(cx),
-            did: cx.map.local_def_id(self.id),
+            did: cx.tcx.map.local_def_id(self.id),
             bounds: self.bounds.clean(cx),
             default: self.default.clean(cx),
         }
@@ -591,11 +603,9 @@ fn maybe_sized(cx: &DocContext) -> TyParamBound {
 
     fn is_sized_bound(&self, cx: &DocContext) -> bool {
         use rustc::hir::TraitBoundModifier as TBM;
-        if let Some(tcx) = cx.tcx_opt() {
-            if let TyParamBound::TraitBound(PolyTrait { ref trait_, .. }, TBM::None) = *self {
-                if trait_.def_id() == tcx.lang_items.sized_trait() {
-                    return true;
-                }
+        if let TyParamBound::TraitBound(PolyTrait { ref trait_, .. }, TBM::None) = *self {
+            if trait_.def_id() == cx.tcx.lang_items.sized_trait() {
+                return true;
             }
         }
         false
@@ -616,9 +626,9 @@ fn external_path_params(cx: &DocContext, trait_did: Option<DefId>, has_self: boo
     let lifetimes = substs.regions().filter_map(|v| v.clean(cx)).collect();
     let types = substs.types().skip(has_self as usize).collect::<Vec<_>>();
 
-    match (trait_did, cx.tcx_opt()) {
+    match trait_did {
         // Attempt to sugar an external path like Fn<(A, B,), C> to Fn(A, B) -> C
-        (Some(did), Some(ref tcx)) if tcx.lang_items.fn_trait_kind(did).is_some() => {
+        Some(did) if cx.tcx.lang_items.fn_trait_kind(did).is_some() => {
             assert_eq!(types.len(), 1);
             let inputs = match types[0].sty {
                 ty::TyTuple(ref tys) => tys.iter().map(|t| t.clean(cx)).collect(),
@@ -641,7 +651,7 @@ fn external_path_params(cx: &DocContext, trait_did: Option<DefId>, has_self: boo
                 output: output
             }
         },
-        (..) => {
+        _ => {
             PathParameters::AngleBracketed {
                 lifetimes: lifetimes,
                 types: types.clean(cx),
@@ -666,10 +676,7 @@ fn external_path(cx: &DocContext, name: &str, trait_did: Option<DefId>, has_self
 
 impl Clean<TyParamBound> for ty::BuiltinBound {
     fn clean(&self, cx: &DocContext) -> TyParamBound {
-        let tcx = match cx.tcx_opt() {
-            Some(tcx) => tcx,
-            None => return RegionBound(Lifetime::statik())
-        };
+        let tcx = cx.tcx;
         let empty = tcx.intern_substs(&[]);
         let (did, path) = match *self {
             ty::BoundSend =>
@@ -700,12 +707,8 @@ fn clean(&self, cx: &DocContext) -> TyParamBound {
 
 impl<'tcx> Clean<TyParamBound> for ty::TraitRef<'tcx> {
     fn clean(&self, cx: &DocContext) -> TyParamBound {
-        let tcx = match cx.tcx_opt() {
-            Some(tcx) => tcx,
-            None => return RegionBound(Lifetime::statik())
-        };
         inline::record_extern_fqn(cx, self.def_id, TypeKind::Trait);
-        let path = external_path(cx, &tcx.item_name(self.def_id).as_str(),
+        let path = external_path(cx, &cx.tcx.item_name(self.def_id).as_str(),
                                  Some(self.def_id), true, vec![], self.substs);
 
         debug!("ty::TraitRef\n  subst: {:?}\n", self.substs);
@@ -772,18 +775,16 @@ pub fn statik() -> Lifetime {
 
 impl Clean<Lifetime> for hir::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;
-                    }
+        let def = cx.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())
     }
@@ -1048,7 +1049,7 @@ fn clean(&self, cx: &DocContext) -> Method {
             },
             output: self.decl.output.clean(cx),
             variadic: false,
-            attrs: Vec::new()
+            attrs: Attributes::default()
         };
         Method {
             generics: self.generics.clean(cx),
@@ -1076,7 +1077,7 @@ fn clean(&self, cx: &DocContext) -> TyMethod {
             },
             output: self.decl.output.clean(cx),
             variadic: false,
-            attrs: Vec::new()
+            attrs: Attributes::default()
         };
         TyMethod {
             unsafety: self.unsafety.clone(),
@@ -1105,7 +1106,7 @@ fn clean(&self, cx: &DocContext) -> Item {
             visibility: self.vis.clean(cx),
             stability: self.stab.clean(cx),
             deprecation: self.depr.clean(cx),
-            def_id: cx.map.local_def_id(self.id),
+            def_id: cx.tcx.map.local_def_id(self.id),
             inner: FunctionItem(Function {
                 decl: self.decl.clean(cx),
                 generics: self.generics.clean(cx),
@@ -1122,7 +1123,7 @@ pub struct FnDecl {
     pub inputs: Arguments,
     pub output: FunctionRetTy,
     pub variadic: bool,
-    pub attrs: Vec<Attribute>,
+    pub attrs: Attributes,
 }
 
 impl FnDecl {
@@ -1148,7 +1149,7 @@ fn clean(&self, cx: &DocContext) -> FnDecl {
             },
             output: self.output.clean(cx),
             variadic: self.variadic,
-            attrs: Vec::new()
+            attrs: Attributes::default()
         }
     }
 }
@@ -1156,14 +1157,14 @@ fn clean(&self, cx: &DocContext) -> FnDecl {
 impl<'a, 'tcx> Clean<FnDecl> for (DefId, &'a ty::PolyFnSig<'tcx>) {
     fn clean(&self, cx: &DocContext) -> FnDecl {
         let (did, sig) = *self;
-        let mut names = if cx.map.as_local_node_id(did).is_some() {
+        let mut names = if cx.tcx.map.as_local_node_id(did).is_some() {
             vec![].into_iter()
         } else {
-            cx.tcx().sess.cstore.fn_arg_names(did).into_iter()
+            cx.tcx.sess.cstore.fn_arg_names(did).into_iter()
         }.peekable();
         FnDecl {
             output: Return(sig.0.output.clean(cx)),
-            attrs: Vec::new(),
+            attrs: Attributes::default(),
             variadic: sig.0.variadic,
             inputs: Arguments {
                 values: sig.0.inputs.iter().map(|t| {
@@ -1247,7 +1248,7 @@ fn clean(&self, cx: &DocContext) -> 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),
+            def_id: cx.tcx.map.local_def_id(self.id),
             visibility: self.vis.clean(cx),
             stability: self.stab.clean(cx),
             deprecation: self.depr.clean(cx),
@@ -1297,10 +1298,10 @@ fn clean(&self, cx: &DocContext) -> Item {
             name: Some(self.name.clean(cx)),
             attrs: self.attrs.clean(cx),
             source: self.span.clean(cx),
-            def_id: cx.map.local_def_id(self.id),
+            def_id: cx.tcx.map.local_def_id(self.id),
             visibility: None,
-            stability: get_stability(cx, cx.map.local_def_id(self.id)),
-            deprecation: get_deprecation(cx, cx.map.local_def_id(self.id)),
+            stability: get_stability(cx, cx.tcx.map.local_def_id(self.id)),
+            deprecation: get_deprecation(cx, cx.tcx.map.local_def_id(self.id)),
             inner: inner
         }
     }
@@ -1329,10 +1330,10 @@ fn clean(&self, cx: &DocContext) -> Item {
             name: Some(self.name.clean(cx)),
             source: self.span.clean(cx),
             attrs: self.attrs.clean(cx),
-            def_id: cx.map.local_def_id(self.id),
+            def_id: cx.tcx.map.local_def_id(self.id),
             visibility: self.vis.clean(cx),
-            stability: get_stability(cx, cx.map.local_def_id(self.id)),
-            deprecation: get_deprecation(cx, cx.map.local_def_id(self.id)),
+            stability: get_stability(cx, cx.tcx.map.local_def_id(self.id)),
+            deprecation: get_deprecation(cx, cx.tcx.map.local_def_id(self.id)),
             inner: inner
         }
     }
@@ -1342,13 +1343,13 @@ impl<'tcx> Clean<Item> for ty::AssociatedItem {
     fn clean(&self, cx: &DocContext) -> Item {
         let inner = match self.kind {
             ty::AssociatedKind::Const => {
-                let ty = cx.tcx().item_type(self.def_id);
+                let ty = cx.tcx.item_type(self.def_id);
                 AssociatedConstItem(ty.clean(cx), None)
             }
             ty::AssociatedKind::Method => {
-                let generics = (cx.tcx().item_generics(self.def_id),
-                                &cx.tcx().item_predicates(self.def_id)).clean(cx);
-                let fty = match cx.tcx().item_type(self.def_id).sty {
+                let generics = (cx.tcx.item_generics(self.def_id),
+                                &cx.tcx.item_predicates(self.def_id)).clean(cx);
+                let fty = match cx.tcx.item_type(self.def_id).sty {
                     ty::TyFnDef(_, _, f) => f,
                     _ => unreachable!()
                 };
@@ -1357,9 +1358,9 @@ fn clean(&self, cx: &DocContext) -> Item {
                 if self.method_has_self_argument {
                     let self_ty = match self.container {
                         ty::ImplContainer(def_id) => {
-                            cx.tcx().item_type(def_id)
+                            cx.tcx.item_type(def_id)
                         }
-                        ty::TraitContainer(_) => cx.tcx().mk_self_type()
+                        ty::TraitContainer(_) => cx.tcx.mk_self_type()
                     };
                     let self_arg_ty = *fty.sig.input(0).skip_binder();
                     if self_arg_ty == self_ty {
@@ -1405,8 +1406,8 @@ fn clean(&self, cx: &DocContext) -> Item {
                     // are actually located on the trait/impl itself, so we need to load
                     // all of the generics from there and then look for bounds that are
                     // applied to this associated type in question.
-                    let def = cx.tcx().lookup_trait_def(did);
-                    let predicates = cx.tcx().item_predicates(did);
+                    let def = cx.tcx.lookup_trait_def(did);
+                    let predicates = cx.tcx.item_predicates(did);
                     let generics = (def.generics, &predicates).clean(cx);
                     generics.where_predicates.iter().filter_map(|pred| {
                         let (name, self_type, trait_, bounds) = match *pred {
@@ -1442,7 +1443,7 @@ fn clean(&self, cx: &DocContext) -> Item {
                 }
 
                 let ty = if self.defaultness.has_value() {
-                    Some(cx.tcx().item_type(self.def_id))
+                    Some(cx.tcx.item_type(self.def_id))
                 } else {
                     None
                 };
@@ -1457,7 +1458,7 @@ fn clean(&self, cx: &DocContext) -> Item {
             stability: get_stability(cx, self.def_id),
             deprecation: get_deprecation(cx, self.def_id),
             def_id: self.def_id,
-            attrs: inline::load_attrs(cx, cx.tcx(), self.def_id),
+            attrs: inline::load_attrs(cx, self.def_id),
             source: Span::empty(),
             inner: inner,
         }
@@ -1616,11 +1617,11 @@ fn from_str(s: &str) -> Option<PrimitiveType> {
         }
     }
 
-    fn find(attrs: &[Attribute]) -> Option<PrimitiveType> {
-        for attr in attrs.list("doc") {
-            if let NameValue(ref k, ref v) = *attr {
-                if "primitive" == *k {
-                    if let ret@Some(..) = PrimitiveType::from_str(v) {
+    fn find(attrs: &Attributes) -> Option<PrimitiveType> {
+        for attr in attrs.lists("doc") {
+            if let Some(v) = attr.value_str() {
+                if attr.check_name("primitive") {
+                    if let ret@Some(..) = PrimitiveType::from_str(&v.as_str()) {
                         return ret;
                     }
                 }
@@ -1710,53 +1711,44 @@ fn clean(&self, cx: &DocContext) -> Type {
                              type_: box m.ty.clean(cx)},
             TySlice(ref ty) => Vector(box ty.clean(cx)),
             TyArray(ref ty, ref e) => {
-                let n = if let Some(tcx) = cx.tcx_opt() {
-                    use rustc_const_math::{ConstInt, ConstUsize};
-                    use rustc_const_eval::eval_const_expr;
-                    use rustc::middle::const_val::ConstVal;
-                    match eval_const_expr(tcx, e) {
-                        ConstVal::Integral(ConstInt::Usize(u)) => match u {
-                            ConstUsize::Us16(u) => u.to_string(),
-                            ConstUsize::Us32(u) => u.to_string(),
-                            ConstUsize::Us64(u) => u.to_string(),
-                        },
-                        // after type checking this can't fail
-                        _ => unreachable!(),
-                    }
-                } else {
-                    pprust::expr_to_string(e)
+                use rustc_const_math::{ConstInt, ConstUsize};
+                use rustc_const_eval::eval_const_expr;
+                use rustc::middle::const_val::ConstVal;
+
+                let n = match eval_const_expr(cx.tcx, e) {
+                    ConstVal::Integral(ConstInt::Usize(u)) => match u {
+                        ConstUsize::Us16(u) => u.to_string(),
+                        ConstUsize::Us32(u) => u.to_string(),
+                        ConstUsize::Us64(u) => u.to_string(),
+                    },
+                    // after type checking this can't fail
+                    _ => unreachable!(),
                 };
                 FixedVector(box ty.clean(cx), n)
             },
             TyTup(ref tys) => Tuple(tys.clean(cx)),
             TyPath(None, ref path) => {
-                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 def = cx.tcx.expect_def(self.id);
+                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 {
-                        // 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) {
-                                Some((tcx, &tcx.map.expect_item(node_id).node))
-                            } else {
-                                None
-                            }
-                        })
-                    } else {
-                        None
+                let mut alias = None;
+                if let Def::TyAlias(def_id) = def {
+                    // Substitute private type aliases
+                    if let Some(node_id) = cx.tcx.map.as_local_node_id(def_id) {
+                        if !cx.access_levels.borrow().is_exported(def_id) {
+                            alias = Some(&cx.tcx.map.expect_item(node_id).node);
+                        }
                     }
-                });
-                if let Some((tcx, &hir::ItemTy(ref ty, ref generics))) = tcx_and_alias {
+                };
+
+                if let Some(&hir::ItemTy(ref ty, ref generics)) = alias {
                     let provided_params = &path.segments.last().unwrap().parameters;
                     let mut ty_substs = FxHashMap();
                     let mut lt_substs = FxHashMap();
                     for (i, ty_param) in generics.ty_params.iter().enumerate() {
-                        let ty_param_def = tcx.expect_def(ty_param.id);
+                        let ty_param_def = cx.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));
@@ -1824,9 +1816,7 @@ fn clean(&self, cx: &DocContext) -> Type {
             ty::TyFloat(float_ty) => Primitive(float_ty.into()),
             ty::TyStr => Primitive(PrimitiveType::Str),
             ty::TyBox(t) => {
-                let box_did = cx.tcx_opt().and_then(|tcx| {
-                    tcx.lang_items.owned_box()
-                });
+                let box_did = cx.tcx.lang_items.owned_box();
                 lang_struct(cx, box_did, t, "Box", Unique)
             }
             ty::TySlice(ty) => Vector(box ty.clean(cx)),
@@ -1846,7 +1836,7 @@ fn clean(&self, cx: &DocContext) -> Type {
                     type_params: Vec::new(),
                     where_predicates: Vec::new()
                 },
-                decl: (cx.map.local_def_id(ast::CRATE_NODE_ID), &fty.sig).clean(cx),
+                decl: (cx.tcx.map.local_def_id(ast::CRATE_NODE_ID), &fty.sig).clean(cx),
                 abi: fty.abi,
             }),
             ty::TyAdt(def, substs) => {
@@ -1857,7 +1847,7 @@ fn clean(&self, cx: &DocContext) -> Type {
                     AdtKind::Enum => TypeKind::Enum,
                 };
                 inline::record_extern_fqn(cx, did, kind);
-                let path = external_path(cx, &cx.tcx().item_name(did).as_str(),
+                let path = external_path(cx, &cx.tcx.item_name(did).as_str(),
                                          None, false, vec![], substs);
                 ResolvedPath {
                     path: path,
@@ -1884,7 +1874,7 @@ fn clean(&self, cx: &DocContext) -> Type {
                     });
                 }
 
-                let path = external_path(cx, &cx.tcx().item_name(did).as_str(),
+                let path = external_path(cx, &cx.tcx.item_name(did).as_str(),
                                          Some(did), false, bindings, obj.principal.0.substs);
                 ResolvedPath {
                     path: path,
@@ -1902,9 +1892,9 @@ fn clean(&self, cx: &DocContext) -> Type {
             ty::TyAnon(def_id, substs) => {
                 // Grab the "TraitA + TraitB" from `impl TraitA + TraitB`,
                 // by looking up the projections associated with the def_id.
-                let item_predicates = cx.tcx().item_predicates(def_id);
-                let substs = cx.tcx().lift(&substs).unwrap();
-                let bounds = item_predicates.instantiate(cx.tcx(), substs);
+                let item_predicates = cx.tcx.item_predicates(def_id);
+                let substs = cx.tcx.lift(&substs).unwrap();
+                let bounds = item_predicates.instantiate(cx.tcx, substs);
                 ImplTrait(bounds.predicates.into_iter().filter_map(|predicate| {
                     predicate.to_opt_poly_trait_ref().clean(cx)
                 }).collect())
@@ -1925,9 +1915,9 @@ fn clean(&self, cx: &DocContext) -> Item {
             attrs: self.attrs.clean(cx),
             source: self.span.clean(cx),
             visibility: self.vis.clean(cx),
-            stability: get_stability(cx, cx.map.local_def_id(self.id)),
-            deprecation: get_deprecation(cx, cx.map.local_def_id(self.id)),
-            def_id: cx.map.local_def_id(self.id),
+            stability: get_stability(cx, cx.tcx.map.local_def_id(self.id)),
+            deprecation: get_deprecation(cx, cx.tcx.map.local_def_id(self.id)),
+            def_id: cx.tcx.map.local_def_id(self.id),
             inner: StructFieldItem(self.ty.clean(cx)),
         }
     }
@@ -1937,7 +1927,7 @@ impl<'tcx> Clean<Item> for ty::FieldDefData<'tcx, 'static> {
     fn clean(&self, cx: &DocContext) -> Item {
         Item {
             name: Some(self.name).clean(cx),
-            attrs: cx.tcx().get_attrs(self.did).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),
@@ -1988,7 +1978,7 @@ fn clean(&self, cx: &DocContext) -> 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),
+            def_id: cx.tcx.map.local_def_id(self.id),
             visibility: self.vis.clean(cx),
             stability: self.stab.clean(cx),
             deprecation: self.depr.clean(cx),
@@ -2008,7 +1998,7 @@ fn clean(&self, cx: &DocContext) -> 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),
+            def_id: cx.tcx.map.local_def_id(self.id),
             visibility: self.vis.clean(cx),
             stability: self.stab.clean(cx),
             deprecation: self.depr.clean(cx),
@@ -2055,7 +2045,7 @@ fn clean(&self, cx: &DocContext) -> 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),
+            def_id: cx.tcx.map.local_def_id(self.id),
             visibility: self.vis.clean(cx),
             stability: self.stab.clean(cx),
             deprecation: self.depr.clean(cx),
@@ -2082,7 +2072,7 @@ fn clean(&self, cx: &DocContext) -> Item {
             visibility: None,
             stability: self.stab.clean(cx),
             deprecation: self.depr.clean(cx),
-            def_id: cx.map.local_def_id(self.def.id()),
+            def_id: cx.tcx.map.local_def_id(self.def.id()),
             inner: VariantItem(Variant {
                 kind: self.def.clean(cx),
             }),
@@ -2107,7 +2097,7 @@ fn clean(&self, cx: &DocContext) -> Item {
                         Item {
                             source: Span::empty(),
                             name: Some(field.name.clean(cx)),
-                            attrs: cx.tcx().get_attrs(field.did).clean(cx),
+                            attrs: cx.tcx.get_attrs(field.did).clean(cx),
                             visibility: field.vis.clean(cx),
                             def_id: field.did,
                             stability: get_stability(cx, field.did),
@@ -2120,7 +2110,7 @@ fn clean(&self, cx: &DocContext) -> Item {
         };
         Item {
             name: Some(self.name.clean(cx)),
-            attrs: inline::load_attrs(cx, cx.tcx(), self.did),
+            attrs: inline::load_attrs(cx, self.did),
             source: Span::empty(),
             visibility: Some(Inherited),
             def_id: self.did,
@@ -2305,7 +2295,7 @@ fn clean(&self, cx: &DocContext) -> 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.clone()),
+            def_id: cx.tcx.map.local_def_id(self.id.clone()),
             visibility: self.vis.clean(cx),
             stability: self.stab.clean(cx),
             deprecation: self.depr.clean(cx),
@@ -2357,7 +2347,7 @@ fn clean(&self, cx: &DocContext) -> 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),
+            def_id: cx.tcx.map.local_def_id(self.id),
             visibility: self.vis.clean(cx),
             stability: self.stab.clean(cx),
             deprecation: self.depr.clean(cx),
@@ -2382,7 +2372,7 @@ fn clean(&self, cx: &DocContext) -> 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),
+            def_id: cx.tcx.map.local_def_id(self.id),
             visibility: self.vis.clean(cx),
             stability: self.stab.clean(cx),
             deprecation: self.depr.clean(cx),
@@ -2443,24 +2433,22 @@ fn clean(&self, cx: &DocContext) -> Vec<Item> {
 
         // If this impl block is an implementation of the Deref trait, then we
         // need to try inlining the target's inherent impl blocks as well.
-        if trait_.def_id() == cx.deref_trait_did.get() {
+        if trait_.def_id() == cx.tcx.lang_items.deref_trait() {
             build_deref_target_impls(cx, &items, &mut ret);
         }
 
-        let provided = trait_.def_id().and_then(|did| {
-            cx.tcx_opt().map(|tcx| {
-                tcx.provided_trait_methods(did)
-                   .into_iter()
-                   .map(|meth| meth.name.to_string())
-                   .collect()
-            })
+        let provided = trait_.def_id().map(|did| {
+            cx.tcx.provided_trait_methods(did)
+                  .into_iter()
+                  .map(|meth| meth.name.to_string())
+                  .collect()
         }).unwrap_or(FxHashSet());
 
         ret.push(Item {
             name: None,
             attrs: self.attrs.clean(cx),
             source: self.whence.clean(cx),
-            def_id: cx.map.local_def_id(self.id),
+            def_id: cx.tcx.map.local_def_id(self.id),
             visibility: self.vis.clean(cx),
             stability: self.stab.clean(cx),
             deprecation: self.depr.clean(cx),
@@ -2481,10 +2469,7 @@ fn clean(&self, cx: &DocContext) -> Vec<Item> {
 fn build_deref_target_impls(cx: &DocContext,
                             items: &[Item],
                             ret: &mut Vec<Item>) {
-    let tcx = match cx.tcx_opt() {
-        Some(t) => t,
-        None => return,
-    };
+    let tcx = cx.tcx;
 
     for item in items {
         let target = match item.inner {
@@ -2494,7 +2479,7 @@ fn build_deref_target_impls(cx: &DocContext,
         let primitive = match *target {
             ResolvedPath { did, .. } if did.is_local() => continue,
             ResolvedPath { did, .. } => {
-                ret.extend(inline::build_impls(cx, tcx, did));
+                ret.extend(inline::build_impls(cx, did));
                 continue
             }
             _ => match target.primitive_type() {
@@ -2525,7 +2510,7 @@ fn build_deref_target_impls(cx: &DocContext,
         };
         if let Some(did) = did {
             if !did.is_local() {
-                inline::build_impl(cx, tcx, did, ret);
+                inline::build_impl(cx, did, ret);
             }
         }
     }
@@ -2543,7 +2528,7 @@ fn clean(&self, cx: &DocContext) -> Item {
             name: None,
             attrs: self.attrs.clean(cx),
             source: self.whence.clean(cx),
-            def_id: cx.map.local_def_id(self.id),
+            def_id: cx.tcx.map.local_def_id(self.id),
             visibility: Some(Public),
             stability: None,
             deprecation: None,
@@ -2627,7 +2612,7 @@ fn clean(&self, cx: &DocContext) -> Vec<Item> {
             name: None,
             attrs: self.attrs.clean(cx),
             source: self.whence.clean(cx),
-            def_id: cx.map.local_def_id(ast::CRATE_NODE_ID),
+            def_id: cx.tcx.map.local_def_id(ast::CRATE_NODE_ID),
             visibility: self.vis.clean(cx),
             stability: None,
             deprecation: None,
@@ -2706,10 +2691,10 @@ fn clean(&self, cx: &DocContext) -> Item {
             name: Some(self.name.clean(cx)),
             attrs: self.attrs.clean(cx),
             source: self.span.clean(cx),
-            def_id: cx.map.local_def_id(self.id),
+            def_id: cx.tcx.map.local_def_id(self.id),
             visibility: self.vis.clean(cx),
-            stability: get_stability(cx, cx.map.local_def_id(self.id)),
-            deprecation: get_deprecation(cx, cx.map.local_def_id(self.id)),
+            stability: get_stability(cx, cx.tcx.map.local_def_id(self.id)),
+            deprecation: get_deprecation(cx, cx.tcx.map.local_def_id(self.id)),
             inner: inner,
         }
     }
@@ -2776,22 +2761,7 @@ fn resolve_type(cx: &DocContext,
                 path: Path,
                 id: ast::NodeId) -> Type {
     debug!("resolve_type({:?},{:?})", path, id);
-    let tcx = match cx.tcx_opt() {
-        Some(tcx) => tcx,
-        // If we're extracting tests, this return value's accuracy is not
-        // important, all we want is a string representation to help people
-        // figure out what doctests are failing.
-        None => {
-            let did = DefId::local(DefIndex::from_u32(0));
-            return ResolvedPath {
-                path: path,
-                typarams: None,
-                did: did,
-                is_generic: false
-            };
-        }
-    };
-    let def = tcx.expect_def(id);
+    let def = cx.tcx.expect_def(id);
     debug!("resolve_type: def={:?}", def);
 
     let is_generic = match def {
@@ -2816,8 +2786,6 @@ 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, TypeKind::Function),
         Def::TyAlias(i) => (i, TypeKind::Typedef),
@@ -2827,7 +2795,7 @@ fn register_def(cx: &DocContext, def: Def) -> DefId {
         Def::Union(i) => (i, TypeKind::Union),
         Def::Mod(i) => (i, TypeKind::Module),
         Def::Static(i, _) => (i, TypeKind::Static),
-        Def::Variant(i) => (tcx.parent_def_id(i).unwrap(), TypeKind::Enum),
+        Def::Variant(i) => (cx.tcx.parent_def_id(i).unwrap(), TypeKind::Enum),
         Def::SelfTy(Some(def_id), _) => (def_id, TypeKind::Trait),
         Def::SelfTy(_, Some(impl_def_id)) => {
             return impl_def_id
@@ -2837,7 +2805,7 @@ fn register_def(cx: &DocContext, def: Def) -> DefId {
     if did.is_local() { return did }
     inline::record_extern_fqn(cx, did, kind);
     if let TypeKind::Trait = kind {
-        let t = inline::build_external_trait(cx, tcx, did);
+        let t = inline::build_external_trait(cx, did);
         cx.external_traits.borrow_mut().insert(did, t);
     }
     did
@@ -2851,9 +2819,7 @@ fn resolve_use_source(cx: &DocContext, path: Path, id: ast::NodeId) -> ImportSou
 }
 
 fn resolve_def(cx: &DocContext, id: ast::NodeId) -> Option<DefId> {
-    cx.tcx_opt().and_then(|tcx| {
-        tcx.expect_def_or_none(id).map(|def| register_def(cx, def))
-    })
+    cx.tcx.expect_def_or_none(id).map(|def| register_def(cx, def))
 }
 
 #[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
@@ -2872,7 +2838,7 @@ fn clean(&self, cx: &DocContext) -> Item {
             visibility: Some(Public),
             stability: self.stab.clean(cx),
             deprecation: self.depr.clean(cx),
-            def_id: cx.map.local_def_id(self.id),
+            def_id: cx.tcx.map.local_def_id(self.id),
             inner: MacroItem(Macro {
                 source: format!("macro_rules! {} {{\n{}}}",
                                 name,
index 19e084905aa92a03f0804fc93a6a7b0aac1238e3..7240f0aedbd2770fd38ab4da16a0fdff138faa41 100644 (file)
@@ -153,7 +153,7 @@ fn trait_is_same_or_supertrait(cx: &DocContext, child: DefId,
     if child == trait_ {
         return true
     }
-    let predicates = cx.tcx().item_super_predicates(child).predicates;
+    let predicates = cx.tcx.item_super_predicates(child).predicates;
     predicates.iter().filter_map(|pred| {
         if let ty::Predicate::Trait(ref pred) = *pred {
             if pred.0.trait_ref.self_ty().is_self() {
index a25cb0bacc5cf785610a2bc634d8535868b80882..7d7b7fead5854d9fbd9944dc32f7e904fb6e8d32 100644 (file)
@@ -7,7 +7,6 @@
 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
-pub use self::MaybeTyped::*;
 
 use rustc_lint;
 use rustc_driver::{driver, target_features, abort_on_err};
 pub use rustc::session::config::Input;
 pub use rustc::session::search_paths::SearchPaths;
 
-/// Are we generating documentation (`Typed`) or tests (`NotTyped`)?
-pub enum MaybeTyped<'a, 'tcx: 'a> {
-    Typed(TyCtxt<'a, 'tcx, 'tcx>),
-    NotTyped(&'a session::Session)
-}
-
 pub type ExternalPaths = FxHashMap<DefId, (Vec<String>, clean::TypeKind)>;
 
 pub struct DocContext<'a, 'tcx: 'a> {
-    pub map: &'a hir_map::Map<'tcx>,
-    pub maybe_typed: MaybeTyped<'a, 'tcx>,
+    pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
     pub input: Input,
     pub populated_all_crate_impls: Cell<bool>,
-    pub deref_trait_did: Cell<Option<DefId>>,
-    pub deref_mut_trait_did: Cell<Option<DefId>>,
     // 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.
@@ -77,24 +67,9 @@ pub struct DocContext<'a, 'tcx: 'a> {
     pub export_map: ExportMap,
 }
 
-impl<'b, 'tcx> DocContext<'b, 'tcx> {
-    pub fn sess<'a>(&'a self) -> &'a session::Session {
-        match self.maybe_typed {
-            Typed(tcx) => &tcx.sess,
-            NotTyped(ref sess) => sess
-        }
-    }
-
-    pub fn tcx_opt<'a>(&'a self) -> Option<TyCtxt<'a, 'tcx, 'tcx>> {
-        match self.maybe_typed {
-            Typed(tcx) => Some(tcx),
-            NotTyped(_) => None
-        }
-    }
-
-    pub fn tcx<'a>(&'a self) -> TyCtxt<'a, 'tcx, 'tcx> {
-        let tcx_opt = self.tcx_opt();
-        tcx_opt.expect("tcx not present")
+impl<'a, 'tcx> DocContext<'a, 'tcx> {
+    pub fn sess(&self) -> &session::Session {
+        &self.tcx.sess
     }
 
     /// Call the closure with the given parameters set as
@@ -208,12 +183,9 @@ pub fn run_core(search_paths: SearchPaths,
         };
 
         let ctxt = DocContext {
-            map: &tcx.map,
-            maybe_typed: Typed(tcx),
+            tcx: tcx,
             input: input,
             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),
             external_traits: Default::default(),
             renderinfo: Default::default(),
@@ -221,11 +193,11 @@ pub fn run_core(search_paths: SearchPaths,
             lt_substs: Default::default(),
             export_map: export_map,
         };
-        debug!("crate: {:?}", ctxt.map.krate());
+        debug!("crate: {:?}", tcx.map.krate());
 
         let krate = {
             let mut v = RustdocVisitor::new(&ctxt);
-            v.visit(ctxt.map.krate());
+            v.visit(tcx.map.krate());
             v.clean(&ctxt)
         };
 
index 31fbcb5059f82188f25ee6f370e788a8fa3ec827..757db81c4402196fc43e77a6547639117b591b0e 100644 (file)
@@ -53,7 +53,7 @@
 use externalfiles::ExternalHtml;
 
 use serialize::json::{ToJson, Json, as_json};
-use syntax::abi;
+use syntax::{abi, ast};
 use syntax::feature_gate::UnstableFeatures;
 use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId, LOCAL_CRATE};
 use rustc::middle::privacy::AccessLevels;
@@ -62,7 +62,7 @@
 use rustc::util::nodemap::{FxHashMap, FxHashSet};
 use rustc_data_structures::flock;
 
-use clean::{self, Attributes, GetDefId, SelfTy, Mutability};
+use clean::{self, AttributesExt, GetDefId, SelfTy, Mutability};
 use doctree;
 use fold::DocFolder;
 use html::escape::Escape;
@@ -453,30 +453,26 @@ pub fn run(mut krate: clean::Crate,
 
     // Crawl the crate attributes looking for attributes which control how we're
     // going to emit HTML
-    if let Some(attrs) = krate.module.as_ref().map(|m| m.attrs.list("doc")) {
-        for attr in attrs {
-            match *attr {
-                clean::NameValue(ref x, ref s)
-                        if "html_favicon_url" == *x => {
+    if let Some(attrs) = krate.module.as_ref().map(|m| &m.attrs) {
+        for attr in attrs.lists("doc") {
+            let name = attr.name().map(|s| s.as_str());
+            match (name.as_ref().map(|s| &s[..]), attr.value_str()) {
+                (Some("html_favicon_url"), Some(s)) => {
                     scx.layout.favicon = s.to_string();
                 }
-                clean::NameValue(ref x, ref s)
-                        if "html_logo_url" == *x => {
+                (Some("html_logo_url"), Some(s)) => {
                     scx.layout.logo = s.to_string();
                 }
-                clean::NameValue(ref x, ref s)
-                        if "html_playground_url" == *x => {
+                (Some("html_playground_url"), Some(s)) => {
                     markdown::PLAYGROUND.with(|slot| {
                         let name = krate.name.clone();
-                        *slot.borrow_mut() = Some((Some(name), s.clone()));
+                        *slot.borrow_mut() = Some((Some(name), s.to_string()));
                     });
                 }
-                clean::NameValue(ref x, ref s)
-                        if "issue_tracker_base_url" == *x => {
+                (Some("issue_tracker_base_url"), Some(s)) => {
                     scx.issue_tracker_base_url = Some(s.to_string());
                 }
-                clean::Word(ref x)
-                        if "html_no_source" == *x => {
+                (Some("html_no_source"), None) if attr.is_word() => {
                     scx.include_sources = false;
                 }
                 _ => {}
@@ -860,13 +856,16 @@ fn extern_location(e: &clean::ExternalCrate, dst: &Path) -> ExternalLocation {
 
     // Failing that, see if there's an attribute specifying where to find this
     // external crate
-    e.attrs.list("doc").value("html_root_url").map(|url| {
-        let mut url = url.to_owned();
+    e.attrs.lists("doc")
+     .filter(|a| a.check_name("html_root_url"))
+     .filter_map(|a| a.value_str())
+     .map(|url| {
+        let mut url = url.to_string();
         if !url.ends_with("/") {
             url.push('/')
         }
         Remote(url)
-    }).unwrap_or(Unknown) // Well, at least we tried.
+    }).next().unwrap_or(Unknown) // Well, at least we tried.
 }
 
 impl<'a> DocFolder for SourceCollector<'a> {
@@ -2511,49 +2510,47 @@ fn item_enum(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
     Ok(())
 }
 
-fn attribute_without_value(s: &str) -> bool {
-    ["must_use", "no_mangle", "unsafe_destructor_blind_to_params"].iter().any(|x| x == &s)
-}
-
-fn attribute_with_value(s: &str) -> bool {
-    ["export_name", "lang", "link_section", "must_use"].iter().any(|x| x == &s)
-}
-
-fn attribute_with_values(s: &str) -> bool {
-    ["repr"].iter().any(|x| x == &s)
-}
+fn render_attribute(attr: &ast::MetaItem) -> Option<String> {
+    let name = attr.name();
 
-fn render_attribute(attr: &clean::Attribute, recurse: bool) -> Option<String> {
-    match *attr {
-        clean::Word(ref s) if attribute_without_value(&*s) || recurse => {
-            Some(format!("{}", s))
-        }
-        clean::NameValue(ref k, ref v) if attribute_with_value(&*k) => {
-            Some(format!("{} = \"{}\"", k, v))
-        }
-        clean::List(ref k, ref values) if attribute_with_values(&*k) => {
-            let display: Vec<_> = values.iter()
-                                        .filter_map(|value| render_attribute(value, true))
-                                        .map(|entry| format!("{}", entry))
-                                        .collect();
+    if attr.is_word() {
+        Some(format!("{}", name))
+    } else if let Some(v) = attr.value_str() {
+        Some(format!("{} = {:?}", name, &v.as_str()[..]))
+    } else if let Some(values) = attr.meta_item_list() {
+        let display: Vec<_> = values.iter().filter_map(|attr| {
+            attr.meta_item().and_then(|mi| render_attribute(mi))
+        }).collect();
 
-            if display.len() > 0 {
-                Some(format!("{}({})", k, display.join(", ")))
-            } else {
-                None
-            }
-        }
-        _ => {
+        if display.len() > 0 {
+            Some(format!("{}({})", name, display.join(", ")))
+        } else {
             None
         }
+    } else {
+        None
     }
 }
 
+const ATTRIBUTE_WHITELIST: &'static [&'static str] = &[
+    "export_name",
+    "lang",
+    "link_section",
+    "must_use",
+    "no_mangle",
+    "repr",
+    "unsafe_destructor_blind_to_params"
+];
+
 fn render_attributes(w: &mut fmt::Formatter, it: &clean::Item) -> fmt::Result {
     let mut attrs = String::new();
 
-    for attr in &it.attrs {
-        if let Some(s) = render_attribute(attr, false) {
+    for attr in &it.attrs.other_attrs {
+        let name = attr.name();
+        if !ATTRIBUTE_WHITELIST.contains(&&name.as_str()[..]) {
+            continue;
+        }
+        if let Some(s) = render_attribute(attr.meta()) {
             attrs.push_str(&format!("#[{}]\n", s));
         }
     }
@@ -2810,7 +2807,7 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi
         }
         write!(w, "</span>")?;
         write!(w, "</h3>\n")?;
-        if let Some(ref dox) = i.impl_item.attrs.value("doc") {
+        if let Some(ref dox) = i.impl_item.doc_value() {
             write!(w, "<div class='docblock'>{}</div>", Markdown(dox))?;
         }
     }
index 3af7c20c1336e91f1941e0ceb50c449b246822ff..60ce7ea53953a5c5dbdef176dd55d0b4d3408785 100644 (file)
@@ -89,7 +89,7 @@ pub mod html {
 pub mod visit_lib;
 pub mod test;
 
-use clean::Attributes;
+use clean::AttributesExt;
 
 struct Output {
     krate: clean::Crate,
@@ -280,43 +280,45 @@ pub fn main_args(args: &[String]) -> isize {
                                                  !matches.opt_present("markdown-no-toc")),
         (false, false) => {}
     }
-    let out = match acquire_input(input, externs, &matches) {
-        Ok(out) => out,
-        Err(s) => {
-            println!("input error: {}", s);
-            return 1;
-        }
-    };
-    let Output { krate, passes, renderinfo } = out;
-    info!("going to format");
-    match matches.opt_str("w").as_ref().map(|s| &**s) {
-        Some("html") | None => {
-            html::render::run(krate, &external_html,
-                              output.unwrap_or(PathBuf::from("doc")),
-                              passes.into_iter().collect(),
-                              css_file_extension,
-                              renderinfo)
-                .expect("failed to generate documentation");
-            0
-        }
-        Some(s) => {
-            println!("unknown output format: {}", s);
-            1
+
+    let output_format = matches.opt_str("w");
+    let res = acquire_input(input, externs, &matches, move |out| {
+        let Output { krate, passes, renderinfo } = out;
+        info!("going to format");
+        match output_format.as_ref().map(|s| &**s) {
+            Some("html") | None => {
+                html::render::run(krate, &external_html,
+                                  output.unwrap_or(PathBuf::from("doc")),
+                                  passes.into_iter().collect(),
+                                  css_file_extension,
+                                  renderinfo)
+                    .expect("failed to generate documentation");
+                0
+            }
+            Some(s) => {
+                println!("unknown output format: {}", s);
+                1
+            }
         }
-    }
+    });
+    res.unwrap_or_else(|s| {
+        println!("input error: {}", s);
+        1
+    })
 }
 
 /// Looks inside the command line arguments to extract the relevant input format
 /// and files and then generates the necessary rustdoc output for formatting.
-fn acquire_input(input: &str,
-                 externs: Externs,
-                 matches: &getopts::Matches) -> Result<Output, String> {
+fn acquire_input<R, F>(input: &str,
+                       externs: Externs,
+                       matches: &getopts::Matches,
+                       f: F)
+                       -> Result<R, String>
+where R: 'static + Send, F: 'static + Send + FnOnce(Output) -> R {
     match matches.opt_str("r").as_ref().map(|s| &**s) {
-        Some("rust") => Ok(rust_input(input, externs, matches)),
+        Some("rust") => Ok(rust_input(input, externs, matches, f)),
         Some(s) => Err(format!("unknown input format: {}", s)),
-        None => {
-            Ok(rust_input(input, externs, matches))
-        }
+        None => Ok(rust_input(input, externs, matches, f))
     }
 }
 
@@ -342,7 +344,8 @@ fn parse_externs(matches: &getopts::Matches) -> Result<Externs, String> {
 /// generated from the cleaned AST of the crate.
 ///
 /// This form of input will run all of the plug/cleaning passes
-fn rust_input(cratefile: &str, externs: Externs, matches: &getopts::Matches) -> Output {
+fn rust_input<R, F>(cratefile: &str, externs: Externs, matches: &getopts::Matches, f: F) -> R
+where R: 'static + Send, F: 'static + Send + FnOnce(Output) -> R {
     let mut default_passes = !matches.opt_present("no-defaults");
     let mut passes = matches.opt_strs("passes");
     let mut plugins = matches.opt_strs("plugins");
@@ -355,6 +358,8 @@ fn rust_input(cratefile: &str, externs: Externs, matches: &getopts::Matches) ->
     let cfgs = matches.opt_strs("cfg");
     let triple = matches.opt_str("target");
     let maybe_sysroot = matches.opt_str("sysroot").map(PathBuf::from);
+    let crate_name = matches.opt_str("crate-name");
+    let plugin_path = matches.opt_str("plugin-path");
 
     let cr = PathBuf::from(cratefile);
     info!("starting to run rustc");
@@ -363,67 +368,68 @@ fn rust_input(cratefile: &str, externs: Externs, matches: &getopts::Matches) ->
     rustc_driver::monitor(move || {
         use rustc::session::config::Input;
 
-        tx.send(core::run_core(paths, cfgs, externs, Input::File(cr),
-                               triple, maybe_sysroot)).unwrap();
-    });
-    let (mut krate, renderinfo) = rx.recv().unwrap();
-    info!("finished with rustc");
+        let (mut krate, renderinfo) =
+            core::run_core(paths, cfgs, externs, Input::File(cr), triple, maybe_sysroot);
 
-    if let Some(name) = matches.opt_str("crate-name") {
-        krate.name = name
-    }
+        info!("finished with rustc");
 
-    // Process all of the crate attributes, extracting plugin metadata along
-    // with the passes which we are supposed to run.
-    for attr in krate.module.as_ref().unwrap().attrs.list("doc") {
-        match *attr {
-            clean::Word(ref w) if "no_default_passes" == *w => {
-                default_passes = false;
-            },
-            clean::NameValue(ref name, ref value) => {
-                let sink = match &name[..] {
-                    "passes" => &mut passes,
-                    "plugins" => &mut plugins,
+        if let Some(name) = crate_name {
+            krate.name = name
+        }
+
+        // Process all of the crate attributes, extracting plugin metadata along
+        // with the passes which we are supposed to run.
+        for attr in krate.module.as_ref().unwrap().attrs.lists("doc") {
+            let name = attr.name().map(|s| s.as_str());
+            let name = name.as_ref().map(|s| &s[..]);
+            if attr.is_word() {
+                if name == Some("no_default_passes") {
+                    default_passes = false;
+                }
+            } else if let Some(value) = attr.value_str() {
+                let sink = match name {
+                    Some("passes") => &mut passes,
+                    Some("plugins") => &mut plugins,
                     _ => continue,
                 };
-                for p in value.split_whitespace() {
+                for p in value.as_str().split_whitespace() {
                     sink.push(p.to_string());
                 }
             }
-            _ => (),
         }
-    }
 
-    if default_passes {
-        for name in passes::DEFAULT_PASSES.iter().rev() {
-            passes.insert(0, name.to_string());
+        if default_passes {
+            for name in passes::DEFAULT_PASSES.iter().rev() {
+                passes.insert(0, name.to_string());
+            }
         }
-    }
 
-    // Load all plugins/passes into a PluginManager
-    let path = matches.opt_str("plugin-path")
-                      .unwrap_or("/tmp/rustdoc/plugins".to_string());
-    let mut pm = plugins::PluginManager::new(PathBuf::from(path));
-    for pass in &passes {
-        let plugin = match passes::PASSES.iter()
-                                         .position(|&(p, ..)| {
-                                             p == *pass
-                                         }) {
-            Some(i) => passes::PASSES[i].1,
-            None => {
-                error!("unknown pass {}, skipping", *pass);
-                continue
-            },
-        };
-        pm.add_plugin(plugin);
-    }
-    info!("loading plugins...");
-    for pname in plugins {
-        pm.load_plugin(pname);
-    }
+        // Load all plugins/passes into a PluginManager
+        let path = plugin_path.unwrap_or("/tmp/rustdoc/plugins".to_string());
+        let mut pm = plugins::PluginManager::new(PathBuf::from(path));
+        for pass in &passes {
+            let plugin = match passes::PASSES.iter()
+                                             .position(|&(p, ..)| {
+                                                 p == *pass
+                                             }) {
+                Some(i) => passes::PASSES[i].1,
+                None => {
+                    error!("unknown pass {}, skipping", *pass);
+                    continue
+                },
+            };
+            pm.add_plugin(plugin);
+        }
+        info!("loading plugins...");
+        for pname in plugins {
+            pm.load_plugin(pname);
+        }
+
+        // Run everything!
+        info!("Executing passes/plugins");
+        let krate = pm.run_plugins(krate);
 
-    // Run everything!
-    info!("Executing passes/plugins");
-    let krate = pm.run_plugins(krate);
-    Output { krate: krate, renderinfo: renderinfo, passes: passes }
+        tx.send(f(Output { krate: krate, renderinfo: renderinfo, passes: passes })).unwrap();
+    });
+    rx.recv().unwrap()
 }
index c034ef9326846c349b7761606918c72bd1fad35d..3c63302127c5eef17b7df6e4818d3851d1f9db0d 100644 (file)
@@ -8,40 +8,33 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use std::string::String;
-
 use clean::{self, Item};
 use plugins;
 use fold;
 use fold::DocFolder;
 
 pub fn collapse_docs(krate: clean::Crate) -> plugins::PluginResult {
-    let mut collapser = Collapser;
-    let krate = collapser.fold_crate(krate);
-    krate
+    Collapser.fold_crate(krate)
 }
 
 struct Collapser;
 
 impl fold::DocFolder for Collapser {
     fn fold_item(&mut self, mut i: Item) -> Option<Item> {
-        let mut docstr = String::new();
-        for attr in &i.attrs {
-            if let clean::NameValue(ref x, ref s) = *attr {
-                if "doc" == *x {
-                    docstr.push_str(s);
-                    docstr.push('\n');
-                }
-            }
-        }
-        let mut a: Vec<clean::Attribute> = i.attrs.iter().filter(|&a| match a {
-            &clean::NameValue(ref x, _) if "doc" == *x => false,
-            _ => true
-        }).cloned().collect();
-        if !docstr.is_empty() {
-            a.push(clean::NameValue("doc".to_string(), docstr));
-        }
-        i.attrs = a;
+        i.attrs.collapse_doc_comments();
         self.fold_item_recur(i)
     }
 }
+
+impl clean::Attributes {
+    pub fn collapse_doc_comments(&mut self) {
+        let mut doc_string = self.doc_strings.join("\n");
+        if doc_string.is_empty() {
+            self.doc_strings = vec![];
+        } else {
+            // FIXME(eddyb) Is this still needed?
+            doc_string.push('\n');
+            self.doc_strings = vec![doc_string];
+        }
+    }
+}
index 927ccf917199978221c2488262aa97e838869e03..68c1231fc6f7c58e7266ee3e3c52708fa36e7b68 100644 (file)
@@ -11,7 +11,7 @@
 use rustc::util::nodemap::DefIdSet;
 use std::mem;
 
-use clean::{self, Attributes};
+use clean::{self, AttributesExt, NestedAttributesExt};
 use clean::Item;
 use plugins;
 use fold;
@@ -41,7 +41,7 @@ struct Stripper<'a> {
 
 impl<'a> fold::DocFolder for Stripper<'a> {
     fn fold_item(&mut self, i: Item) -> Option<Item> {
-        if i.attrs.list("doc").has_word("hidden") {
+        if i.attrs.lists("doc").has_word("hidden") {
             debug!("found one in strip_hidden; removing");
             // use a dedicated hidden item for given item type if any
             match i.inner {
index 20640f3f88518f98d2c8f7269a9377a9f698559e..4d94c30847852f42ce5393049f4b3ee22d6cecea 100644 (file)
 use fold::{self, DocFolder};
 
 pub fn unindent_comments(krate: clean::Crate) -> plugins::PluginResult {
-    let mut cleaner = CommentCleaner;
-    let krate = cleaner.fold_crate(krate);
-    krate
+    CommentCleaner.fold_crate(krate)
 }
 
 struct CommentCleaner;
 
 impl fold::DocFolder for CommentCleaner {
     fn fold_item(&mut self, mut i: Item) -> Option<Item> {
-        let mut avec: Vec<clean::Attribute> = Vec::new();
-        for attr in &i.attrs {
-            match attr {
-                &clean::NameValue(ref x, ref s)
-                        if "doc" == *x => {
-                    avec.push(clean::NameValue("doc".to_string(),
-                                               unindent(s)))
-                }
-                x => avec.push(x.clone())
-            }
-        }
-        i.attrs = avec;
+        i.attrs.unindent_doc_comments();
         self.fold_item_recur(i)
     }
 }
 
+impl clean::Attributes {
+    pub fn unindent_doc_comments(&mut self) {
+        for doc_string in &mut self.doc_strings {
+            *doc_string = unindent(doc_string);
+        }
+    }
+}
+
 fn unindent(s: &str) -> String {
     let lines = s.lines().collect::<Vec<&str> >();
     let mut saw_first_line = false;
index 12d33dcb207f7c78ab170e5cbb69439a8b27b098..9f29319430dd5f4688444904fa55295170f32ed8 100644 (file)
@@ -8,7 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use std::cell::Cell;
 use std::env;
 use std::ffi::OsString;
 use std::io::prelude::*;
@@ -23,7 +22,8 @@
 use testing;
 use rustc_lint;
 use rustc::dep_graph::DepGraph;
-use rustc::hir::map as hir_map;
+use rustc::hir;
+use rustc::hir::intravisit;
 use rustc::session::{self, config};
 use rustc::session::config::{OutputType, OutputTypes, Externs};
 use rustc::session::search_paths::{SearchPaths, PathKind};
 use rustc_driver::driver::phase_2_configure_and_expand;
 use rustc_metadata::cstore::CStore;
 use rustc_resolve::MakeGlobMap;
+use rustc_trans::back::link;
+use syntax::ast;
 use syntax::codemap::CodeMap;
 use syntax::feature_gate::UnstableFeatures;
 use errors;
 use errors::emitter::ColorConfig;
 
-use core;
-use clean;
-use clean::Clean;
-use fold::DocFolder;
+use clean::Attributes;
 use html::markdown;
-use passes;
-use visit_ast::RustdocVisitor;
 
 #[derive(Clone, Default)]
 pub struct TestOptions {
@@ -87,48 +84,36 @@ pub fn run(input: &str,
         config::build_configuration(&sess, config::parse_cfgspecs(cfgs.clone()));
 
     let krate = panictry!(driver::phase_1_parse_input(&sess, &input));
-    let driver::ExpansionResult { defs, mut hir_forest, analysis, .. } = {
+    let driver::ExpansionResult { defs, mut hir_forest, .. } = {
         phase_2_configure_and_expand(
             &sess, &cstore, krate, None, "rustdoc-test", None, MakeGlobMap::No, |_| Ok(())
         ).expect("phase_2_configure_and_expand aborted in rustdoc!")
     };
 
-    let dep_graph = DepGraph::new(false);
+    let crate_name = crate_name.unwrap_or_else(|| {
+        link::find_crate_name(None, &hir_forest.krate().attrs, &input)
+    });
     let opts = scrape_test_config(hir_forest.krate());
-    let _ignore = dep_graph.in_ignore();
-    let map = hir_map::map_crate(&mut hir_forest, defs);
-
-    let ctx = core::DocContext {
-        map: &map,
-        maybe_typed: core::NotTyped(&sess),
-        input: input,
-        populated_all_crate_impls: Cell::new(false),
-        external_traits: 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(),
-        export_map: analysis.export_map,
-    };
-
-    let mut v = RustdocVisitor::new(&ctx);
-    v.visit(ctx.map.krate());
-    let mut krate = v.clean(&ctx);
-    if let Some(name) = crate_name {
-        krate.name = name;
-    }
-    let krate = passes::collapse_docs(krate);
-    let krate = passes::unindent_comments(krate);
-
-    let mut collector = Collector::new(krate.name.to_string(),
+    let mut collector = Collector::new(crate_name,
                                        cfgs,
                                        libs,
                                        externs,
                                        false,
                                        opts);
-    collector.fold_crate(krate);
+
+    {
+        let dep_graph = DepGraph::new(false);
+        let _ignore = dep_graph.in_ignore();
+        let map = hir::map::map_crate(&mut hir_forest, defs);
+        let krate = map.krate();
+        let mut hir_collector = HirCollector {
+            collector: &mut collector,
+            map: &map
+        };
+        hir_collector.visit_testable("".to_string(), &krate.attrs, |this| {
+            intravisit::walk_crate(this, krate);
+        });
+    }
 
     test_args.insert(0, "rustdoctest".to_string());
 
@@ -472,56 +457,84 @@ pub fn register_header(&mut self, name: &str, level: u32) {
     }
 }
 
-impl DocFolder for Collector {
-    fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
-        let current_name = match item.name {
-            Some(ref name) if !name.is_empty() => Some(name.clone()),
-            _ => typename_if_impl(&item)
-        };
+struct HirCollector<'a, 'hir: 'a> {
+    collector: &'a mut Collector,
+    map: &'a hir::map::Map<'hir>
+}
 
-        let pushed = current_name.map(|name| self.names.push(name)).is_some();
+impl<'a, 'hir> HirCollector<'a, 'hir> {
+    fn visit_testable<F: FnOnce(&mut Self)>(&mut self,
+                                            name: String,
+                                            attrs: &[ast::Attribute],
+                                            nested: F) {
+        let has_name = !name.is_empty();
+        if has_name {
+            self.collector.names.push(name);
+        }
 
-        if let Some(doc) = item.doc_value() {
-            self.cnt = 0;
-            markdown::find_testable_code(doc, &mut *self);
+        let mut attrs = Attributes::from_ast(attrs);
+        attrs.collapse_doc_comments();
+        attrs.unindent_doc_comments();
+        if let Some(doc) = attrs.doc_value() {
+            self.collector.cnt = 0;
+            markdown::find_testable_code(doc, self.collector);
         }
 
-        let ret = self.fold_item_recur(item);
-        if pushed {
-            self.names.pop();
+        nested(self);
+
+        if has_name {
+            self.collector.names.pop();
         }
+    }
+}
+
+impl<'a, 'hir> intravisit::Visitor<'hir> for HirCollector<'a, 'hir> {
+    fn nested_visit_map(&mut self) -> Option<&hir::map::Map<'hir>> {
+        Some(self.map)
+    }
+
+    fn visit_item(&mut self, item: &'hir hir::Item) {
+        let name = if let hir::ItemImpl(.., ref ty, _) = item.node {
+            hir::print::ty_to_string(ty)
+        } else {
+            item.name.to_string()
+        };
 
-        return ret;
+        self.visit_testable(name, &item.attrs, |this| {
+            intravisit::walk_item(this, item);
+        });
+    }
 
-        // FIXME: it would be better to not have the escaped version in the first place
-        fn unescape_for_testname(mut s: String) -> String {
-            // for refs `&foo`
-            if s.contains("&amp;") {
-                s = s.replace("&amp;", "&");
+    fn visit_trait_item(&mut self, item: &'hir hir::TraitItem) {
+        self.visit_testable(item.name.to_string(), &item.attrs, |this| {
+            intravisit::walk_trait_item(this, item);
+        });
+    }
 
-                // `::&'a mut Foo::` looks weird, let's make it `::<&'a mut Foo>`::
-                if let Some('&') = s.chars().nth(0) {
-                    s = format!("<{}>", s);
-                }
-            }
+    fn visit_impl_item(&mut self, item: &'hir hir::ImplItem) {
+        self.visit_testable(item.name.to_string(), &item.attrs, |this| {
+            intravisit::walk_impl_item(this, item);
+        });
+    }
 
-            // either `<..>` or `->`
-            if s.contains("&gt;") {
-                s.replace("&gt;", ">")
-                 .replace("&lt;", "<")
-            } else {
-                s
-            }
-        }
+    fn visit_foreign_item(&mut self, item: &'hir hir::ForeignItem) {
+        self.visit_testable(item.name.to_string(), &item.attrs, |this| {
+            intravisit::walk_foreign_item(this, item);
+        });
+    }
 
-        fn typename_if_impl(item: &clean::Item) -> Option<String> {
-            if let clean::ItemEnum::ImplItem(ref impl_) = item.inner {
-                let path = impl_.for_.to_string();
-                let unescaped_path = unescape_for_testname(path);
-                Some(unescaped_path)
-            } else {
-                None
-            }
-        }
+    fn visit_variant(&mut self,
+                     v: &'hir hir::Variant,
+                     g: &'hir hir::Generics,
+                     item_id: ast::NodeId) {
+        self.visit_testable(v.node.name.to_string(), &v.node.attrs, |this| {
+            intravisit::walk_variant(this, v, g, item_id);
+        });
+    }
+
+    fn visit_struct_field(&mut self, f: &'hir hir::StructField) {
+        self.visit_testable(f.name.to_string(), &f.attrs, |this| {
+            intravisit::walk_struct_field(this, f);
+        });
     }
 }
index 939fd6ccfc88e0e6f337d4fe04a4cc03d867f31e..8ed0567d820ac4af27ea5df04f26f3700374e3ee 100644 (file)
@@ -28,7 +28,7 @@
 use rustc::hir;
 
 use core;
-use clean::{self, Clean, Attributes};
+use clean::{self, AttributesExt, NestedAttributesExt};
 use doctree::*;
 
 // looks to me like the first two of these are actually
@@ -65,18 +65,13 @@ pub fn new(cx: &'a core::DocContext<'a, 'tcx>) -> RustdocVisitor<'a, 'tcx> {
     }
 
     fn stability(&self, id: ast::NodeId) -> Option<attr::Stability> {
-        self.cx.tcx_opt().and_then(|tcx| {
-            self.cx.map.opt_local_def_id(id)
-                       .and_then(|def_id| tcx.lookup_stability(def_id))
-                       .cloned()
-        })
+        self.cx.tcx.map.opt_local_def_id(id)
+            .and_then(|def_id| self.cx.tcx.lookup_stability(def_id)).cloned()
     }
 
     fn deprecation(&self, id: ast::NodeId) -> Option<attr::Deprecation> {
-        self.cx.tcx_opt().and_then(|tcx| {
-            self.cx.map.opt_local_def_id(id)
-                       .and_then(|def_id| tcx.lookup_deprecation(def_id))
-        })
+        self.cx.tcx.map.opt_local_def_id(id)
+            .and_then(|def_id| self.cx.tcx.lookup_deprecation(def_id))
     }
 
     pub fn visit(&mut self, krate: &hir::Crate) {
@@ -196,7 +191,7 @@ pub fn visit_mod_contents(&mut self, span: Span, attrs: hir::HirVec<ast::Attribu
         let orig_inside_public_path = self.inside_public_path;
         self.inside_public_path &= vis == hir::Public;
         for i in &m.item_ids {
-            let item = self.cx.map.expect_item(i.id);
+            let item = self.cx.tcx.map.expect_item(i.id);
             self.visit_item(item, None, &mut om);
         }
         self.inside_public_path = orig_inside_public_path;
@@ -279,10 +274,9 @@ fn maybe_inline_local(&mut self, id: ast::NodeId, renamed: Option<ast::Name>,
                   glob: bool, om: &mut Module, please_inline: bool) -> bool {
 
         fn inherits_doc_hidden(cx: &core::DocContext, mut node: ast::NodeId) -> bool {
-            while let Some(id) = cx.map.get_enclosing_scope(node) {
+            while let Some(id) = cx.tcx.map.get_enclosing_scope(node) {
                 node = id;
-                let attrs = cx.map.attrs(node).clean(cx);
-                if attrs.list("doc").has_word("hidden") {
+                if cx.tcx.map.attrs(node).lists("doc").has_word("hidden") {
                     return true;
                 }
                 if node == ast::CRATE_NODE_ID {
@@ -292,25 +286,22 @@ fn inherits_doc_hidden(cx: &core::DocContext, mut node: ast::NodeId) -> bool {
             false
         }
 
-        let tcx = match self.cx.tcx_opt() {
-            Some(tcx) => tcx,
-            None => return false
-        };
+        let tcx = self.cx.tcx;
         let def = tcx.expect_def(id);
         let def_did = def.def_id();
 
-        let use_attrs = tcx.map.attrs(id).clean(self.cx);
+        let use_attrs = tcx.map.attrs(id);
         // Don't inline doc(hidden) imports so they can be stripped at a later stage.
-        let is_no_inline = use_attrs.list("doc").has_word("no_inline") ||
-                           use_attrs.list("doc").has_word("hidden");
+        let is_no_inline = use_attrs.lists("doc").has_word("no_inline") ||
+                           use_attrs.lists("doc").has_word("hidden");
 
         // For cross-crate impl inlining we need to know whether items are
         // reachable in documentation - a previously nonreachable item can be
         // made reachable by cross-crate inlining which we're checking here.
         // (this is done here because we need to know this upfront)
         if !def_did.is_local() && !is_no_inline {
-            let attrs = clean::inline::load_attrs(self.cx, tcx, def_did);
-            let self_is_hidden = attrs.list("doc").has_word("hidden");
+            let attrs = clean::inline::load_attrs(self.cx, def_did);
+            let self_is_hidden = attrs.lists("doc").has_word("hidden");
             match def {
                 Def::Trait(did) |
                 Def::Struct(did) |
@@ -348,7 +339,7 @@ fn inherits_doc_hidden(cx: &core::DocContext, mut node: ast::NodeId) -> bool {
                     match it.node {
                         hir::ItemMod(ref m) => {
                             for i in &m.item_ids {
-                                let i = self.cx.map.expect_item(i.id);
+                                let i = self.cx.tcx.map.expect_item(i.id);
                                 self.visit_item(i, None, om);
                             }
                         }
@@ -507,7 +498,7 @@ pub fn visit_item(&mut self, item: &hir::Item,
                 // regardless of where they're located.
                 if !self.inlining {
                     let items = item_ids.iter()
-                                        .map(|ii| self.cx.map.impl_item(ii.id).clone())
+                                        .map(|ii| self.cx.tcx.map.impl_item(ii.id).clone())
                                         .collect();
                     let i = Impl {
                         unsafety: unsafety,
index 6d2830c56192bb434b73485384b6a9681d8d7d8b..cee292f99153e4fc318463094d1633f8ac8e6074 100644 (file)
@@ -16,7 +16,7 @@
 
 use std::cell::RefMut;
 
-use clean::{Attributes, Clean};
+use clean::{AttributesExt, NestedAttributesExt};
 
 // FIXME: this may not be exhaustive, but is sufficient for rustdocs current uses
 
@@ -49,10 +49,7 @@ pub fn visit_lib(&mut self, cnum: CrateNum) {
 
     // Updates node level and returns the updated level
     fn update(&mut self, did: DefId, level: Option<AccessLevel>) -> Option<AccessLevel> {
-        let attrs: Vec<_> = self.cx.tcx().get_attrs(did).iter()
-                                                        .map(|a| a.clean(self.cx))
-                                                        .collect();
-        let is_hidden = attrs.list("doc").has_word("hidden");
+        let is_hidden = self.cx.tcx.get_attrs(did).lists("doc").has_word("hidden");
 
         let old_level = self.access_levels.map.get(&did).cloned();
         // Accessibility levels can only grow
index e29dbe35c5a59a242c592fd0dc0c3c3c5adb47ab..baa2b5d2846220c3ea41e1e3622f267cc43a3804 100644 (file)
@@ -546,17 +546,23 @@ pub fn current_exe() -> io::Result<PathBuf> {
     os_imp::current_exe()
 }
 
-/// An iterator over the arguments of a process, yielding a `String` value
+/// An iterator over the arguments of a process, yielding a [`String`] value
 /// for each argument.
 ///
-/// This structure is created through the `std::env::args` method.
+/// This structure is created through the [`std::env::args`] method.
+///
+/// [`String`]: ../string/struct.String.html
+/// [`std::env::args`]: ./fn.args.html
 #[stable(feature = "env", since = "1.0.0")]
 pub struct Args { inner: ArgsOs }
 
-/// An iterator over the arguments of a process, yielding an `OsString` value
+/// An iterator over the arguments of a process, yielding an [`OsString`] value
 /// for each argument.
 ///
-/// This structure is created through the `std::env::args_os` method.
+/// This structure is created through the [`std::env::args_os`] method.
+///
+/// [`OsString`]: ../ffi/struct.OsString.html
+/// [`std::env::args_os`]: ./fn.args_os.html
 #[stable(feature = "env", since = "1.0.0")]
 pub struct ArgsOs { inner: sys::args::Args }
 
@@ -571,7 +577,7 @@ pub struct ArgsOs { inner: sys::args::Args }
 ///
 /// The returned iterator will panic during iteration if any argument to the
 /// process is not valid unicode. If this is not desired,
-/// use the `args_os` function instead.
+/// use the [`args_os`] function instead.
 ///
 /// # Examples
 ///
@@ -583,6 +589,8 @@ pub struct ArgsOs { inner: sys::args::Args }
 ///     println!("{}", argument);
 /// }
 /// ```
+///
+/// [`args_os`]: ./fn.args_os.html
 #[stable(feature = "env", since = "1.0.0")]
 pub fn args() -> Args {
     Args { inner: args_os() }
index df5741d00a2c10b08dce46127377e6a8cebf2cf7..e91e808c5489a48a6a2d2cd03929e73384996a8d 100644 (file)
@@ -348,6 +348,41 @@ pub fn try_clone(&self) -> io::Result<File> {
             inner: self.inner.duplicate()?
         })
     }
+
+    /// Changes the permissions on the underlying file.
+    ///
+    /// # Platform-specific behavior
+    ///
+    /// This function currently corresponds to the `fchmod` function on Unix and
+    /// the `SetFileInformationByHandle` function on Windows. Note that, this
+    /// [may change in the future][changes].
+    ///
+    /// [changes]: ../io/index.html#platform-specific-behavior
+    ///
+    /// # Errors
+    ///
+    /// This function will return an error if the user lacks permission change
+    /// attributes on the underlying file. It may also return an error in other
+    /// os-specific unspecified cases.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(set_permissions_atomic)]
+    /// # fn foo() -> std::io::Result<()> {
+    /// use std::fs::File;
+    ///
+    /// let file = File::open("foo.txt")?;
+    /// let mut perms = file.metadata()?.permissions();
+    /// perms.set_readonly(true);
+    /// file.set_permissions(perms)?;
+    /// # Ok(())
+    /// # }
+    /// ```
+    #[unstable(feature = "set_permissions_atomic", issue="37916")]
+    pub fn set_permissions(&self, perm: Permissions) -> io::Result<()> {
+        self.inner.set_permissions(perm.0)
+    }
 }
 
 impl AsInner<fs_imp::File> for File {
@@ -2469,6 +2504,24 @@ fn chmod_works() {
         check!(fs::set_permissions(&file, p));
     }
 
+    #[test]
+    fn fchmod_works() {
+        let tmpdir = tmpdir();
+        let path = tmpdir.join("in.txt");
+
+        let file = check!(File::create(&path));
+        let attr = check!(fs::metadata(&path));
+        assert!(!attr.permissions().readonly());
+        let mut p = attr.permissions();
+        p.set_readonly(true);
+        check!(file.set_permissions(p.clone()));
+        let attr = check!(fs::metadata(&path));
+        assert!(attr.permissions().readonly());
+
+        p.set_readonly(false);
+        check!(file.set_permissions(p));
+    }
+
     #[test]
     fn sync_doesnt_kill_anything() {
         let tmpdir = tmpdir();
index 1c016015b7928c9b9da3343bc6fb81b9a7e901b4..0328012ee57269a4411c6499da22de23907ff027 100644 (file)
@@ -194,6 +194,14 @@ pub fn is_ipv6(&self) -> bool {
 
 impl SocketAddrV4 {
     /// Creates a new socket address from the (ip, port) pair.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::{SocketAddrV4, Ipv4Addr};
+    ///
+    /// let socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080);
+    /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn new(ip: Ipv4Addr, port: u16) -> SocketAddrV4 {
         SocketAddrV4 {
@@ -207,6 +215,15 @@ pub fn new(ip: Ipv4Addr, port: u16) -> SocketAddrV4 {
     }
 
     /// Returns the IP address associated with this socket address.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::{SocketAddrV4, Ipv4Addr};
+    ///
+    /// let socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080);
+    /// assert_eq!(socket.ip(), &Ipv4Addr::new(127, 0, 0, 1));
+    /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn ip(&self) -> &Ipv4Addr {
         unsafe {
@@ -215,18 +232,47 @@ pub fn ip(&self) -> &Ipv4Addr {
     }
 
     /// Change the IP address associated with this socket address.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::{SocketAddrV4, Ipv4Addr};
+    ///
+    /// let mut socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080);
+    /// socket.set_ip(Ipv4Addr::new(192, 168, 0, 1));
+    /// assert_eq!(socket.ip(), &Ipv4Addr::new(192, 168, 0, 1));
+    /// ```
     #[stable(feature = "sockaddr_setters", since = "1.9.0")]
     pub fn set_ip(&mut self, new_ip: Ipv4Addr) {
         self.inner.sin_addr = *new_ip.as_inner()
     }
 
     /// Returns the port number associated with this socket address.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::{SocketAddrV4, Ipv4Addr};
+    ///
+    /// let socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080);
+    /// assert_eq!(socket.port(), 8080);
+    /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn port(&self) -> u16 {
         ntoh(self.inner.sin_port)
     }
 
     /// Change the port number associated with this socket address.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::{SocketAddrV4, Ipv4Addr};
+    ///
+    /// let mut socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080);
+    /// socket.set_port(4242);
+    /// assert_eq!(socket.port(), 4242);
+    /// ```
     #[stable(feature = "sockaddr_setters", since = "1.9.0")]
     pub fn set_port(&mut self, new_port: u16) {
         self.inner.sin_port = hton(new_port);
index 0b43fd2ac8c4df3a670c2899046ba9c0f1c301e2..9ee0458b5da365d1fae1c99bfa17fbdf0d20113f 100644 (file)
@@ -526,6 +526,11 @@ pub fn duplicate(&self) -> io::Result<File> {
     pub fn fd(&self) -> &FileDesc { &self.0 }
 
     pub fn into_fd(self) -> FileDesc { self.0 }
+
+    pub fn set_permissions(&self, perm: FilePermissions) -> io::Result<()> {
+        cvt_r(|| unsafe { libc::fchmod(self.0.raw(), perm.mode) })?;
+        Ok(())
+    }
 }
 
 impl DirBuilder {
index dfc998b88e37f69ec8ff94bcfc3a3d0a5d4e6bb6..1a563127f7f0668d69ba11485abdadfd5f49aa7d 100644 (file)
@@ -389,6 +389,15 @@ pub enum FILE_INFO_BY_HANDLE_CLASS {
     MaximumFileInfoByHandlesClass
 }
 
+#[repr(C)]
+pub struct FILE_BASIC_INFO {
+    pub CreationTime: LARGE_INTEGER,
+    pub LastAccessTime: LARGE_INTEGER,
+    pub LastWriteTime: LARGE_INTEGER,
+    pub ChangeTime: LARGE_INTEGER,
+    pub FileAttributes: DWORD,
+}
+
 #[repr(C)]
 pub struct FILE_END_OF_FILE_INFO {
     pub EndOfFile: LARGE_INTEGER,
index 98fd15f863ba10ad0c18a1f404d00db98a6e88b7..7d7d78bbd87308315d75551a88c9ac5ef4558ac1 100644 (file)
@@ -417,6 +417,24 @@ fn readlink(&self) -> io::Result<PathBuf> {
             Ok(PathBuf::from(OsString::from_wide(subst)))
         }
     }
+
+    pub fn set_permissions(&self, perm: FilePermissions) -> io::Result<()> {
+        let mut info = c::FILE_BASIC_INFO {
+            CreationTime: 0,
+            LastAccessTime: 0,
+            LastWriteTime: 0,
+            ChangeTime: 0,
+            FileAttributes: perm.attrs,
+        };
+        let size = mem::size_of_val(&info);
+        cvt(unsafe {
+            c::SetFileInformationByHandle(self.handle.raw(),
+                                          c::FileBasicInfo,
+                                          &mut info as *mut _ as *mut _,
+                                          size as c::DWORD)
+        })?;
+        Ok(())
+    }
 }
 
 impl FromInner<c::HANDLE> for File {
index bb07efdd9e7231d161d085968b02dbf38e1c199b..2a911aceb9d94e01a8be3187953b019271d6103d 100644 (file)
@@ -999,8 +999,8 @@ pub enum ExprKind {
 
     /// A referencing operation (`&a` or `&mut a`)
     AddrOf(Mutability, P<Expr>),
-    /// A `break`, with an optional label to break
-    Break(Option<SpannedIdent>),
+    /// A `break`, with an optional label to break, and an optional expression
+    Break(Option<SpannedIdent>, Option<P<Expr>>),
     /// A `continue`, with an optional label
     Continue(Option<SpannedIdent>),
     /// A `return`, with an optional value to be returned
index ddf4cf11f204810ff6340d48f8c30c17235b87af..ddbca47429d1876298601836b0ed032e2d1ed1b7 100644 (file)
@@ -18,7 +18,7 @@
 use ext::expand::{self, Expansion};
 use ext::hygiene::Mark;
 use fold::{self, Folder};
-use parse::{self, parser};
+use parse::{self, parser, DirectoryOwnership};
 use parse::token;
 use ptr::P;
 use symbol::Symbol;
@@ -568,9 +568,7 @@ pub struct ExpansionData {
     pub depth: usize,
     pub backtrace: ExpnId,
     pub module: Rc<ModuleData>,
-
-    // True if non-inline modules without a `#[path]` are forbidden at the root of this expansion.
-    pub no_noninline_mod: bool,
+    pub directory_ownership: DirectoryOwnership,
 }
 
 /// One of these is made during expansion and incrementally updated as we go;
@@ -601,7 +599,7 @@ pub fn new(parse_sess: &'a parse::ParseSess,
                 depth: 0,
                 backtrace: NO_EXPANSION,
                 module: Rc::new(ModuleData { mod_path: Vec::new(), directory: PathBuf::new() }),
-                no_noninline_mod: false,
+                directory_ownership: DirectoryOwnership::Owned,
             },
         }
     }
index 324afc20051d4461d3e29d8c58ad34ae812d6e5d..a208b934d79e1da09b7ca1b31ba069b7aca824dd 100644 (file)
@@ -777,7 +777,7 @@ fn expr_none(&self, sp: Span) -> P<ast::Expr> {
 
 
     fn expr_break(&self, sp: Span) -> P<ast::Expr> {
-        self.expr(sp, ast::ExprKind::Break(None))
+        self.expr(sp, ast::ExprKind::Break(None, None))
     }
 
 
index 844fb77e29d79fa70753ef0e2b5c567c1163eeff..fd6cae1e1b6688bbfdea9b91da5935b06d5fad99 100644 (file)
@@ -21,7 +21,7 @@
 use feature_gate::{self, Features};
 use fold;
 use fold::*;
-use parse::{ParseSess, PResult, lexer};
+use parse::{ParseSess, DirectoryOwnership, PResult, lexer};
 use parse::parser::Parser;
 use parse::token;
 use print::pprust;
@@ -727,9 +727,10 @@ fn fold_stmt(&mut self, stmt: ast::Stmt) -> SmallVector<ast::Stmt> {
     }
 
     fn fold_block(&mut self, block: P<Block>) -> P<Block> {
-        let no_noninline_mod = mem::replace(&mut self.cx.current_expansion.no_noninline_mod, true);
+        let old_directory_ownership = self.cx.current_expansion.directory_ownership;
+        self.cx.current_expansion.directory_ownership = DirectoryOwnership::UnownedViaBlock;
         let result = noop_fold_block(block, self);
-        self.cx.current_expansion.no_noninline_mod = no_noninline_mod;
+        self.cx.current_expansion.directory_ownership = old_directory_ownership;
         result
     }
 
@@ -768,7 +769,7 @@ fn fold_item(&mut self, item: P<ast::Item>) -> SmallVector<P<ast::Item>> {
                     return noop_fold_item(item, self);
                 }
 
-                let orig_no_noninline_mod = self.cx.current_expansion.no_noninline_mod;
+                let orig_directory_ownership = self.cx.current_expansion.directory_ownership;
                 let mut module = (*self.cx.current_expansion.module).clone();
                 module.mod_path.push(item.ident);
 
@@ -779,23 +780,28 @@ fn fold_item(&mut self, item: P<ast::Item>) -> SmallVector<P<ast::Item>> {
 
                 if inline_module {
                     if let Some(path) = attr::first_attr_value_str_by_name(&item.attrs, "path") {
-                        self.cx.current_expansion.no_noninline_mod = false;
+                        self.cx.current_expansion.directory_ownership = DirectoryOwnership::Owned;
                         module.directory.push(&*path.as_str());
                     } else {
                         module.directory.push(&*item.ident.name.as_str());
                     }
                 } else {
-                    self.cx.current_expansion.no_noninline_mod = false;
-                    module.directory =
+                    let mut path =
                         PathBuf::from(self.cx.parse_sess.codemap().span_to_filename(inner));
-                    module.directory.pop();
+                    let directory_ownership = match path.file_name().unwrap().to_str() {
+                        Some("mod.rs") => DirectoryOwnership::Owned,
+                        _ => DirectoryOwnership::UnownedViaMod(false),
+                    };
+                    path.pop();
+                    module.directory = path;
+                    self.cx.current_expansion.directory_ownership = directory_ownership;
                 }
 
                 let orig_module =
                     mem::replace(&mut self.cx.current_expansion.module, Rc::new(module));
                 let result = noop_fold_item(item, self);
                 self.cx.current_expansion.module = orig_module;
-                self.cx.current_expansion.no_noninline_mod = orig_no_noninline_mod;
+                self.cx.current_expansion.directory_ownership = orig_directory_ownership;
                 return result;
             }
             // Ensure that test functions are accessible from the test harness.
index 320d49b64634c9f5c840b7aa3901a38cc8f1e91d..39b92c7d007dec77b151fd23129b3b9b0e02fbfb 100644 (file)
@@ -13,7 +13,7 @@
 use ext::base::*;
 use ext::base;
 use ext::build::AstBuilder;
-use parse::token;
+use parse::{token, DirectoryOwnership};
 use parse;
 use print::pprust;
 use ptr::P;
@@ -90,7 +90,8 @@ pub fn expand_include<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[tokenstream::T
     };
     // The file will be added to the code map by the parser
     let path = res_rel_file(cx, sp, Path::new(&file));
-    let p = parse::new_sub_parser_from_file(cx.parse_sess(), &path, true, None, sp);
+    let directory_ownership = DirectoryOwnership::Owned;
+    let p = parse::new_sub_parser_from_file(cx.parse_sess(), &path, directory_ownership, None, sp);
 
     struct ExpandResult<'a> {
         p: parse::parser::Parser<'a>,
index 59b8b50e88cb61b6b139ff9632d24049b143772b..4164b4a93ec91d4c91d65bcc65950730eff905e5 100644 (file)
@@ -19,7 +19,7 @@
 use ext::tt::macro_parser::{parse, parse_failure_msg};
 use parse::ParseSess;
 use parse::lexer::new_tt_reader;
-use parse::parser::{Parser, Restrictions};
+use parse::parser::Parser;
 use parse::token::{self, NtTT, Token};
 use parse::token::Token::*;
 use print;
@@ -117,11 +117,12 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt,
                 let trncbr =
                     new_tt_reader(&cx.parse_sess.span_diagnostic, Some(named_matches), rhs);
                 let mut p = Parser::new(cx.parse_sess(), Box::new(trncbr));
-                p.directory = cx.current_expansion.module.directory.clone();
-                p.restrictions = match cx.current_expansion.no_noninline_mod {
-                    true => Restrictions::NO_NONINLINE_MOD,
-                    false => Restrictions::empty(),
-                };
+                let module = &cx.current_expansion.module;
+                p.directory.path = module.directory.clone();
+                p.directory.ownership = cx.current_expansion.directory_ownership;
+                p.root_module_name =
+                    module.mod_path.last().map(|id| (*id.name.as_str()).to_owned());
+
                 p.check_unknown_macro_variable();
                 // Let the context choose how to interpret the result.
                 // Weird, but useful for X-macros.
index 16d4adf170589921512f31da58604a3bb8e364dd..aa6a29b78b075d2263a5eb2ed194161f371db08e 100644 (file)
@@ -313,6 +313,9 @@ pub fn new() -> Features {
     (active, link_cfg, "1.14.0", Some(37406)),
 
     (active, use_extern_macros, "1.15.0", Some(35896)),
+
+    // Allows `break {expr}` with a value inside `loop`s.
+    (active, loop_break_value, "1.14.0", Some(37339)),
 );
 
 declare_features! (
@@ -1189,6 +1192,10 @@ fn visit_expr(&mut self, e: &ast::Expr) {
                     }
                 }
             }
+            ast::ExprKind::Break(_, Some(_)) => {
+                gate_feature_post!(&self, loop_break_value, e.span,
+                                   "`break` with a value is experimental");
+            }
             _ => {}
         }
         visit::walk_expr(self, e);
index ff0255a2f21f23f2d255949c53f8f842030c0334..6af8efb2a195c6c3408a568b2fa0b8a8f7c04568 100644 (file)
@@ -1238,10 +1238,11 @@ pub fn noop_fold_expr<T: Folder>(Expr {id, node, span, attrs}: Expr, folder: &mu
                 });
                 ExprKind::Path(qself, folder.fold_path(path))
             }
-            ExprKind::Break(opt_ident) => ExprKind::Break(opt_ident.map(|label|
-                respan(folder.new_span(label.span),
-                       folder.fold_ident(label.node)))
-            ),
+            ExprKind::Break(opt_ident, opt_expr) => {
+                ExprKind::Break(opt_ident.map(|label| respan(folder.new_span(label.span),
+                                                             folder.fold_ident(label.node))),
+                                opt_expr.map(|e| folder.fold_expr(e)))
+            }
             ExprKind::Continue(opt_ident) => ExprKind::Continue(opt_ident.map(|label|
                 respan(folder.new_span(label.span),
                        folder.fold_ident(label.node)))
index be340a5b5aa93e0a9fca53629de5bfe931f30aa3..bfaf00a3d3f0814ee319772f306d564a2fea5c73 100644 (file)
@@ -76,6 +76,19 @@ pub fn codemap(&self) -> &CodeMap {
     }
 }
 
+#[derive(Clone)]
+pub struct Directory {
+    pub path: PathBuf,
+    pub ownership: DirectoryOwnership,
+}
+
+#[derive(Copy, Clone)]
+pub enum DirectoryOwnership {
+    Owned,
+    UnownedViaBlock,
+    UnownedViaMod(bool /* legacy warnings? */),
+}
+
 // a bunch of utility functions of the form parse_<thing>_from_<source>
 // where <thing> includes crate, expr, item, stmt, tts, and one that
 // uses a HOF to parse anything, and <source> includes file and
@@ -152,11 +165,11 @@ pub fn new_parser_from_file<'a>(sess: &'a ParseSess, path: &Path) -> Parser<'a>
 /// On an error, use the given span as the source of the problem.
 pub fn new_sub_parser_from_file<'a>(sess: &'a ParseSess,
                                     path: &Path,
-                                    owns_directory: bool,
+                                    directory_ownership: DirectoryOwnership,
                                     module_name: Option<String>,
                                     sp: Span) -> Parser<'a> {
     let mut p = filemap_to_parser(sess, file_to_filemap(sess, path, Some(sp)));
-    p.owns_directory = owns_directory;
+    p.directory.ownership = directory_ownership;
     p.root_module_name = module_name;
     p
 }
index 4997e464c2bf533987d9c6ca86cb81431835279a..49226be4147d7c4b9b01a062f4b44c4997fcc45f 100644 (file)
@@ -38,7 +38,7 @@
 use ast::{ViewPath, ViewPathGlob, ViewPathList, ViewPathSimple};
 use ast::{Visibility, WhereClause};
 use ast::{BinOpKind, UnOp};
-use ast;
+use {ast, attr};
 use codemap::{self, CodeMap, Spanned, spanned, respan};
 use syntax_pos::{self, Span, BytePos, mk_sp};
 use errors::{self, DiagnosticBuilder};
@@ -49,7 +49,7 @@
 use parse::lexer::{Reader, TokenAndSpan};
 use parse::obsolete::ObsoleteSyntax;
 use parse::token::{self, MatchNt, SubstNt};
-use parse::{new_sub_parser_from_file, ParseSess};
+use parse::{new_sub_parser_from_file, ParseSess, Directory, DirectoryOwnership};
 use util::parser::{AssocOp, Fixity};
 use print::pprust;
 use ptr::P;
@@ -68,7 +68,6 @@
     flags Restrictions: u8 {
         const RESTRICTION_STMT_EXPR         = 1 << 0,
         const RESTRICTION_NO_STRUCT_LITERAL = 1 << 1,
-        const NO_NONINLINE_MOD  = 1 << 2,
     }
 }
 
@@ -200,12 +199,9 @@ pub struct Parser<'a> {
     /// extra detail when the same error is seen twice
     pub obsolete_set: HashSet<ObsoleteSyntax>,
     /// Used to determine the path to externally loaded source files
-    pub directory: PathBuf,
+    pub directory: Directory,
     /// 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
-    /// in. This will affect how nested files are looked up.
-    pub owns_directory: bool,
     /// Name of the root module this parser originated from. If `None`, then the
     /// name is not known. This does not change while the parser is descending
     /// into modules, and sub-parsers have new values for this name.
@@ -245,8 +241,9 @@ pub struct ModulePath {
 }
 
 pub struct ModulePathSuccess {
-    pub path: ::std::path::PathBuf,
-    pub owns_directory: bool,
+    pub path: PathBuf,
+    pub directory_ownership: DirectoryOwnership,
+    warn: bool,
 }
 
 pub struct ModulePathError {
@@ -296,9 +293,8 @@ pub fn new_with_doc_flag(sess: &'a ParseSess, rdr: Box<Reader+'a>, desugar_doc_c
             quote_depth: 0,
             parsing_token_tree: false,
             obsolete_set: HashSet::new(),
-            directory: PathBuf::new(),
+            directory: Directory { path: PathBuf::new(), ownership: DirectoryOwnership::Owned },
             open_braces: Vec::new(),
-            owns_directory: true,
             root_module_name: None,
             expected_tokens: Vec::new(),
             tts: Vec::new(),
@@ -310,8 +306,8 @@ pub fn new_with_doc_flag(sess: &'a ParseSess, rdr: Box<Reader+'a>, desugar_doc_c
         parser.token = tok.tok;
         parser.span = tok.sp;
         if parser.span != syntax_pos::DUMMY_SP {
-            parser.directory = PathBuf::from(sess.codemap().span_to_filename(parser.span));
-            parser.directory.pop();
+            parser.directory.path = PathBuf::from(sess.codemap().span_to_filename(parser.span));
+            parser.directory.path.pop();
         }
         parser
     }
@@ -2260,15 +2256,25 @@ fn parse_bottom_expr(&mut self) -> PResult<'a, P<Expr>> {
                         ex = ExprKind::Ret(None);
                     }
                 } else if self.eat_keyword(keywords::Break) {
-                    if self.token.is_lifetime() {
-                        ex = ExprKind::Break(Some(Spanned {
+                    let lt = if self.token.is_lifetime() {
+                        let spanned_lt = Spanned {
                             node: self.get_lifetime(),
                             span: self.span
-                        }));
+                        };
                         self.bump();
+                        Some(spanned_lt)
                     } else {
-                        ex = ExprKind::Break(None);
-                    }
+                        None
+                    };
+                    let e = if self.token.can_begin_expr()
+                               && !(self.token == token::OpenDelim(token::Brace)
+                                    && self.restrictions.contains(
+                                           Restrictions::RESTRICTION_NO_STRUCT_LITERAL)) {
+                        Some(self.parse_expr()?)
+                    } else {
+                        None
+                    };
+                    ex = ExprKind::Break(lt, e);
                     hi = self.prev_span.hi;
                 } else if self.token.is_keyword(keywords::Let) {
                     // Catch this syntax error here, instead of in `check_strict_keywords`, so
@@ -3966,9 +3972,11 @@ fn parse_stmt_without_recovery(&mut self,
             }
         } else {
             // FIXME: Bad copy of attrs
-            let restrictions = self.restrictions | Restrictions::NO_NONINLINE_MOD;
-            match self.with_res(restrictions,
-                                |this| this.parse_item_(attrs.clone(), false, true))? {
+            let old_directory_ownership =
+                mem::replace(&mut self.directory.ownership, DirectoryOwnership::UnownedViaBlock);
+            let item = self.parse_item_(attrs.clone(), false, true)?;
+            self.directory.ownership = old_directory_ownership;
+            match item {
                 Some(i) => Stmt {
                     id: ast::DUMMY_NODE_ID,
                     span: mk_sp(lo, i.span.hi),
@@ -5271,38 +5279,53 @@ fn parse_item_mod(&mut self, outer_attrs: &[Attribute]) -> PResult<'a, ItemInfo>
             self.bump();
             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)))
+                let ModulePathSuccess { path, directory_ownership, warn } =
+                    self.submod_path(id, &outer_attrs, id_span)?;
+                let (module, mut attrs) =
+                    self.eval_src_mod(path, directory_ownership, id.to_string(), id_span)?;
+                if warn {
+                    let attr = ast::Attribute {
+                        id: attr::mk_attr_id(),
+                        style: ast::AttrStyle::Outer,
+                        value: ast::MetaItem {
+                            name: Symbol::intern("warn_directory_ownership"),
+                            node: ast::MetaItemKind::Word,
+                            span: syntax_pos::DUMMY_SP,
+                        },
+                        is_sugared_doc: false,
+                        span: syntax_pos::DUMMY_SP,
+                    };
+                    attr::mark_known(&attr);
+                    attrs.push(attr);
+                }
+                Ok((id, module, 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();
-            let restrictions = self.push_directory(id, &outer_attrs);
+            let old_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.with_res(restrictions, |this| {
-                this.parse_mod_items(&token::CloseDelim(token::Brace), mod_inner_lo)
-            })?;
-            self.directory = directory;
-            Ok((id, ItemKind::Mod(m), Some(attrs)))
+            let module = self.parse_mod_items(&token::CloseDelim(token::Brace), mod_inner_lo)?;
+            self.directory = old_directory;
+            Ok((id, ItemKind::Mod(module), Some(attrs)))
         }
     }
 
-    fn push_directory(&mut self, id: Ident, attrs: &[Attribute]) -> Restrictions {
-        if let Some(path) = ::attr::first_attr_value_str_by_name(attrs, "path") {
-            self.directory.push(&*path.as_str());
-            self.restrictions - Restrictions::NO_NONINLINE_MOD
+    fn push_directory(&mut self, id: Ident, attrs: &[Attribute]) {
+        if let Some(path) = attr::first_attr_value_str_by_name(attrs, "path") {
+            self.directory.path.push(&*path.as_str());
+            self.directory.ownership = DirectoryOwnership::Owned;
         } else {
-            self.directory.push(&*id.name.as_str());
-            self.restrictions
+            self.directory.path.push(&*id.name.as_str());
         }
     }
 
     pub fn submod_path_from_attr(attrs: &[ast::Attribute], dir_path: &Path) -> Option<PathBuf> {
-        ::attr::first_attr_value_str_by_name(attrs, "path").map(|d| dir_path.join(&*d.as_str()))
+        attr::first_attr_value_str_by_name(attrs, "path").map(|d| dir_path.join(&*d.as_str()))
     }
 
     /// Returns either a path to a module, or .
@@ -5317,8 +5340,16 @@ pub fn default_submod_path(id: ast::Ident, dir_path: &Path, codemap: &CodeMap) -
         let secondary_exists = codemap.file_exists(&secondary_path);
 
         let result = match (default_exists, secondary_exists) {
-            (true, false) => Ok(ModulePathSuccess { path: default_path, owns_directory: false }),
-            (false, true) => Ok(ModulePathSuccess { path: secondary_path, owns_directory: true }),
+            (true, false) => Ok(ModulePathSuccess {
+                path: default_path,
+                directory_ownership: DirectoryOwnership::UnownedViaMod(false),
+                warn: false,
+            }),
+            (false, true) => Ok(ModulePathSuccess {
+                path: secondary_path,
+                directory_ownership: DirectoryOwnership::Owned,
+                warn: false,
+            }),
             (false, false) => Err(ModulePathError {
                 err_msg: format!("file not found for module `{}`", mod_name),
                 help_msg: format!("name the file either {} or {} inside the directory {:?}",
@@ -5346,13 +5377,20 @@ fn submod_path(&mut self,
                    id: ast::Ident,
                    outer_attrs: &[ast::Attribute],
                    id_sp: Span) -> PResult<'a, ModulePathSuccess> {
-        if let Some(p) = Parser::submod_path_from_attr(outer_attrs, &self.directory) {
-            return Ok(ModulePathSuccess { path: p, owns_directory: true });
+        if let Some(path) = Parser::submod_path_from_attr(outer_attrs, &self.directory.path) {
+            return Ok(ModulePathSuccess {
+                directory_ownership: match path.file_name().and_then(|s| s.to_str()) {
+                    Some("mod.rs") => DirectoryOwnership::Owned,
+                    _ => DirectoryOwnership::UnownedViaMod(true),
+                },
+                path: path,
+                warn: false,
+            });
         }
 
-        let paths = Parser::default_submod_path(id, &self.directory, self.sess.codemap());
+        let paths = Parser::default_submod_path(id, &self.directory.path, self.sess.codemap());
 
-        if self.restrictions.contains(Restrictions::NO_NONINLINE_MOD) {
+        if let DirectoryOwnership::UnownedViaBlock = self.directory.ownership {
             let msg =
                 "Cannot declare a non-inline module inside a block unless it has a path attribute";
             let mut err = self.diagnostic().struct_span_err(id_sp, msg);
@@ -5362,10 +5400,15 @@ fn submod_path(&mut self,
                 err.span_note(id_sp, &msg);
             }
             return Err(err);
-        } else if !self.owns_directory {
+        } else if let DirectoryOwnership::UnownedViaMod(warn) = self.directory.ownership {
+            if warn {
+                if let Ok(result) = paths.result {
+                    return Ok(ModulePathSuccess { warn: true, ..result });
+                }
+            }
             let mut err = self.diagnostic().struct_span_err(id_sp,
                 "cannot declare a new module at this location");
-            let this_module = match self.directory.file_name() {
+            let this_module = match self.directory.path.file_name() {
                 Some(file_name) => file_name.to_str().unwrap().to_owned(),
                 None => self.root_module_name.as_ref().unwrap().clone(),
             };
@@ -5378,8 +5421,10 @@ fn submod_path(&mut self,
                               &format!("... or maybe `use` the module `{}` instead \
                                         of possibly redeclaring it",
                                        paths.name));
-            }
-            return Err(err);
+                return Err(err);
+            } else {
+                return Err(err);
+            };
         }
 
         match paths.result {
@@ -5390,25 +5435,11 @@ fn submod_path(&mut self,
 
     /// Read a module from a source file.
     fn eval_src_mod(&mut self,
-                    id: ast::Ident,
-                    outer_attrs: &[ast::Attribute],
+                    path: PathBuf,
+                    directory_ownership: DirectoryOwnership,
+                    name: String,
                     id_sp: Span)
                     -> PResult<'a, (ast::ItemKind, Vec<ast::Attribute> )> {
-        let ModulePathSuccess { path, owns_directory } = self.submod_path(id,
-                                                                          outer_attrs,
-                                                                          id_sp)?;
-
-        self.eval_src_mod_from_path(path,
-                                    owns_directory,
-                                    id.to_string(),
-                                    id_sp)
-    }
-
-    fn eval_src_mod_from_path(&mut self,
-                              path: PathBuf,
-                              owns_directory: bool,
-                              name: String,
-                              id_sp: Span) -> PResult<'a, (ast::ItemKind, Vec<ast::Attribute> )> {
         let mut included_mod_stack = self.sess.included_mod_stack.borrow_mut();
         if let Some(i) = included_mod_stack.iter().position(|p| *p == path) {
             let mut err = String::from("circular modules: ");
@@ -5423,7 +5454,8 @@ fn eval_src_mod_from_path(&mut self,
         included_mod_stack.push(path.clone());
         drop(included_mod_stack);
 
-        let mut p0 = new_sub_parser_from_file(self.sess, &path, owns_directory, Some(name), id_sp);
+        let mut p0 =
+            new_sub_parser_from_file(self.sess, &path, directory_ownership, Some(name), id_sp);
         let mod_inner_lo = p0.span.lo;
         let mod_attrs = p0.parse_inner_attributes()?;
         let m0 = p0.parse_mod_items(&token::Eof, mod_inner_lo)?;
index 3820f5ea90ccc6e147e835b9515f63a12f8164dc..c28b9d00501b70fd6a989f27af86ad170873d3df 100644 (file)
@@ -2191,13 +2191,17 @@ fn print_expr_outer_attr_style(&mut self,
             ast::ExprKind::Path(Some(ref qself), ref path) => {
                 try!(self.print_qpath(path, qself, true))
             }
-            ast::ExprKind::Break(opt_ident) => {
+            ast::ExprKind::Break(opt_ident, ref opt_expr) => {
                 try!(word(&mut self.s, "break"));
                 try!(space(&mut self.s));
                 if let Some(ident) = opt_ident {
                     try!(self.print_ident(ident.node));
                     try!(space(&mut self.s));
                 }
+                if let Some(ref expr) = *opt_expr {
+                    try!(self.print_expr(expr));
+                    try!(space(&mut self.s));
+                }
             }
             ast::ExprKind::Continue(opt_ident) => {
                 try!(word(&mut self.s, "continue"));
index 7c1ff617ab64d00b46d07021b15c5f83ab79abb7..da36225fb329cdd17d51846e2b953a07abb82f6a 100644 (file)
@@ -746,7 +746,11 @@ pub fn walk_expr<V: Visitor>(visitor: &mut V, expression: &Expr) {
             }
             visitor.visit_path(path, expression.id)
         }
-        ExprKind::Break(ref opt_sp_ident) | ExprKind::Continue(ref opt_sp_ident) => {
+        ExprKind::Break(ref opt_sp_ident, ref opt_expr) => {
+            walk_opt_sp_ident(visitor, opt_sp_ident);
+            walk_list!(visitor, visit_expr, opt_expr);
+        }
+        ExprKind::Continue(ref opt_sp_ident) => {
             walk_opt_sp_ident(visitor, opt_sp_ident);
         }
         ExprKind::Ret(ref optional_expression) => {
diff --git a/src/test/compile-fail/auxiliary/rmeta_meta.rs b/src/test/compile-fail/auxiliary/rmeta_meta.rs
new file mode 100644 (file)
index 0000000..7bd1a96
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// no-prefer-dynamic
+
+#![crate_type="metadata"]
+
+pub struct Foo {
+    pub field: i32,
+}
diff --git a/src/test/compile-fail/auxiliary/rmeta_rlib.rs b/src/test/compile-fail/auxiliary/rmeta_rlib.rs
new file mode 100644 (file)
index 0000000..6096c4d
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![crate_type="rlib"]
+
+pub struct Foo {
+    pub field: i32,
+}
index 1dbad9e30e3addd8c4f7293a9d585437db6efe94..b98f464c902278443f7ecec8231ea4efc6c6508b 100644 (file)
@@ -115,4 +115,9 @@ fn main()
     let _ = cf as *const Bar;
     //~^ ERROR casting
     //~^^ NOTE vtable kinds
+
+    vec![0.0].iter().map(|s| s as f32).collect::<Vec<f32>>();
+    //~^ ERROR casting `&{float}` as `f32` is invalid
+    //~| NOTE cannot cast `&{float}` as `f32`
+    //~| NOTE did you mean `*s`?
 }
diff --git a/src/test/compile-fail/directory_ownership/backcompat-warnings.rs b/src/test/compile-fail/directory_ownership/backcompat-warnings.rs
new file mode 100644 (file)
index 0000000..75e3426
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// error-pattern: cannot declare a new module at this location
+// error-pattern: will become a hard error
+// error-pattern: compilation successful
+
+#![feature(rustc_attrs)]
+
+#[path="mod_file_not_owning_aux3.rs"]
+mod foo;
+
+#[rustc_error]
+fn main() {}
diff --git a/src/test/compile-fail/directory_ownership/macro-expanded-mod.rs b/src/test/compile-fail/directory_ownership/macro-expanded-mod.rs
new file mode 100644 (file)
index 0000000..8e631a6
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that macro-expanded non-inline modules behave correctly
+
+macro_rules! mod_decl {
+    ($i:ident) => { mod $i; }
+}
+
+mod macro_expanded_mod_helper {
+    mod_decl!(foo); // This should search in the folder `macro_expanded_mod_helper`
+}
+
+fn main() {
+    mod_decl!(foo); //~ ERROR Cannot declare a non-inline module inside a block
+}
diff --git a/src/test/compile-fail/directory_ownership/macro_expanded_mod_helper/foo/bar.rs b/src/test/compile-fail/directory_ownership/macro_expanded_mod_helper/foo/bar.rs
new file mode 100644 (file)
index 0000000..3ec3436
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// ignore-test
diff --git a/src/test/compile-fail/directory_ownership/macro_expanded_mod_helper/foo/mod.rs b/src/test/compile-fail/directory_ownership/macro_expanded_mod_helper/foo/mod.rs
new file mode 100644 (file)
index 0000000..25fcf11
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// ignore-test
+
+mod_decl!(bar);
diff --git a/src/test/compile-fail/directory_ownership/mod_file_not_owning.rs b/src/test/compile-fail/directory_ownership/mod_file_not_owning.rs
new file mode 100644 (file)
index 0000000..adbcedd
--- /dev/null
@@ -0,0 +1,15 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// error-pattern: cannot declare a new module at this location
+
+mod mod_file_not_owning_aux1;
+
+fn main() {}
diff --git a/src/test/compile-fail/directory_ownership/mod_file_not_owning_aux1.rs b/src/test/compile-fail/directory_ownership/mod_file_not_owning_aux1.rs
new file mode 100644 (file)
index 0000000..4ac94a9
--- /dev/null
@@ -0,0 +1,16 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// ignore-test this is not a test
+
+macro_rules! m {
+    () => { mod mod_file_not_owning_aux2; }
+}
+m!();
diff --git a/src/test/compile-fail/directory_ownership/mod_file_not_owning_aux2.rs b/src/test/compile-fail/directory_ownership/mod_file_not_owning_aux2.rs
new file mode 100644 (file)
index 0000000..41401d6
--- /dev/null
@@ -0,0 +1,11 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// ignore-test this is not a test
diff --git a/src/test/compile-fail/directory_ownership/mod_file_not_owning_aux3.rs b/src/test/compile-fail/directory_ownership/mod_file_not_owning_aux3.rs
new file mode 100644 (file)
index 0000000..3a164fd
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// ignore-test this is not a test
+
+mod mod_file_not_owning_aux2;
diff --git a/src/test/compile-fail/directory_ownership/non-inline-mod-restriction.rs b/src/test/compile-fail/directory_ownership/non-inline-mod-restriction.rs
new file mode 100644 (file)
index 0000000..c4ede12
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that non-inline modules are not allowed inside blocks.
+
+fn main() {
+    mod foo; //~ ERROR Cannot declare a non-inline module inside a block
+}
diff --git a/src/test/compile-fail/directory_ownership/unowned_mod_with_path.rs b/src/test/compile-fail/directory_ownership/unowned_mod_with_path.rs
new file mode 100644 (file)
index 0000000..854f790
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// error-pattern: cannot declare a new module at this location
+
+// This is not a directory owner since the file name is not "mod.rs".
+#[path = "mod_file_not_owning_aux1.rs"]
+mod foo;
diff --git a/src/test/compile-fail/feature-gate-loop-break-value.rs b/src/test/compile-fail/feature-gate-loop-break-value.rs
new file mode 100644 (file)
index 0000000..1632c40
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+    loop {
+        break 123; //~ ERROR `break` with a value is experimental
+    }
+}
diff --git a/src/test/compile-fail/loop-break-value.rs b/src/test/compile-fail/loop-break-value.rs
new file mode 100644 (file)
index 0000000..d4f2959
--- /dev/null
@@ -0,0 +1,101 @@
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(loop_break_value)]
+#![feature(never_type)]
+
+fn main() {
+    let val: ! = loop { break break; };
+    //~^ ERROR mismatched types
+
+    loop {
+        if true {
+            break "asdf";
+        } else {
+            break 123; //~ ERROR mismatched types
+        }
+    };
+
+    let _: i32 = loop {
+        break "asdf"; //~ ERROR mismatched types
+    };
+
+    let _: i32 = 'outer_loop: loop {
+        loop {
+            break 'outer_loop "nope"; //~ ERROR mismatched types
+            break "ok";
+        };
+    };
+
+    'while_loop: while true {
+        break;
+        break (); //~ ERROR `break` with value from a `while` loop
+        loop {
+            break 'while_loop 123;
+            //~^ ERROR `break` with value from a `while` loop
+            //~| ERROR mismatched types
+            break 456;
+            break 789;
+        };
+    }
+
+    'while_let_loop: while let Some(_) = Some(()) {
+        if break () { //~ ERROR `break` with value from a `while let` loop
+            break;
+            break None;
+            //~^ ERROR `break` with value from a `while let` loop
+            //~| ERROR mismatched types
+        }
+        loop {
+            break 'while_let_loop "nope";
+            //~^ ERROR `break` with value from a `while let` loop
+            //~| ERROR mismatched types
+            break 33;
+        };
+    }
+
+    'for_loop: for _ in &[1,2,3] {
+        break (); //~ ERROR `break` with value from a `for` loop
+        break [()];
+        //~^ ERROR `break` with value from a `for` loop
+        //~| ERROR mismatched types
+        loop {
+            break Some(3);
+            break 'for_loop Some(17);
+            //~^ ERROR `break` with value from a `for` loop
+            //~| ERROR mismatched types
+        };
+    }
+
+    let _: i32 = 'a: loop {
+        let _: () = 'b: loop {
+            break ('c: loop {
+                break;
+                break 'c 123; //~ ERROR mismatched types
+            });
+            break 'a 123;
+        };
+    };
+
+    loop {
+        break (break, break); //~ ERROR mismatched types
+    };
+
+    loop {
+        break;
+        break 2; //~ ERROR mismatched types
+    };
+
+    loop {
+        break 2;
+        break; //~ ERROR mismatched types
+        break 4;
+    };
+}
diff --git a/src/test/compile-fail/macro-expanded-mod.rs b/src/test/compile-fail/macro-expanded-mod.rs
deleted file mode 100644 (file)
index 8e631a6..0000000
+++ /dev/null
@@ -1,23 +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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// Test that macro-expanded non-inline modules behave correctly
-
-macro_rules! mod_decl {
-    ($i:ident) => { mod $i; }
-}
-
-mod macro_expanded_mod_helper {
-    mod_decl!(foo); // This should search in the folder `macro_expanded_mod_helper`
-}
-
-fn main() {
-    mod_decl!(foo); //~ ERROR Cannot declare a non-inline module inside a block
-}
diff --git a/src/test/compile-fail/macro_expanded_mod_helper/foo/bar.rs b/src/test/compile-fail/macro_expanded_mod_helper/foo/bar.rs
deleted file mode 100644 (file)
index 3ec3436..0000000
+++ /dev/null
@@ -1,11 +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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// ignore-test
diff --git a/src/test/compile-fail/macro_expanded_mod_helper/foo/mod.rs b/src/test/compile-fail/macro_expanded_mod_helper/foo/mod.rs
deleted file mode 100644 (file)
index 25fcf11..0000000
+++ /dev/null
@@ -1,13 +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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// ignore-test
-
-mod_decl!(bar);
diff --git a/src/test/compile-fail/mod_file_not_owning.rs b/src/test/compile-fail/mod_file_not_owning.rs
deleted file mode 100644 (file)
index 7dcff6e..0000000
+++ /dev/null
@@ -1,17 +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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// compile-flags: -Z parse-only
-
-// error-pattern: cannot declare a new module at this location
-
-mod mod_file_not_owning_aux1;
-
-fn main() {}
diff --git a/src/test/compile-fail/mod_file_not_owning_aux1.rs b/src/test/compile-fail/mod_file_not_owning_aux1.rs
deleted file mode 100644 (file)
index 2d522be..0000000
+++ /dev/null
@@ -1,13 +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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// ignore-test this is not a test
-
-mod mod_file_not_owning_aux2;
diff --git a/src/test/compile-fail/mod_file_not_owning_aux2.rs b/src/test/compile-fail/mod_file_not_owning_aux2.rs
deleted file mode 100644 (file)
index 41401d6..0000000
+++ /dev/null
@@ -1,11 +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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// ignore-test this is not a test
diff --git a/src/test/compile-fail/non-inline-mod-restriction.rs b/src/test/compile-fail/non-inline-mod-restriction.rs
deleted file mode 100644 (file)
index c4ede12..0000000
+++ /dev/null
@@ -1,15 +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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// Test that non-inline modules are not allowed inside blocks.
-
-fn main() {
-    mod foo; //~ ERROR Cannot declare a non-inline module inside a block
-}
diff --git a/src/test/compile-fail/rmeta-lib-pass.rs b/src/test/compile-fail/rmeta-lib-pass.rs
new file mode 100644 (file)
index 0000000..f2ac37a
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:rmeta_rlib.rs
+// no-prefer-dynamic
+// must-compile-successfully
+
+// Check that building a metadata crate works with a dependent, rlib crate.
+// This is a cfail test since there is no executable to run.
+
+#![crate_type="metadata"]
+
+extern crate rmeta_rlib;
+use rmeta_rlib::Foo;
+
+pub fn main() {
+    let _ = Foo { field: 42 };
+}
diff --git a/src/test/compile-fail/rmeta-pass.rs b/src/test/compile-fail/rmeta-pass.rs
new file mode 100644 (file)
index 0000000..2c0b6f7
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:rmeta_meta.rs
+// no-prefer-dynamic
+// must-compile-successfully
+
+// Check that building a metadata crate works with a dependent, metadata-only
+// crate.
+// This is a cfail test since there is no executable to run.
+
+#![crate_type="metadata"]
+
+extern crate rmeta_meta;
+use rmeta_meta::Foo;
+
+pub fn main() {
+    let _ = Foo { field: 42 };
+}
diff --git a/src/test/compile-fail/rmeta.rs b/src/test/compile-fail/rmeta.rs
new file mode 100644 (file)
index 0000000..e81e054
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// no-prefer-dynamic
+
+// Check that building a metadata crate finds an error.
+
+#![crate_type="metadata"]
+
+fn main() {
+    let _ = Foo; //~ ERROR unresolved name `Foo`
+}
diff --git a/src/test/compile-fail/rmeta_lib.rs b/src/test/compile-fail/rmeta_lib.rs
new file mode 100644 (file)
index 0000000..3b7d1f3
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:rmeta_meta.rs
+// no-prefer-dynamic
+// error-pattern: crate `rmeta_meta` required to be available in rlib, but it was not available
+
+// Check that building a non-metadata crate fails if a dependent crate is
+// metadata-only.
+
+extern crate rmeta_meta;
+use rmeta_meta::Foo;
+
+fn main() {
+    let _ = Foo { field: 42 };
+}
diff --git a/src/test/compile-fail/rmeta_meta_main.rs b/src/test/compile-fail/rmeta_meta_main.rs
new file mode 100644 (file)
index 0000000..1c922c2
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:rmeta_meta.rs
+// no-prefer-dynamic
+
+// Check that building a metadata crate finds an error with a dependent,
+// metadata-only crate.
+
+#![crate_type="metadata"]
+
+extern crate rmeta_meta;
+use rmeta_meta::Foo;
+
+fn main() {
+    let _ = Foo { field2: 42 }; //~ ERROR struct `rmeta_meta::Foo` has no field named `field2`
+}
diff --git a/src/test/incremental/hashes/struct_constructors.rs b/src/test/incremental/hashes/struct_constructors.rs
new file mode 100644 (file)
index 0000000..c4366ea
--- /dev/null
@@ -0,0 +1,254 @@
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+
+// This test case tests the incremental compilation hash (ICH) implementation
+// for struct constructor expressions.
+
+// The general pattern followed here is: Change one thing between rev1 and rev2
+// and make sure that the hash has changed, then change nothing between rev2 and
+// rev3 and make sure that the hash has not changed.
+
+// must-compile-successfully
+// revisions: cfail1 cfail2 cfail3
+// compile-flags: -Z query-dep-graph
+
+#![allow(warnings)]
+#![feature(rustc_attrs)]
+#![crate_type="rlib"]
+
+
+struct RegularStruct {
+    x: i32,
+    y: i64,
+    z: i16,
+}
+
+// Change field value (regular struct) -----------------------------------------
+#[cfg(cfail1)]
+fn change_field_value_regular_struct() -> RegularStruct {
+    RegularStruct {
+        x: 0,
+        y: 1,
+        z: 2,
+    }
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+fn change_field_value_regular_struct() -> RegularStruct {
+    RegularStruct {
+        x: 0,
+        y: 2,
+        z: 2,
+    }
+}
+
+
+
+// Change field order (regular struct) -----------------------------------------
+#[cfg(cfail1)]
+fn change_field_order_regular_struct() -> RegularStruct {
+    RegularStruct {
+        x: 3,
+        y: 4,
+        z: 5,
+    }
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+fn change_field_order_regular_struct() -> RegularStruct {
+    RegularStruct {
+        y: 4,
+        x: 3,
+        z: 5,
+    }
+}
+
+
+
+// Add field (regular struct) --------------------------------------------------
+#[cfg(cfail1)]
+fn add_field_regular_struct() -> RegularStruct {
+    let struct1 = RegularStruct {
+        x: 3,
+        y: 4,
+        z: 5,
+    };
+
+    RegularStruct {
+        x: 7,
+        .. struct1
+    }
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+fn add_field_regular_struct() -> RegularStruct {
+    let struct1 = RegularStruct {
+        x: 3,
+        y: 4,
+        z: 5,
+    };
+
+    RegularStruct {
+        x: 7,
+        y: 8,
+        .. struct1
+    }
+}
+
+
+
+// Change field label (regular struct) -----------------------------------------
+#[cfg(cfail1)]
+fn change_field_label_regular_struct() -> RegularStruct {
+    let struct1 = RegularStruct {
+        x: 3,
+        y: 4,
+        z: 5,
+    };
+
+    RegularStruct {
+        x: 7,
+        y: 9,
+        .. struct1
+    }
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+fn change_field_label_regular_struct() -> RegularStruct {
+    let struct1 = RegularStruct {
+        x: 3,
+        y: 4,
+        z: 5,
+    };
+
+    RegularStruct {
+        x: 7,
+        z: 9,
+        .. struct1
+    }
+}
+
+
+
+struct RegularStruct2 {
+    x: i8,
+    y: i8,
+    z: i8,
+}
+
+// Change constructor path (regular struct) ------------------------------------
+#[cfg(cfail1)]
+fn change_constructor_path_regular_struct() {
+    let _ = RegularStruct {
+        x: 0,
+        y: 1,
+        z: 2,
+    };
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+fn change_constructor_path_regular_struct() {
+    let _ = RegularStruct2 {
+        x: 0,
+        y: 1,
+        z: 2,
+    };
+}
+
+
+
+// Change constructor path indirectly (regular struct) -------------------------
+mod change_constructor_path_indirectly_regular_struct {
+    #[cfg(cfail1)]
+    use super::RegularStruct as Struct;
+    #[cfg(not(cfail1))]
+    use super::RegularStruct2 as Struct;
+
+    fn function() -> Struct {
+        Struct {
+            x: 0,
+            y: 1,
+            z: 2,
+        }
+    }
+}
+
+
+
+struct TupleStruct(i32, i64, i16);
+
+// Change field value (tuple struct) -------------------------------------------
+#[cfg(cfail1)]
+fn change_field_value_tuple_struct() -> TupleStruct {
+    TupleStruct(0, 1, 2)
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+fn change_field_value_tuple_struct() -> TupleStruct {
+    TupleStruct(0, 1, 3)
+}
+
+
+
+struct TupleStruct2(u16, u16, u16);
+
+// Change constructor path (tuple struct) --------------------------------------
+#[cfg(cfail1)]
+fn change_constructor_path_tuple_struct() {
+    let _ = TupleStruct(0, 1, 2);
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+fn change_constructor_path_tuple_struct() {
+    let _ = TupleStruct2(0, 1, 2);
+}
+
+
+
+// Change constructor path indirectly (tuple struct) ---------------------------
+mod change_constructor_path_indirectly_tuple_struct {
+    #[cfg(cfail1)]
+    use super::TupleStruct as Struct;
+    #[cfg(not(cfail1))]
+    use super::TupleStruct2 as Struct;
+
+    fn function() -> Struct {
+        Struct(0, 1, 2)
+    }
+}
index 4de817dbd9ca7823ba14719bf2d25bb4af2c6a49..94770aa875b4258b04cc336e54fdcf11ad688d8e 100644 (file)
@@ -12,6 +12,7 @@
 
 // ignore-test: this is an auxiliary file for circular-modules-main.rs
 
+#[path = "circular_modules_main.rs"]
 mod circular_modules_main;
 
 pub fn say_hello() {
diff --git a/src/test/run-make/save-analysis-fail/Makefile b/src/test/run-make/save-analysis-fail/Makefile
new file mode 100644 (file)
index 0000000..f29f907
--- /dev/null
@@ -0,0 +1,6 @@
+-include ../tools.mk
+all: code
+krate2: krate2.rs
+       $(RUSTC) $<
+code: foo.rs krate2
+       $(RUSTC) foo.rs -Zsave-analysis || exit 0
diff --git a/src/test/run-make/save-analysis-fail/SameDir.rs b/src/test/run-make/save-analysis-fail/SameDir.rs
new file mode 100644 (file)
index 0000000..fe70ac1
--- /dev/null
@@ -0,0 +1,15 @@
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// sub-module in the same directory as the main crate file
+
+pub struct SameStruct {
+    pub name: String
+}
diff --git a/src/test/run-make/save-analysis-fail/SameDir3.rs b/src/test/run-make/save-analysis-fail/SameDir3.rs
new file mode 100644 (file)
index 0000000..315f900
--- /dev/null
@@ -0,0 +1,13 @@
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub fn hello(x: isize) {
+    println!("macro {} :-(", x);
+}
diff --git a/src/test/run-make/save-analysis-fail/SubDir/mod.rs b/src/test/run-make/save-analysis-fail/SubDir/mod.rs
new file mode 100644 (file)
index 0000000..fe84db0
--- /dev/null
@@ -0,0 +1,37 @@
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// sub-module in a sub-directory
+
+use sub::sub2 as msalias;
+use sub::sub2;
+
+static yy: usize = 25;
+
+mod sub {
+    pub mod sub2 {
+        pub mod sub3 {
+            pub fn hello() {
+                println!("hello from module 3");
+            }
+        }
+        pub fn hello() {
+            println!("hello from a module");
+        }
+
+        pub struct nested_struct {
+            pub field2: u32,
+        }
+    }
+}
+
+pub struct SubStruct {
+    pub name: String
+}
diff --git a/src/test/run-make/save-analysis-fail/foo.rs b/src/test/run-make/save-analysis-fail/foo.rs
new file mode 100644 (file)
index 0000000..e331f65
--- /dev/null
@@ -0,0 +1,450 @@
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![ crate_name = "test" ]
+#![feature(box_syntax)]
+#![feature(rustc_private)]
+
+extern crate graphviz;
+// A simple rust project
+
+extern crate krate2;
+extern crate krate2 as krate3;
+extern crate flate as myflate;
+
+use graphviz::RenderOption;
+use std::collections::{HashMap,HashSet};
+use std::cell::RefCell;
+use std::io::Write;
+
+
+use sub::sub2 as msalias;
+use sub::sub2;
+use sub::sub2::nested_struct as sub_struct;
+
+use std::mem::size_of;
+
+use std::char::from_u32;
+
+static uni: &'static str = "Les Miséééééééérables";
+static yy: usize = 25;
+
+static bob: Option<graphviz::RenderOption> = None;
+
+// buglink test - see issue #1337.
+
+fn test_alias<I: Iterator>(i: Option<<I as Iterator>::Item>) {
+    let s = sub_struct{ field2: 45u32, };
+
+    // import tests
+    fn foo(x: &Write) {}
+    let _: Option<_> = from_u32(45);
+
+    let x = 42usize;
+
+    krate2::hello();
+    krate3::hello();
+    myflate::deflate_bytes(&[]);
+
+    let x = (3isize, 4usize);
+    let y = x.1;
+}
+
+// Issue #37700
+const LUT_BITS: usize = 3;
+pub struct HuffmanTable {
+    ac_lut: Option<[(i16, u8); 1 << LUT_BITS]>,
+}
+
+struct TupStruct(isize, isize, Box<str>);
+
+fn test_tup_struct(x: TupStruct) -> isize {
+    x.1
+}
+
+fn println(s: &str) {
+    std::io::stdout().write_all(s.as_bytes());
+}
+
+mod sub {
+    pub mod sub2 {
+        use std::io::Write;
+        pub mod sub3 {
+            use std::io::Write;
+            pub fn hello() {
+                ::println("hello from module 3");
+            }
+        }
+        pub fn hello() {
+            ::println("hello from a module");
+        }
+
+        pub struct nested_struct {
+            pub field2: u32,
+        }
+
+        pub enum nested_enum {
+            Nest2 = 2,
+            Nest3 = 3
+        }
+    }
+}
+
+pub mod SameDir;
+pub mod SubDir;
+
+#[path = "SameDir3.rs"]
+pub mod SameDir2;
+
+struct nofields;
+
+#[derive(Clone)]
+struct some_fields {
+    field1: u32,
+}
+
+type SF = some_fields;
+
+trait SuperTrait {
+    fn qux(&self) { panic!(); }
+}
+
+trait SomeTrait: SuperTrait {
+    fn Method(&self, x: u32) -> u32;
+
+    fn prov(&self, x: u32) -> u32 {
+        println(&x.to_string());
+        42
+    }
+    fn provided_method(&self) -> u32 {
+        42
+    }
+}
+
+trait SubTrait: SomeTrait {
+    fn stat2(x: &Self) -> u32 {
+        32
+    }
+}
+
+trait SizedTrait: Sized {}
+
+fn error(s: &SizedTrait) {
+    let foo = 42;
+    println!("Hello world! {}", foo);
+}
+
+impl SomeTrait for some_fields {
+    fn Method(&self, x: u32) -> u32 {
+        println(&x.to_string());
+        self.field1
+    }
+}
+
+impl SuperTrait for some_fields {
+}
+
+impl SubTrait for some_fields {}
+
+impl some_fields {
+    fn stat(x: u32) -> u32 {
+        println(&x.to_string());
+        42
+    }
+    fn stat2(x: &some_fields) -> u32 {
+        42
+    }
+
+    fn align_to<T>(&mut self) {
+
+    }
+
+    fn test(&mut self) {
+        self.align_to::<bool>();
+    }
+}
+
+impl SuperTrait for nofields {
+}
+impl SomeTrait for nofields {
+    fn Method(&self, x: u32) -> u32 {
+        self.Method(x);
+        43
+    }
+
+    fn provided_method(&self) -> u32 {
+        21
+    }
+}
+
+impl SubTrait for nofields {}
+
+impl SuperTrait for (Box<nofields>, Box<some_fields>) {}
+
+fn f_with_params<T: SomeTrait>(x: &T) {
+    x.Method(41);
+}
+
+type MyType = Box<some_fields>;
+
+enum SomeEnum<'a> {
+    Ints(isize, isize),
+    Floats(f64, f64),
+    Strings(&'a str, &'a str, &'a str),
+    MyTypes(MyType, MyType)
+}
+
+#[derive(Copy, Clone)]
+enum SomeOtherEnum {
+    SomeConst1,
+    SomeConst2,
+    SomeConst3
+}
+
+enum SomeStructEnum {
+    EnumStruct{a:isize, b:isize},
+    EnumStruct2{f1:MyType, f2:MyType},
+    EnumStruct3{f1:MyType, f2:MyType, f3:SomeEnum<'static>}
+}
+
+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::MyTypes(mt1, mt2) => { println(&(mt1.field1 - mt2.field1).to_string()); }
+    }
+}
+
+fn matchSomeStructEnum(se: SomeStructEnum) {
+    match se {
+        SomeStructEnum::EnumStruct{a:a, ..} => println(&a.to_string()),
+        SomeStructEnum::EnumStruct2{f1:f1, f2:f_2} => println(&f_2.field1.to_string()),
+        SomeStructEnum::EnumStruct3{f1, ..} => println(&f1.field1.to_string()),
+    }
+}
+
+
+fn matchSomeStructEnum2(se: SomeStructEnum) {
+    use 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()),
+        _ => {},
+    }
+}
+
+fn matchSomeOtherEnum(val: SomeOtherEnum) {
+    use SomeOtherEnum::{SomeConst2, SomeConst3};
+    match val {
+        SomeOtherEnum::SomeConst1 => { println("I'm const1."); }
+        SomeConst2 | SomeConst3 => { println("I'm const2 or const3."); }
+    }
+}
+
+fn hello<X: SomeTrait>((z, a) : (u32, String), ex: X) {
+    SameDir2::hello(43);
+
+    println(&yy.to_string());
+    let (x, y): (u32, u32) = (5, 3);
+    println(&x.to_string());
+    println(&z.to_string());
+    let x: u32 = x;
+    println(&x.to_string());
+    let x = "hello";
+    println(x);
+
+    let x = 32.0f32;
+    let _ = (x + ((x * x) + 1.0).sqrt()).ln();
+
+    let s: Box<SomeTrait> = box some_fields {field1: 43};
+    let s2: Box<some_fields> =  box some_fields {field1: 43};
+    let s3 = box nofields;
+
+    s.Method(43);
+    s3.Method(43);
+    s2.Method(43);
+
+    ex.prov(43);
+
+    let y: u32 = 56;
+    // static method on struct
+    let r = some_fields::stat(y);
+    // trait static method, calls default
+    let r = SubTrait::stat2(&*s3);
+
+    let s4 = s3 as Box<SomeTrait>;
+    s4.Method(43);
+
+    s4.provided_method();
+    s2.prov(45);
+
+    let closure = |x: u32, s: &SomeTrait| {
+        s.Method(23);
+        return x + y;
+    };
+
+    let z = closure(10, &*s);
+}
+
+pub struct blah {
+    used_link_args: RefCell<[&'static str; 0]>,
+}
+
+#[macro_use]
+mod macro_use_test {
+    macro_rules! test_rec {
+        (q, $src: expr) => {{
+            print!("{}", $src);
+            test_rec!($src);
+        }};
+        ($src: expr) => {
+            print!("{}", $src);
+        };
+    }
+
+    macro_rules! internal_vars {
+        ($src: ident) => {{
+            let mut x = $src;
+            x += 100;
+        }};
+    }
+}
+
+fn main() { // foo
+    let s = box some_fields {field1: 43};
+    hello((43, "a".to_string()), *s);
+    sub::sub2::hello();
+    sub2::sub3::hello();
+
+    let h = sub2::sub3::hello;
+    h();
+
+    // utf8 chars
+    let ut = "Les Miséééééééérables";
+
+    // For some reason, this pattern of macro_rules foiled our generated code
+    // avoiding strategy.
+    macro_rules! variable_str(($name:expr) => (
+        some_fields {
+            field1: $name,
+        }
+    ));
+    let vs = variable_str!(32);
+
+    let mut candidates: RefCell<HashMap<&'static str, &'static str>> = RefCell::new(HashMap::new());
+    let _ = blah {
+        used_link_args: RefCell::new([]),
+    };
+    let s1 = nofields;
+    let s2 = SF { field1: 55};
+    let s3: some_fields = some_fields{ field1: 55};
+    let s4: msalias::nested_struct = sub::sub2::nested_struct{ field2: 55};
+    let s4: msalias::nested_struct = sub2::nested_struct{ field2: 55};
+    println(&s2.field1.to_string());
+    let s5: MyType = box some_fields{ field1: 55};
+    let s = SameDir::SameStruct{name: "Bob".to_string()};
+    let s = SubDir::SubStruct{name:"Bob".to_string()};
+    let s6: SomeEnum = SomeEnum::MyTypes(box s2.clone(), s5);
+    let s7: SomeEnum = SomeEnum::Strings("one", "two", "three");
+    matchSomeEnum(s6);
+    matchSomeEnum(s7);
+    let s8: SomeOtherEnum = SomeOtherEnum::SomeConst2;
+    matchSomeOtherEnum(s8);
+    let s9: SomeStructEnum = SomeStructEnum::EnumStruct2{ f1: box some_fields{ field1:10 },
+                                                          f2: box s2 };
+    matchSomeStructEnum(s9);
+
+    for x in &vec![1, 2, 3] {
+        let _y = x;
+    }
+
+    let s7: SomeEnum = SomeEnum::Strings("one", "two", "three");
+    if let SomeEnum::Strings(..) = s7 {
+        println!("hello!");
+    }
+
+    for i in 0..5 {
+        foo_foo(i);
+    }
+
+    if let Some(x) = None {
+        foo_foo(x);
+    }
+
+    if false {
+    } else if let Some(y) = None {
+        foo_foo(y);
+    }
+
+    while let Some(z) = None {
+        foo_foo(z);
+    }
+
+    let mut x = 4;
+    test_rec!(q, "Hello");
+    assert_eq!(x, 4);
+    internal_vars!(x);
+}
+
+fn foo_foo(_: i32) {}
+
+impl Iterator for nofields {
+    type Item = (usize, usize);
+
+    fn next(&mut self) -> Option<(usize, usize)> {
+        panic!()
+    }
+
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        panic!()
+    }
+}
+
+trait Pattern<'a> {
+    type Searcher;
+}
+
+struct CharEqPattern;
+
+impl<'a> Pattern<'a> for CharEqPattern {
+    type Searcher = CharEqPattern;
+}
+
+struct CharSearcher<'a>(<CharEqPattern as Pattern<'a>>::Searcher);
+
+pub trait Error {
+}
+
+impl Error + 'static {
+    pub fn is<T: Error + 'static>(&self) -> bool {
+        panic!()
+    }
+}
+
+impl Error + 'static + Send {
+    pub fn is<T: Error + 'static>(&self) -> bool {
+        <Error + 'static>::is::<T>(self)
+    }
+}
+extern crate serialize;
+#[derive(Clone, Copy, Hash, Encodable, Decodable, PartialEq, Eq, PartialOrd, Ord, Debug, Default)]
+struct AllDerives(i32);
+
+fn test_format_args() {
+    let x = 1;
+    let y = 2;
+    let name = "Joe Blogg";
+    println!("Hello {}", name);
+    print!("Hello {0}", name);
+    print!("{0} + {} = {}", x, y);
+    print!("x is {}, y is {1}, name is {n}", x, y, n = name);
+}
diff --git a/src/test/run-make/save-analysis-fail/krate2.rs b/src/test/run-make/save-analysis-fail/krate2.rs
new file mode 100644 (file)
index 0000000..2c6f517
--- /dev/null
@@ -0,0 +1,18 @@
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![ crate_name = "krate2" ]
+#![ crate_type = "lib" ]
+
+use std::io::Write;
+
+pub fn hello() {
+    std::io::stdout().write_all(b"hello world!\n");
+}
diff --git a/src/test/run-pass-fulldeps/myriad-closures.rs b/src/test/run-pass-fulldeps/myriad-closures.rs
new file mode 100644 (file)
index 0000000..a946ec6
--- /dev/null
@@ -0,0 +1,48 @@
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This test case tests whether we can handle code bases that contain a high
+// number of closures, something that needs special handling in the MingGW
+// toolchain.
+// See https://github.com/rust-lang/rust/issues/34793 for more information.
+
+// Make sure we don't optimize anything away:
+// compile-flags: -C no-prepopulate-passes
+
+// Expand something exponentially
+macro_rules! go_bacterial {
+    ($mac:ident) => ($mac!());
+    ($mac:ident 1 $($t:tt)*) => (
+        go_bacterial!($mac $($t)*);
+        go_bacterial!($mac $($t)*);
+    )
+}
+
+macro_rules! mk_closure {
+    () => ((move || {})())
+}
+
+macro_rules! mk_fn {
+    () => {
+        {
+            fn function() {
+                // Make 16 closures
+                go_bacterial!(mk_closure 1 1 1 1);
+            }
+            let _ = function();
+        }
+    }
+}
+
+fn main() {
+    // Make 2^12 functions, each containing 16 closures,
+    // resulting in 2^16 closures overall.
+    go_bacterial!(mk_fn 1 1 1 1  1 1 1 1  1 1 1 1);
+}
diff --git a/src/test/run-pass/auxiliary/rmeta_rlib.rs b/src/test/run-pass/auxiliary/rmeta_rlib.rs
new file mode 100644 (file)
index 0000000..28c1131
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// no-prefer-dynamic
+
+#![crate_type="rlib"]
+#![crate_name="rmeta_aux"]
+
+pub struct Foo {
+    pub field: i32,
+}
diff --git a/src/test/run-pass/auxiliary/rmeta_rmeta.rs b/src/test/run-pass/auxiliary/rmeta_rmeta.rs
new file mode 100644 (file)
index 0000000..394845b
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// no-prefer-dynamic
+
+#![crate_type="metadata"]
+#![crate_name="rmeta_aux"]
+
+pub struct Foo {
+    pub field2: i32,
+}
diff --git a/src/test/run-pass/issue-23699.rs b/src/test/run-pass/issue-23699.rs
new file mode 100644 (file)
index 0000000..1909be4
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn gimme_a_raw_pointer<T>(_: *const T) { }
+
+fn test<T>(t: T) { }
+
+fn main() {
+    // Clearly `pointer` must be of type `*const ()`.
+    let pointer = &() as *const _;
+    gimme_a_raw_pointer(pointer);
+
+    let t = test as fn (i32);
+    t(0i32);
+}
+
diff --git a/src/test/run-pass/loop-break-value.rs b/src/test/run-pass/loop-break-value.rs
new file mode 100644 (file)
index 0000000..6a5e051
--- /dev/null
@@ -0,0 +1,133 @@
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(loop_break_value)]
+#![feature(never_type)]
+
+#[allow(unused)]
+fn never_returns() {
+    loop {
+        break loop {};
+    }
+}
+
+pub fn main() {
+    let value = 'outer: loop {
+        if 1 == 1 {
+            break 13;
+        } else {
+            let _never: ! = loop {
+                break loop {
+                    break 'outer panic!();
+                }
+            };
+        }
+    };
+    assert_eq!(value, 13);
+
+    let x = [1, 3u32, 5];
+    let y = [17];
+    let z = [];
+    let coerced: &[_] = loop {
+        match 2 {
+            1 => break &x,
+            2 => break &y,
+            3 => break &z,
+            _ => (),
+        }
+    };
+    assert_eq!(coerced, &[17u32]);
+
+    let trait_unified = loop {
+        break if true {
+            break Default::default()
+        } else {
+            break [13, 14]
+        };
+    };
+    assert_eq!(trait_unified, [0, 0]);
+
+    let trait_unified_2 = loop {
+        if false {
+            break [String::from("Hello")]
+        } else {
+            break Default::default()
+        };
+    };
+    assert_eq!(trait_unified_2, [""]);
+
+    let trait_unified_3 = loop {
+        break if false {
+            break [String::from("Hello")]
+        } else {
+            ["Yes".into()]
+        };
+    };
+    assert_eq!(trait_unified_3, ["Yes"]);
+
+    let regular_break = loop {
+        if true {
+            break;
+        } else {
+            break break Default::default();
+        }
+    };
+    assert_eq!(regular_break, ());
+
+    let regular_break_2 = loop {
+        if true {
+            break Default::default();
+        } else {
+            break;
+        }
+    };
+    assert_eq!(regular_break_2, ());
+
+    let regular_break_3 = loop {
+        break if true {
+            Default::default()
+        } else {
+            break;
+        }
+    };
+    assert_eq!(regular_break_3, ());
+
+    let regular_break_4 = loop {
+        break ();
+        break;
+    };
+    assert_eq!(regular_break_4, ());
+
+    let regular_break_5 = loop {
+        break;
+        break ();
+    };
+    assert_eq!(regular_break_5, ());
+
+    let nested_break_value = 'outer2: loop {
+        let _a: u32 = 'inner: loop {
+            if true {
+                break 'outer2 "hello";
+            } else {
+                break 'inner 17;
+            }
+        };
+        panic!();
+    };
+    assert_eq!(nested_break_value, "hello");
+
+    let break_from_while_cond = loop {
+        while break {
+            panic!();
+        }
+        break 123;
+    };
+    assert_eq!(break_from_while_cond, 123);
+}
diff --git a/src/test/run-pass/myriad-closures.rs b/src/test/run-pass/myriad-closures.rs
deleted file mode 100644 (file)
index d2c9a5d..0000000
+++ /dev/null
@@ -1,48 +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 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// This test case tests whether we can handle code bases that contain a high
-// number of closures, something that needs special handling in the MingGW
-// toolchain.
-// See https://github.com/rust-lang/rust/issues/34793 for more information.
-
-// Expand something exponentially
-macro_rules! go_bacterial {
-    ($mac:ident) => ($mac!());
-    ($mac:ident 1 $($t:tt)*) => (
-        go_bacterial!($mac $($t)*);
-        go_bacterial!($mac $($t)*);
-    )
-}
-
-macro_rules! mk_closure {
-    () => ({
-        let c = |a: u32| a + 4;
-        let _ = c(2);
-    })
-}
-
-macro_rules! mk_fn {
-    () => {
-        {
-            fn function() {
-                // Make 16 closures
-                go_bacterial!(mk_closure 1 1 1 1);
-            }
-            let _ = function();
-        }
-    }
-}
-
-fn main() {
-    // Make 2^12 functions, each containing 16 closures,
-    // resulting in 2^16 closures overall.
-    go_bacterial!(mk_fn 1 1 1 1  1 1 1 1  1 1 1 1);
-}
diff --git a/src/test/run-pass/rmeta.rs b/src/test/run-pass/rmeta.rs
new file mode 100644 (file)
index 0000000..11684d8
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that using rlibs and rmeta dep crates work together. Specifically, that
+// there can be both an rmeta and an rlib file and rustc will prefer the rlib.
+
+// aux-build:rmeta_rmeta.rs
+// aux-build:rmeta_rlib.rs
+
+extern crate rmeta_aux;
+use rmeta_aux::Foo;
+
+pub fn main() {
+    let _ = Foo { field: 42 };
+}
diff --git a/src/test/ui/print_type_sizes/anonymous.rs b/src/test/ui/print_type_sizes/anonymous.rs
new file mode 100644 (file)
index 0000000..dc93bdd
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: -Z print-type-sizes
+
+// All of the types that occur in this function are uninteresting, in
+// that one cannot control the sizes of these types with the same sort
+// of enum-variant manipulation tricks.
+
+pub fn main() {
+    let _byte: u8 = 0;
+    let _word: usize = 0;
+    let _tuple: (u8, usize)= (0, 0);
+    let _array: [u8; 128] = [0; 128];
+    let _fn: fn (u8) -> u8 = id;
+    let _diverging: fn (u8) -> ! = bye;
+
+    fn id(x: u8) -> u8 { x };
+    fn bye(_: u8) -> ! { loop { } }
+}
diff --git a/src/test/ui/print_type_sizes/generics.rs b/src/test/ui/print_type_sizes/generics.rs
new file mode 100644 (file)
index 0000000..93bcd1c
--- /dev/null
@@ -0,0 +1,73 @@
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: -Z print-type-sizes
+
+// This file illustrates how generics are handled: types have to be
+// monomorphized, in the MIR of the original function in which they
+// occur, to have their size reported.
+
+// In an ad-hoc attempt to avoid the injection of unwinding code
+// (which clutters the output of `-Z print-type-sizes` with types from
+// `unwind::libunwind`):
+//
+//   * I am not using Default to build values because that seems to
+//     cause the injection of unwinding code. (Instead I just make `fn new`
+//     methods.)
+//
+//   * Pair derive Copy to ensure that we don't inject
+//     unwinding code into generic uses of Pair when T itself is also
+//     Copy.
+//
+//     (I suspect this reflect some naivety within the rust compiler
+//      itself; it should be checking for drop glue, i.e. a destructor
+//      somewhere in the monomorphized types. It should not matter whether
+//      the type is Copy.)
+#[derive(Copy, Clone)]
+pub struct Pair<T> {
+    _car: T,
+    _cdr: T,
+}
+
+impl<T> Pair<T> {
+    fn new(a: T, d: T) -> Self {
+        Pair {
+            _car: a,
+            _cdr: d,
+        }
+    }
+}
+
+#[derive(Copy, Clone)]
+pub struct SevenBytes([u8; 7]);
+pub struct FiftyBytes([u8; 50]);
+
+pub struct ZeroSized;
+
+impl SevenBytes {
+    fn new() -> Self { SevenBytes([0; 7]) }
+}
+
+impl FiftyBytes {
+    fn new() -> Self { FiftyBytes([0; 50]) }
+}
+
+pub fn f1<T:Copy>(x: T) {
+    let _v: Pair<T> = Pair::new(x, x);
+    let _v2: Pair<FiftyBytes> =
+        Pair::new(FiftyBytes::new(), FiftyBytes::new());
+}
+
+pub fn main() {
+    let _b: Pair<u8> = Pair::new(0, 0);
+    let _s: Pair<SevenBytes> = Pair::new(SevenBytes::new(), SevenBytes::new());
+    let _z: ZeroSized = ZeroSized;
+    f1::<SevenBytes>(SevenBytes::new());
+}
diff --git a/src/test/ui/print_type_sizes/generics.stdout b/src/test/ui/print_type_sizes/generics.stdout
new file mode 100644 (file)
index 0000000..0f02f39
--- /dev/null
@@ -0,0 +1,14 @@
+print-type-size type: `Pair<FiftyBytes>`: 100 bytes, alignment: 1 bytes
+print-type-size     field `._car`: 50 bytes
+print-type-size     field `._cdr`: 50 bytes
+print-type-size type: `FiftyBytes`: 50 bytes, alignment: 1 bytes
+print-type-size     field `.0`: 50 bytes
+print-type-size type: `Pair<SevenBytes>`: 14 bytes, alignment: 1 bytes
+print-type-size     field `._car`: 7 bytes
+print-type-size     field `._cdr`: 7 bytes
+print-type-size type: `SevenBytes`: 7 bytes, alignment: 1 bytes
+print-type-size     field `.0`: 7 bytes
+print-type-size type: `Pair<u8>`: 2 bytes, alignment: 1 bytes
+print-type-size     field `._car`: 1 bytes
+print-type-size     field `._cdr`: 1 bytes
+print-type-size type: `ZeroSized`: 0 bytes, alignment: 1 bytes
diff --git a/src/test/ui/print_type_sizes/multiple_types.rs b/src/test/ui/print_type_sizes/multiple_types.rs
new file mode 100644 (file)
index 0000000..2b50107
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: -Z print-type-sizes
+
+// This file illustrates that when multiple structural types occur in
+// a function, every one of them is included in the output.
+
+pub struct SevenBytes([u8;  7]);
+pub struct FiftyBytes([u8; 50]);
+
+pub enum Enum {
+    Small(SevenBytes),
+    Large(FiftyBytes),
+}
+
+pub fn main() {
+    let _e: Enum;
+    let _f: FiftyBytes;
+    let _s: SevenBytes;
+}
diff --git a/src/test/ui/print_type_sizes/multiple_types.stdout b/src/test/ui/print_type_sizes/multiple_types.stdout
new file mode 100644 (file)
index 0000000..eed9af2
--- /dev/null
@@ -0,0 +1,10 @@
+print-type-size type: `Enum`: 51 bytes, alignment: 1 bytes
+print-type-size     discriminant: 1 bytes
+print-type-size     variant `Small`: 7 bytes
+print-type-size         field `.0`: 7 bytes
+print-type-size     variant `Large`: 50 bytes
+print-type-size         field `.0`: 50 bytes
+print-type-size type: `FiftyBytes`: 50 bytes, alignment: 1 bytes
+print-type-size     field `.0`: 50 bytes
+print-type-size type: `SevenBytes`: 7 bytes, alignment: 1 bytes
+print-type-size     field `.0`: 7 bytes
diff --git a/src/test/ui/print_type_sizes/no_duplicates.rs b/src/test/ui/print_type_sizes/no_duplicates.rs
new file mode 100644 (file)
index 0000000..6008a34
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: -Z print-type-sizes
+
+// This file illustrates that when the same type occurs repeatedly
+// (even if multiple functions), it is only printed once in the
+// print-type-sizes output.
+
+pub struct SevenBytes([u8; 7]);
+
+pub fn f1() {
+    let _s: SevenBytes = SevenBytes([0; 7]);
+}
+
+pub fn main() {
+    let _s: SevenBytes = SevenBytes([0; 7]);
+}
diff --git a/src/test/ui/print_type_sizes/no_duplicates.stdout b/src/test/ui/print_type_sizes/no_duplicates.stdout
new file mode 100644 (file)
index 0000000..50180f3
--- /dev/null
@@ -0,0 +1,2 @@
+print-type-size type: `SevenBytes`: 7 bytes, alignment: 1 bytes
+print-type-size     field `.0`: 7 bytes
diff --git a/src/test/ui/print_type_sizes/nullable.rs b/src/test/ui/print_type_sizes/nullable.rs
new file mode 100644 (file)
index 0000000..f7fdcac
--- /dev/null
@@ -0,0 +1,69 @@
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: -Z print-type-sizes
+
+// This file illustrates how enums with a non-null field are handled,
+// modelled after cases like `Option<&u32>` and such.
+//
+// It uses NonZero directly, rather than `&_` or `Unique<_>`, because
+// the test is not set up to deal with target-dependent pointer width.
+//
+// It avoids using u64/i64 because on some targets that is only 4-byte
+// aligned (while on most it is 8-byte aligned) and so the resulting
+// padding and overall computed sizes can be quite different.
+
+#![feature(nonzero)]
+#![allow(dead_code)]
+
+extern crate core;
+use core::nonzero::{NonZero, Zeroable};
+
+pub enum MyOption<T> { None, Some(T) }
+
+impl<T> Default for MyOption<T> {
+    fn default() -> Self { MyOption::None }
+}
+
+pub enum EmbeddedDiscr {
+    None,
+    Record { pre: u8, val: NonZero<u32>, post: u16 },
+}
+
+impl Default for EmbeddedDiscr {
+    fn default() -> Self { EmbeddedDiscr::None }
+}
+
+#[derive(Default)]
+pub struct IndirectNonZero<T: Zeroable> {
+    pre: u8,
+    nested: NestedNonZero<T>,
+    post: u16,
+}
+
+pub struct NestedNonZero<T: Zeroable> {
+    pre: u8,
+    val: NonZero<T>,
+    post: u16,
+}
+
+impl<T: Zeroable+Default> Default for NestedNonZero<T> {
+    fn default() -> Self {
+        unsafe {
+            NestedNonZero { pre: 0, val: NonZero::new(Default::default()), post: 0 }
+        }
+    }
+}
+
+pub fn main() {
+    let _x: MyOption<NonZero<u32>> = Default::default();
+    let _y: EmbeddedDiscr = Default::default();
+    let _z: MyOption<IndirectNonZero<u32>> = Default::default();
+}
diff --git a/src/test/ui/print_type_sizes/nullable.stdout b/src/test/ui/print_type_sizes/nullable.stdout
new file mode 100644 (file)
index 0000000..dd999c4
--- /dev/null
@@ -0,0 +1,27 @@
+print-type-size type: `IndirectNonZero<u32>`: 20 bytes, alignment: 4 bytes
+print-type-size     field `.pre`: 1 bytes
+print-type-size     padding: 3 bytes
+print-type-size     field `.nested`: 12 bytes, alignment: 4 bytes
+print-type-size     field `.post`: 2 bytes
+print-type-size     end padding: 2 bytes
+print-type-size type: `MyOption<IndirectNonZero<u32>>`: 20 bytes, alignment: 4 bytes
+print-type-size     variant `Some`: 20 bytes
+print-type-size         field `.0`: 20 bytes
+print-type-size type: `EmbeddedDiscr`: 12 bytes, alignment: 4 bytes
+print-type-size     variant `Record`: 10 bytes
+print-type-size         field `.pre`: 1 bytes
+print-type-size         padding: 3 bytes
+print-type-size         field `.val`: 4 bytes, alignment: 4 bytes
+print-type-size         field `.post`: 2 bytes
+print-type-size     end padding: 2 bytes
+print-type-size type: `NestedNonZero<u32>`: 12 bytes, alignment: 4 bytes
+print-type-size     field `.pre`: 1 bytes
+print-type-size     padding: 3 bytes
+print-type-size     field `.val`: 4 bytes, alignment: 4 bytes
+print-type-size     field `.post`: 2 bytes
+print-type-size     end padding: 2 bytes
+print-type-size type: `MyOption<core::nonzero::NonZero<u32>>`: 4 bytes, alignment: 4 bytes
+print-type-size     variant `Some`: 4 bytes
+print-type-size         field `.0`: 4 bytes
+print-type-size type: `core::nonzero::NonZero<u32>`: 4 bytes, alignment: 4 bytes
+print-type-size     field `.0`: 4 bytes
diff --git a/src/test/ui/print_type_sizes/packed.rs b/src/test/ui/print_type_sizes/packed.rs
new file mode 100644 (file)
index 0000000..cd7ef86
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: -Z print-type-sizes
+
+// This file illustrates how packing is handled; it should cause
+// the elimination of padding that would normally be introduced
+// to satisfy alignment desirata.
+//
+// It avoids using u64/i64 because on some targets that is only 4-byte
+// aligned (while on most it is 8-byte aligned) and so the resulting
+// padding and overall computed sizes can be quite different.
+
+#![feature(untagged_unions)]
+
+#![allow(dead_code)]
+
+#[derive(Default)]
+#[repr(packed)]
+struct Packed {
+    a: u8,
+    b: u8,
+    g: i32,
+    c: u8,
+    h: i16,
+    d: u8,
+}
+
+#[derive(Default)]
+struct Padded {
+    a: u8,
+    b: u8,
+    g: i32,
+    c: u8,
+    h: i16,
+    d: u8,
+}
+
+pub fn main() {
+    let _c: Packed = Default::default();
+    let _d: Padded = Default::default();
+}
diff --git a/src/test/ui/print_type_sizes/packed.stdout b/src/test/ui/print_type_sizes/packed.stdout
new file mode 100644 (file)
index 0000000..1278a7d
--- /dev/null
@@ -0,0 +1,17 @@
+print-type-size type: `Padded`: 16 bytes, alignment: 4 bytes
+print-type-size     field `.a`: 1 bytes
+print-type-size     field `.b`: 1 bytes
+print-type-size     padding: 2 bytes
+print-type-size     field `.g`: 4 bytes, alignment: 4 bytes
+print-type-size     field `.c`: 1 bytes
+print-type-size     padding: 1 bytes
+print-type-size     field `.h`: 2 bytes, alignment: 2 bytes
+print-type-size     field `.d`: 1 bytes
+print-type-size     end padding: 3 bytes
+print-type-size type: `Packed`: 10 bytes, alignment: 1 bytes
+print-type-size     field `.a`: 1 bytes
+print-type-size     field `.b`: 1 bytes
+print-type-size     field `.g`: 4 bytes
+print-type-size     field `.c`: 1 bytes
+print-type-size     field `.h`: 2 bytes
+print-type-size     field `.d`: 1 bytes
diff --git a/src/test/ui/print_type_sizes/padding.rs b/src/test/ui/print_type_sizes/padding.rs
new file mode 100644 (file)
index 0000000..af34a90
--- /dev/null
@@ -0,0 +1,39 @@
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: -Z print-type-sizes
+
+// This file illustrates how padding is handled: alignment
+// requirements can lead to the introduction of padding, either before
+// fields or at the end of the structure as a whole.
+//
+// It avoids using u64/i64 because on some targets that is only 4-byte
+// aligned (while on most it is 8-byte aligned) and so the resulting
+// padding and overall computed sizes can be quite different.
+
+#![allow(dead_code)]
+
+struct S {
+    a: bool,
+    b: bool,
+    g: i32,
+}
+
+enum E1 {
+    A(i32, i8),
+    B(S),
+}
+
+enum E2 {
+    A(i8, i32),
+    B(S),
+}
+
+fn main() { }
diff --git a/src/test/ui/print_type_sizes/padding.stdout b/src/test/ui/print_type_sizes/padding.stdout
new file mode 100644 (file)
index 0000000..bb95f79
--- /dev/null
@@ -0,0 +1,21 @@
+print-type-size type: `E1`: 12 bytes, alignment: 4 bytes
+print-type-size     discriminant: 4 bytes
+print-type-size     variant `A`: 5 bytes
+print-type-size         field `.0`: 4 bytes
+print-type-size         field `.1`: 1 bytes
+print-type-size     variant `B`: 8 bytes
+print-type-size         field `.0`: 8 bytes
+print-type-size type: `E2`: 12 bytes, alignment: 4 bytes
+print-type-size     discriminant: 1 bytes
+print-type-size     variant `A`: 7 bytes
+print-type-size         field `.0`: 1 bytes
+print-type-size         padding: 2 bytes
+print-type-size         field `.1`: 4 bytes, alignment: 4 bytes
+print-type-size     variant `B`: 11 bytes
+print-type-size         padding: 3 bytes
+print-type-size         field `.0`: 8 bytes, alignment: 4 bytes
+print-type-size type: `S`: 8 bytes, alignment: 4 bytes
+print-type-size     field `.a`: 1 bytes
+print-type-size     field `.b`: 1 bytes
+print-type-size     padding: 2 bytes
+print-type-size     field `.g`: 4 bytes, alignment: 4 bytes
diff --git a/src/test/ui/print_type_sizes/variants.rs b/src/test/ui/print_type_sizes/variants.rs
new file mode 100644 (file)
index 0000000..875edb4
--- /dev/null
@@ -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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: -Z print-type-sizes
+
+// This file illustrates two things:
+//
+// 1. Only types that appear in a monomorphized function appear in the
+//    print-type-sizes output, and
+//
+// 2. For an enum, the print-type-sizes output will also include the
+//    size of each variant.
+
+pub struct SevenBytes([u8;  7]);
+pub struct FiftyBytes([u8; 50]);
+
+pub enum Enum {
+    Small(SevenBytes),
+    Large(FiftyBytes),
+}
+
+pub fn main() {
+    let _e: Enum;
+}
diff --git a/src/test/ui/print_type_sizes/variants.stdout b/src/test/ui/print_type_sizes/variants.stdout
new file mode 100644 (file)
index 0000000..eed9af2
--- /dev/null
@@ -0,0 +1,10 @@
+print-type-size type: `Enum`: 51 bytes, alignment: 1 bytes
+print-type-size     discriminant: 1 bytes
+print-type-size     variant `Small`: 7 bytes
+print-type-size         field `.0`: 7 bytes
+print-type-size     variant `Large`: 50 bytes
+print-type-size         field `.0`: 50 bytes
+print-type-size type: `FiftyBytes`: 50 bytes, alignment: 1 bytes
+print-type-size     field `.0`: 50 bytes
+print-type-size type: `SevenBytes`: 7 bytes, alignment: 1 bytes
+print-type-size     field `.0`: 7 bytes