]> git.lizzy.rs Git - rust.git/commitdiff
Auto merge of #38008 - bluss:rustbuild-benches, r=alexcrichton
authorbors <bors@rust-lang.org>
Sat, 26 Nov 2016 18:32:19 +0000 (12:32 -0600)
committerGitHub <noreply@github.com>
Sat, 26 Nov 2016 18:32:19 +0000 (12:32 -0600)
Add rustbuild command `bench`

Add command bench to rustbuild, so that `./x.py bench <path>` can compile and run benchmarks.

`./x.py bench --stage 1 src/libcollections` and `./x.py bench --stage 1 src/libstd` should both compile well. Just `./x.py bench` runs all benchmarks for the libstd crates.

Fixes #37897

77 files changed:
src/bootstrap/lib.rs
src/compiler-rt
src/doc/book/variable-bindings.md
src/libcollections/enum_set.rs
src/libcollections/lib.rs
src/libcollections/vec.rs
src/libcollectionstest/lib.rs
src/libcollectionstest/slice.rs
src/libcore/char.rs
src/libcore/iter/mod.rs
src/libcore/slice.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/structural_impls.rs
src/librustc/ty/sty.rs
src/librustc_const_eval/check_match.rs
src/librustc_driver/driver.rs
src/librustc_llvm/diagnostic.rs
src/librustc_llvm/ffi.rs
src/librustc_metadata/creader.rs
src/librustc_metadata/decoder.rs
src/librustc_metadata/encoder.rs
src/librustc_metadata/locator.rs
src/librustc_metadata/schema.rs
src/librustc_resolve/lib.rs
src/librustc_resolve/macros.rs
src/librustc_save_analysis/dump_visitor.rs
src/librustc_save_analysis/lib.rs
src/librustc_trans/adt.rs
src/librustc_trans/back/write.rs
src/librustc_trans/base.rs
src/librustc_unicode/char.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/Cargo.toml
src/libstd/error.rs
src/libstd/net/addr.rs
src/libstd/panicking.rs
src/libstd/sync/mpsc/mod.rs
src/libstd/sync/mutex.rs
src/libstd/sync/rwlock.rs
src/rustc/std_shim/Cargo.toml
src/rustllvm/RustWrapper.cpp
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/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 518eafb6f36c45015abf7b86d95326c746636a8e..03c74ff081ae0aa3768deb1462cf91a93f04ae80 100644 (file)
@@ -509,7 +509,7 @@ fn tool_cmd(&self, compiler: &Compiler, tool: &str) -> Command {
     /// Get the space-separated set of activated features for the standard
     /// library.
     fn std_features(&self) -> String {
-        let mut features = String::new();
+        let mut features = "panic-unwind".to_string();
         if self.config.debug_jemalloc {
             features.push_str(" debug-jemalloc");
         }
index 3bc0272cab9fdcfc2ef4df9625ec3c9d5909db79..a8fc4c169fac43a5dc204d4fd56ddb1739f8c178 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 3bc0272cab9fdcfc2ef4df9625ec3c9d5909db79
+Subproject commit a8fc4c169fac43a5dc204d4fd56ddb1739f8c178
index 54316649c715f3169b7e533413df92fbd833c23b..37b6c0513fc9647feef5562e6e31158e66e4c6bd 100644 (file)
@@ -47,7 +47,7 @@ let x: i32 = 5;
 ```
 
 If I asked you to read this out loud to the rest of the class, you’d say “`x`
-is a binding with the type `i32` and the value `five`.”
+is a binding with the type `i32` and the value `5`.”
 
 In this case we chose to represent `x` as a 32-bit signed integer. Rust has
 many different primitive integer types. They begin with `i` for signed integers
index 2d12b4ccffe01aa246611dd2afa3fb51b86052ef..79e0021b148a049f34e9f06a493cbd400ad618ea 100644 (file)
@@ -16,7 +16,7 @@
 #![unstable(feature = "enumset",
             reason = "matches collection reform specification, \
                       waiting for dust to settle",
-            issue = "0")]
+            issue = "37966")]
 
 use core::marker;
 use core::fmt;
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 26d28049a474d3f6d4076a3a52c8092a977963d9..966481e7b32bc65b5ca3f17951d24cf1aae0a4d9 100644 (file)
@@ -238,7 +238,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 /// A 'radix' here is sometimes also called a 'base'. A radix of two
 /// indicates a binary number, a radix of ten, decimal, and a radix of
 /// sixteen, hexadecimal, to give some common values. Arbitrary
-/// radicum are supported.
+/// radices are supported.
 ///
 /// `from_digit()` will return `None` if the input is not a digit in
 /// the given radix.
index 02a2e370547e9f147e038e871d4e619be0d14189..3999db0d63c99ac8770076f537e8807d5a8e33cc 100644 (file)
 //! often called 'iterator adapters', as they're a form of the 'adapter
 //! pattern'.
 //!
-//! Common iterator adapters include [`map()`], [`take()`], and [`collect()`].
+//! Common iterator adapters include [`map()`], [`take()`], and [`filter()`].
 //! For more, see their documentation.
 //!
 //! [`map()`]: trait.Iterator.html#method.map
 //! [`take()`]: trait.Iterator.html#method.take
-//! [`collect()`]: trait.Iterator.html#method.collect
+//! [`filter()`]: trait.Iterator.html#method.filter
 //!
 //! # Laziness
 //!
 //! [`map()`]: trait.Iterator.html#method.map
 //!
 //! The two most common ways to evaluate an iterator are to use a `for` loop
-//! like this, or using the [`collect()`] adapter to produce a new collection.
+//! like this, or using the [`collect()`] method to produce a new collection.
 //!
 //! [`collect()`]: trait.Iterator.html#method.collect
 //!
@@ -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>
@@ -920,7 +937,7 @@ unsafe impl<A, B> TrustedLen for Zip<A, B>
 /// you can also [`map()`] backwards:
 ///
 /// ```rust
-/// let v: Vec<i32> = vec![1, 2, 3].into_iter().rev().map(|x| x + 1).collect();
+/// let v: Vec<i32> = vec![1, 2, 3].into_iter().map(|x| x + 1).rev().collect();
 ///
 /// assert_eq!(v, [4, 3, 2]);
 /// ```
@@ -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>
@@ -1945,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.
@@ -2012,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> {}
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 f3677b8081953a2013543967cdf246b8247356e9..26dafed7019ed7b9e25c8f6732fb222636aa4ab6 100644 (file)
@@ -909,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],
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 ebf8c96def7cc1472d55b682d958b05a3253f91d..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;
@@ -1390,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 }
 
@@ -1532,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
@@ -1796,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,
@@ -1821,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)]
index e73be23a42c76d068416337e3ef2cd89e8d0f8b3..877da7ee3b51255167ab2f13db97edc2b85a8cd4 100644 (file)
@@ -481,7 +481,12 @@ fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F)
             ty::TyUint(_) | ty::TyFloat(_) | ty::TyError | ty::TyInfer(_) |
             ty::TyParam(..) | ty::TyNever => return self
         };
-        folder.tcx().mk_ty(sty)
+
+        if self.sty == sty {
+            self
+        } else {
+            folder.tcx().mk_ty(sty)
+        }
     }
 
     fn fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> 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 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 5cbb8f93fc9d40433f0c322c111de97c21b18bc2..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,
index 8767f03b3e756286ad0e9e183c9b05ec9dfc0545..e11274f2064dd43bd08d938c1501b254002fc831 100644 (file)
@@ -48,29 +48,32 @@ pub struct OptimizationDiagnostic {
     pub pass_name: *const c_char,
     pub function: ValueRef,
     pub debug_loc: DebugLocRef,
-    pub message: TwineRef,
+    pub message: String,
 }
 
 impl OptimizationDiagnostic {
     unsafe fn unpack(kind: OptimizationDiagnosticKind,
                      di: DiagnosticInfoRef)
                      -> OptimizationDiagnostic {
-
-        let mut opt = OptimizationDiagnostic {
+        let mut pass_name = ptr::null();
+        let mut function = ptr::null_mut();
+        let mut debug_loc = ptr::null_mut();
+
+        let message = super::build_string(|message|
+            super::LLVMRustUnpackOptimizationDiagnostic(di,
+                                                        &mut pass_name,
+                                                        &mut function,
+                                                        &mut debug_loc,
+                                                        message)
+        );
+
+        OptimizationDiagnostic {
             kind: kind,
-            pass_name: ptr::null(),
-            function: ptr::null_mut(),
-            debug_loc: ptr::null_mut(),
-            message: ptr::null_mut(),
-        };
-
-        super::LLVMRustUnpackOptimizationDiagnostic(di,
-                                                    &mut opt.pass_name,
-                                                    &mut opt.function,
-                                                    &mut opt.debug_loc,
-                                                    &mut opt.message);
-
-        opt
+            pass_name: pass_name,
+            function: function,
+            debug_loc: debug_loc,
+            message: message.expect("got a non-UTF8 OptimizationDiagnostic message from LLVM")
+        }
     }
 }
 
index 470e8d1fd4578d75eb2bb86274f4674713abfba0..15bca0207c707a0f5ee8d1c8e847531decf87340 100644 (file)
@@ -1823,7 +1823,7 @@ pub fn LLVMRustUnpackOptimizationDiagnostic(DI: DiagnosticInfoRef,
                                                 pass_name_out: *mut *const c_char,
                                                 function_out: *mut ValueRef,
                                                 debugloc_out: *mut DebugLocRef,
-                                                message_out: *mut TwineRef);
+                                                message_out: RustStringRef);
     pub fn LLVMRustUnpackInlineAsmDiagnostic(DI: DiagnosticInfoRef,
                                              cookie_out: *mut c_uint,
                                              message_out: *mut TwineRef,
index 27c00481bfd3adad17006212acada0650b339915..372152d2b0a138ba6f232cf31171b5bdd43de16a 100644 (file)
@@ -344,6 +344,7 @@ fn resolve_crate(&mut self,
                 rejected_via_triple: vec![],
                 rejected_via_kind: vec![],
                 rejected_via_version: vec![],
+                rejected_via_filename: vec![],
                 should_match_name: true,
                 is_proc_macro: Some(false),
             };
@@ -359,6 +360,7 @@ fn resolve_crate(&mut self,
                     rejected_via_triple: vec![],
                     rejected_via_kind: vec![],
                     rejected_via_version: vec![],
+                    rejected_via_filename: vec![],
                     is_proc_macro: Some(true),
                     ..locate_ctxt
                 };
@@ -502,6 +504,7 @@ fn read_extension_crate(&mut self, span: Span, info: &ExternCrateInfo) -> Extens
             rejected_via_triple: vec![],
             rejected_via_kind: vec![],
             rejected_via_version: vec![],
+            rejected_via_filename: vec![],
             should_match_name: true,
             is_proc_macro: None,
         };
index 8a187bb97969a385145c1e098a26e60c8ea28b01..f59f2bcc074764c42bf61f55e5da3a6729239536 100644 (file)
@@ -421,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 be9284baa74cbabe6f37d9c7e3b9e36b1894fe7e..de465ea92f6b81a3dbb2cc38bb718454e9c386d0 100644 (file)
@@ -269,6 +269,7 @@ pub struct Context<'a> {
     pub rejected_via_triple: Vec<CrateMismatch>,
     pub rejected_via_kind: Vec<CrateMismatch>,
     pub rejected_via_version: Vec<CrateMismatch>,
+    pub rejected_via_filename: Vec<CrateMismatch>,
     pub should_match_name: bool,
     pub is_proc_macro: Option<bool>,
 }
@@ -417,6 +418,18 @@ pub fn report_errs(&mut self) -> ! {
                                   got));
             }
         }
+        if !self.rejected_via_filename.is_empty() {
+            let dylibname = self.dylibname();
+            let mismatches = self.rejected_via_filename.iter();
+            for &CrateMismatch { ref path, .. } in mismatches {
+                err.note(&format!("extern location for {} is of an unknown type: {}",
+                                  self.crate_name,
+                                  path.display()))
+                   .help(&format!("file name should be lib*.rlib or {}*.{}",
+                                  dylibname.0,
+                                  dylibname.1));
+            }
+        }
 
         err.emit();
         self.sess.abort_if_errors();
@@ -639,25 +652,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");
@@ -742,13 +756,12 @@ fn find_commandline_library<'b, LOCS>(&mut self, locs: LOCS) -> Option<Library>
                         return true;
                     }
                 }
-                sess.struct_err(&format!("extern location for {} is of an unknown type: {}",
-                                         self.crate_name,
-                                         loc.display()))
-                    .help(&format!("file name should be lib*.rlib or {}*.{}",
-                                   dylibname.0,
-                                   dylibname.1))
-                    .emit();
+
+                self.rejected_via_filename.push(CrateMismatch {
+                    path: loc.clone(),
+                    got: String::new(),
+                });
+
                 false
             });
 
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 ab3d361a940f9ed9dba097742ff07302db613b76..30d25c7ccecdd162a17933e456d7a03bb29fd660 100644 (file)
@@ -1137,7 +1137,7 @@ pub struct Resolver<'a> {
     crate_loader: &'a mut CrateLoader,
     macro_names: FxHashSet<Name>,
     builtin_macros: FxHashMap<Name, &'a NameBinding<'a>>,
-    lexical_macro_resolutions: Vec<(Name, LegacyScope<'a>)>,
+    lexical_macro_resolutions: Vec<(Name, &'a Cell<LegacyScope<'a>>)>,
     macro_map: FxHashMap<DefId, Rc<SyntaxExtension>>,
     macro_exports: Vec<Export>,
 
@@ -3419,7 +3419,7 @@ fn report_shadowing_errors(&mut self) {
 
         let mut reported_errors = FxHashSet();
         for binding in replace(&mut self.disallowed_shadowing, Vec::new()) {
-            if self.resolve_legacy_scope(binding.parent, binding.name, false).is_some() &&
+            if self.resolve_legacy_scope(&binding.parent, binding.name, false).is_some() &&
                reported_errors.insert((binding.name, binding.span)) {
                 let msg = format!("`{}` is already in scope", binding.name);
                 self.session.struct_span_err(binding.span, &msg)
index 62adf382a69add955ddddc8125e83a7785f9124f..cdb51f459e8c29ce965084776dffe583fe936a34 100644 (file)
@@ -66,21 +66,8 @@ pub enum LegacyScope<'a> {
     Binding(&'a LegacyBinding<'a>),
 }
 
-impl<'a> LegacyScope<'a> {
-    fn simplify_expansion(mut invoc: &'a InvocationData<'a>) -> Self {
-        while let LegacyScope::Invocation(_) = invoc.expansion.get() {
-            match invoc.legacy_scope.get() {
-                LegacyScope::Expansion(new_invoc) => invoc = new_invoc,
-                LegacyScope::Binding(_) => break,
-                scope @ _ => return scope,
-            }
-        }
-        LegacyScope::Expansion(invoc)
-    }
-}
-
 pub struct LegacyBinding<'a> {
-    pub parent: LegacyScope<'a>,
+    pub parent: Cell<LegacyScope<'a>>,
     pub name: ast::Name,
     ext: Rc<SyntaxExtension>,
     pub span: Span,
@@ -157,7 +144,7 @@ fn add_macro(&mut self, scope: Mark, mut def: ast::MacroDef, export: bool) {
 
         let invocation = self.invocations[&scope];
         let binding = self.arenas.alloc_legacy_binding(LegacyBinding {
-            parent: invocation.legacy_scope.get(),
+            parent: Cell::new(invocation.legacy_scope.get()),
             name: def.ident.name,
             ext: Rc::new(macro_rules::compile(&self.session.parse_sess, &def)),
             span: def.span,
@@ -228,12 +215,8 @@ fn resolve_macro(&mut self, scope: Mark, path: &ast::Path, force: bool)
         let name = path.segments[0].identifier.name;
 
         let invocation = self.invocations[&scope];
-        if let LegacyScope::Expansion(parent) = invocation.legacy_scope.get() {
-            invocation.legacy_scope.set(LegacyScope::simplify_expansion(parent));
-        }
-
         self.current_module = invocation.module.get();
-        let result = match self.resolve_legacy_scope(invocation.legacy_scope.get(), name, false) {
+        let result = match self.resolve_legacy_scope(&invocation.legacy_scope, name, false) {
             Some(MacroBinding::Legacy(binding)) => Ok(binding.ext.clone()),
             Some(MacroBinding::Modern(binding)) => Ok(self.get_macro(binding)),
             None => match self.resolve_in_item_lexical_scope(name, MacroNS, None) {
@@ -299,7 +282,7 @@ fn resolve_in_item_lexical_scope(&mut self,
     }
 
     pub fn resolve_legacy_scope(&mut self,
-                                mut scope: LegacyScope<'a>,
+                                mut scope: &'a Cell<LegacyScope<'a>>,
                                 name: Name,
                                 record_used: bool)
                                 -> Option<MacroBinding<'a>> {
@@ -307,22 +290,26 @@ pub fn resolve_legacy_scope(&mut self,
         let mut relative_depth: u32 = 0;
         let mut binding = None;
         loop {
-            scope = match scope {
+            match scope.get() {
                 LegacyScope::Empty => break,
                 LegacyScope::Expansion(invocation) => {
-                    if let LegacyScope::Empty = invocation.expansion.get() {
-                        if possible_time_travel.is_none() {
-                            possible_time_travel = Some(scope);
+                    match invocation.expansion.get() {
+                        LegacyScope::Invocation(_) => scope.set(invocation.legacy_scope.get()),
+                        LegacyScope::Empty => {
+                            if possible_time_travel.is_none() {
+                                possible_time_travel = Some(scope);
+                            }
+                            scope = &invocation.legacy_scope;
+                        }
+                        _ => {
+                            relative_depth += 1;
+                            scope = &invocation.expansion;
                         }
-                        invocation.legacy_scope.get()
-                    } else {
-                        relative_depth += 1;
-                        invocation.expansion.get()
                     }
                 }
                 LegacyScope::Invocation(invocation) => {
                     relative_depth = relative_depth.saturating_sub(1);
-                    invocation.legacy_scope.get()
+                    scope = &invocation.legacy_scope;
                 }
                 LegacyScope::Binding(potential_binding) => {
                     if potential_binding.name == name {
@@ -332,7 +319,7 @@ pub fn resolve_legacy_scope(&mut self,
                         binding = Some(potential_binding);
                         break
                     }
-                    potential_binding.parent
+                    scope = &potential_binding.parent;
                 }
             };
         }
@@ -358,7 +345,7 @@ pub fn resolve_legacy_scope(&mut self,
     pub fn finalize_current_module_macro_resolutions(&mut self) {
         let module = self.current_module;
         for &(mark, name, span) in module.legacy_macro_resolutions.borrow().iter() {
-            let legacy_scope = self.invocations[&mark].legacy_scope.get();
+            let legacy_scope = &self.invocations[&mark].legacy_scope;
             let legacy_resolution = self.resolve_legacy_scope(legacy_scope, name, true);
             let resolution = self.resolve_in_item_lexical_scope(name, MacroNS, Some(span));
             let (legacy_resolution, resolution) = match (legacy_resolution, resolution) {
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 01eea08c50bc589dab4d36dba16eefc5e715c08e..029930472586e6370953da8dafe76838725cb058 100644 (file)
@@ -417,7 +417,7 @@ struct HandlerFreeVars<'a> {
                                                 opt.kind.describe(),
                                                 pass_name,
                                                 if loc.is_empty() { "[unknown]" } else { &*loc },
-                                                llvm::twine_to_string(opt.message)));
+                                                opt.message));
             }
         }
 
index 4353c7bd58645fb1a8b957cd8b3de5243935a9ee..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! {
@@ -1741,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);
@@ -1771,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 702d7d8b4b2ca421aac2a4bf796d7a1aeabd0d18..94599216db6a849d36e95f29b3d19fe047442f0f 100644 (file)
@@ -138,7 +138,7 @@ impl char {
     /// A 'radix' here is sometimes also called a 'base'. A radix of two
     /// indicates a binary number, a radix of ten, decimal, and a radix of
     /// sixteen, hexadecimal, to give some common values. Arbitrary
-    /// radicum are supported.
+    /// radices are supported.
     ///
     /// Compared to `is_numeric()`, this function only recognizes the characters
     /// `0-9`, `a-z` and `A-Z`.
@@ -190,7 +190,7 @@ pub fn is_digit(self, radix: u32) -> bool {
     /// A 'radix' here is sometimes also called a 'base'. A radix of two
     /// indicates a binary number, a radix of ten, decimal, and a radix of
     /// sixteen, hexadecimal, to give some common values. Arbitrary
-    /// radicum are supported.
+    /// radices are supported.
     ///
     /// 'Digit' is defined to be only the following characters:
     ///
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 21e6acc37f3d511845b9f8faf4d771a6ae0937e9..b9f52e20fdd8c9933c354509c2cfdafc82e54d24 100644 (file)
@@ -13,7 +13,7 @@ crate-type = ["dylib", "rlib"]
 alloc = { path = "../liballoc" }
 alloc_jemalloc = { path = "../liballoc_jemalloc", optional = true }
 alloc_system = { path = "../liballoc_system" }
-panic_unwind = { path = "../libpanic_unwind" }
+panic_unwind = { path = "../libpanic_unwind", optional = true }
 panic_abort = { path = "../libpanic_abort" }
 collections = { path = "../libcollections" }
 core = { path = "../libcore" }
@@ -29,5 +29,6 @@ gcc = "0.3.27"
 
 [features]
 backtrace = []
-jemalloc = ["alloc_jemalloc"]
 debug-jemalloc = ["alloc_jemalloc/debug"]
+jemalloc = ["alloc_jemalloc"]
+panic-unwind = ["panic_unwind"]
index 454fa47cfbc99f4277cfab407759e5d18ad0c132..e115263d2eb9591a536f6dd88144e64f58cb41db 100644 (file)
@@ -109,7 +109,7 @@ pub trait Error: Debug + Display {
     ///
     /// impl Error for SuperError {
     ///     fn description(&self) -> &str {
-    ///         "I'm the superhero of errors!"
+    ///         "I'm the superhero of errors"
     ///     }
     ///
     ///     fn cause(&self) -> Option<&Error> {
@@ -128,7 +128,7 @@ pub trait Error: Debug + Display {
     ///
     /// impl Error for SuperErrorSideKick {
     ///     fn description(&self) -> &str {
-    ///         "I'm SuperError side kick!"
+    ///         "I'm SuperError side kick"
     ///     }
     /// }
     ///
index 0328012ee57269a4411c6499da22de23907ff027..1ce37f6cc0a167bafe45cb51326cf07c18d80f1c 100644 (file)
@@ -282,6 +282,14 @@ pub fn set_port(&mut self, new_port: u16) {
 impl SocketAddrV6 {
     /// Creates a new socket address from the ip/port/flowinfo/scope_id
     /// components.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::{SocketAddrV6, Ipv6Addr};
+    ///
+    /// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 0);
+    /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn new(ip: Ipv6Addr, port: u16, flowinfo: u32, scope_id: u32)
                -> SocketAddrV6 {
@@ -298,6 +306,15 @@ pub fn new(ip: Ipv6Addr, port: u16, flowinfo: u32, scope_id: u32)
     }
 
     /// Returns the IP address associated with this socket address.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::{SocketAddrV6, Ipv6Addr};
+    ///
+    /// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 0);
+    /// assert_eq!(socket.ip(), &Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));
+    /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn ip(&self) -> &Ipv6Addr {
         unsafe {
@@ -306,18 +323,47 @@ pub fn ip(&self) -> &Ipv6Addr {
     }
 
     /// Change the IP address associated with this socket address.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::{SocketAddrV6, Ipv6Addr};
+    ///
+    /// let mut socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 0);
+    /// socket.set_ip(Ipv6Addr::new(76, 45, 0, 0, 0, 0, 0, 0));
+    /// assert_eq!(socket.ip(), &Ipv6Addr::new(76, 45, 0, 0, 0, 0, 0, 0));
+    /// ```
     #[stable(feature = "sockaddr_setters", since = "1.9.0")]
     pub fn set_ip(&mut self, new_ip: Ipv6Addr) {
         self.inner.sin6_addr = *new_ip.as_inner()
     }
 
     /// Returns the port number associated with this socket address.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::{SocketAddrV6, Ipv6Addr};
+    ///
+    /// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 0);
+    /// assert_eq!(socket.port(), 8080);
+    /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn port(&self) -> u16 {
         ntoh(self.inner.sin6_port)
     }
 
     /// Change the port number associated with this socket address.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::{SocketAddrV6, Ipv6Addr};
+    ///
+    /// let mut socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 0);
+    /// 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.sin6_port = hton(new_port);
@@ -325,12 +371,31 @@ pub fn set_port(&mut self, new_port: u16) {
 
     /// Returns the flow information associated with this address,
     /// corresponding to the `sin6_flowinfo` field in C.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::{SocketAddrV6, Ipv6Addr};
+    ///
+    /// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 10, 0);
+    /// assert_eq!(socket.flowinfo(), 10);
+    /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn flowinfo(&self) -> u32 {
         self.inner.sin6_flowinfo
     }
 
     /// Change the flow information associated with this socket address.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::{SocketAddrV6, Ipv6Addr};
+    ///
+    /// let mut socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 10, 0);
+    /// socket.set_flowinfo(56);
+    /// assert_eq!(socket.flowinfo(), 56);
+    /// ```
     #[stable(feature = "sockaddr_setters", since = "1.9.0")]
     pub fn set_flowinfo(&mut self, new_flowinfo: u32) {
         self.inner.sin6_flowinfo = new_flowinfo;
@@ -338,12 +403,31 @@ pub fn set_flowinfo(&mut self, new_flowinfo: u32) {
 
     /// Returns the scope ID associated with this address,
     /// corresponding to the `sin6_scope_id` field in C.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::{SocketAddrV6, Ipv6Addr};
+    ///
+    /// let socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 78);
+    /// assert_eq!(socket.scope_id(), 78);
+    /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn scope_id(&self) -> u32 {
         self.inner.sin6_scope_id
     }
 
     /// Change the scope ID associated with this socket address.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::net::{SocketAddrV6, Ipv6Addr};
+    ///
+    /// let mut socket = SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 78);
+    /// socket.set_scope_id(42);
+    /// assert_eq!(socket.scope_id(), 42);
+    /// ```
     #[stable(feature = "sockaddr_setters", since = "1.9.0")]
     pub fn set_scope_id(&mut self, new_scope_id: u32) {
         self.inner.sin6_scope_id = new_scope_id;
index 1f5b3437b615529e33be872ef99949d7329ae3e0..04050a5edc4523b94d89e2464737cb05cfa60f55 100644 (file)
@@ -153,7 +153,7 @@ pub fn take_hook() -> Box<Fn(&PanicInfo) + 'static + Sync + Send> {
 
         match hook {
             Hook::Default => Box::new(default_hook),
-            Hook::Custom(ptr) => {Box::from_raw(ptr)} // FIXME #30530
+            Hook::Custom(ptr) => Box::from_raw(ptr),
         }
     }
 }
index 2773629c7d7d4e63e911e0723a172d8e43deb98a..ca6e46eb15ac6451630d2159b05abc728cdbb9e4 100644 (file)
@@ -491,11 +491,11 @@ pub fn channel<T>() -> (Sender<T>, Receiver<T>) {
 /// becomes available. These channels differ greatly in the semantics of the
 /// sender from asynchronous channels, however.
 ///
-/// This channel has an internal buffer on which messages will be queued. When
-/// the internal buffer becomes full, future sends will *block* waiting for the
-/// buffer to open up. Note that a buffer size of 0 is valid, in which case this
-/// becomes  "rendezvous channel" where each send will not return until a recv
-/// is paired with it.
+/// This channel has an internal buffer on which messages will be queued. `bound`
+/// specifies the buffer size. When the internal buffer becomes full, future sends
+/// will *block* waiting for the buffer to open up. Note that a buffer size of 0
+/// is valid, in which case this becomes  "rendezvous channel" where each send will
+/// not return until a recv is paired with it.
 ///
 /// As with asynchronous channels, all senders will panic in `send` if the
 /// `Receiver` has been destroyed.
index 812724c7a167eaf13e61801d079dd421222c9315..df4a3746a49bd7480ae37eb1d536e12de816b34f 100644 (file)
@@ -133,7 +133,14 @@ unsafe impl<T: ?Sized + Send> Sync for Mutex<T> { }
 /// dropped (falls out of scope), the lock will be unlocked.
 ///
 /// The data protected by the mutex can be access through this guard via its
-/// `Deref` and `DerefMut` implementations
+/// `Deref` and `DerefMut` implementations.
+///
+/// This structure is created by the [`lock()`] and [`try_lock()`] methods on
+/// [`Mutex`].
+///
+/// [`lock()`]: struct.Mutex.html#method.lock
+/// [`try_lock()`]: struct.Mutex.html#method.try_lock
+/// [`Mutex`]: struct.Mutex.html
 #[must_use]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct MutexGuard<'a, T: ?Sized + 'a> {
index f08b7641521447582b4786c64c7db41c3480268a..f83cf7ba9c29e41dc21679f63cff17e0c44df7ed 100644 (file)
@@ -77,6 +77,13 @@ unsafe impl<T: ?Sized + Send + Sync> Sync for RwLock<T> {}
 
 /// RAII structure used to release the shared read access of a lock when
 /// dropped.
+///
+/// This structure is created by the [`read()`] and [`try_read()`] methods on
+/// [`RwLock`].
+///
+/// [`read()`]: struct.RwLock.html#method.read
+/// [`try_read()`]: struct.RwLock.html#method.try_read
+/// [`RwLock`]: struct.RwLock.html
 #[must_use]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct RwLockReadGuard<'a, T: ?Sized + 'a> {
@@ -88,6 +95,13 @@ impl<'a, T: ?Sized> !marker::Send for RwLockReadGuard<'a, T> {}
 
 /// RAII structure used to release the exclusive write access of a lock when
 /// dropped.
+///
+/// This structure is created by the [`write()`] and [`try_write()`] methods
+/// on [`RwLock`].
+///
+/// [`write()`]: struct.RwLock.html#method.write
+/// [`try_write()`]: struct.RwLock.html#method.try_write
+/// [`RwLock`]: struct.RwLock.html
 #[must_use]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct RwLockWriteGuard<'a, T: ?Sized + 'a> {
index 58a7bd8a1cb7519fa31ce820b44c0c0686ea2dc0..b4b7acc4e66b82b02e6847d1846741b27b05305a 100644 (file)
@@ -45,6 +45,7 @@ core = { path = "../../libcore" }
 
 # Reexport features from std
 [features]
-jemalloc = ["std/jemalloc"]
-debug-jemalloc = ["std/debug-jemalloc"]
 backtrace = ["std/backtrace"]
+debug-jemalloc = ["std/debug-jemalloc"]
+jemalloc = ["std/jemalloc"]
+panic-unwind = ["std/panic-unwind"]
index b035e134e37d52abedff817571f0f6e362991de8..9f0e38b53ff2717cf87278c7a9fb57763fa518f6 100644 (file)
@@ -747,7 +747,11 @@ extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateNameSpace(
         unwrapDI<DIDescriptor>(Scope),
         Name,
         unwrapDI<DIFile>(File),
-        LineNo));
+        LineNo
+#if LLVM_VERSION_GE(4, 0)
+        , false // ExportSymbols (only relevant for C++ anonymous namespaces)
+#endif
+    ));
 }
 
 extern "C" void LLVMRustDICompositeTypeSetTypeArray(
@@ -871,16 +875,21 @@ LLVMRustUnpackOptimizationDiagnostic(
     const char **pass_name_out,
     LLVMValueRef *function_out,
     LLVMDebugLocRef *debugloc_out,
-    LLVMTwineRef *message_out)
+    RustStringRef message_out)
 {
     // Undefined to call this not on an optimization diagnostic!
     llvm::DiagnosticInfoOptimizationBase *opt
         = static_cast<llvm::DiagnosticInfoOptimizationBase*>(unwrap(di));
 
+#if LLVM_VERSION_GE(4, 0)
+    *pass_name_out = opt->getPassName().data();
+#else
     *pass_name_out = opt->getPassName();
+#endif
     *function_out = wrap(&opt->getFunction());
     *debugloc_out = wrap(&opt->getDebugLoc());
-    *message_out = wrap(&opt->getMsg());
+    raw_rust_string_ostream os(message_out);
+    os << opt->getMsg();
 }
 
 extern "C" void
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/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