/// 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");
}
-Subproject commit 3bc0272cab9fdcfc2ef4df9625ec3c9d5909db79
+Subproject commit a8fc4c169fac43a5dc204d4fd56ddb1739f8c178
```
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
#![unstable(feature = "enumset",
reason = "matches collection reform specification, \
waiting for dust to settle",
- issue = "0")]
+ issue = "37966")]
use core::marker;
use core::fmt;
#![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)]
}
#[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> {}
#[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> {}
#![feature(const_fn)]
#![feature(dedup_by)]
#![feature(enumset)]
+#![feature(exact_size_is_empty)]
#![feature(pattern)]
#![feature(rand)]
#![feature(repeat_str)]
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];
/// 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.
//! 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
//!
#[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>
#[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>
/// 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]);
/// ```
#[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>
}
#[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>
#[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.
#[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>
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> {}
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> {}
--- /dev/null
+// 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);
+ }
+ }
+ }
+}
"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],
// 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;
use std::time::Duration;
use libc::c_int;
+mod code_stats;
pub mod config;
pub mod filesearch;
pub mod search_paths;
/// 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>,
}
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);
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(())
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(())
}
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;
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 }
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
}
}
+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,
}
}
+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)]
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 {
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;
}
}
- 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,
}
}
// 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 {} \
})??
};
+ 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,
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")
+ }
}
}
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,
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),
};
rejected_via_triple: vec![],
rejected_via_kind: vec![],
rejected_via_version: vec![],
+ rejected_via_filename: vec![],
is_proc_macro: Some(true),
..locate_ctxt
};
rejected_via_triple: vec![],
rejected_via_kind: vec![],
rejected_via_version: vec![],
+ rejected_via_filename: vec![],
should_match_name: true,
is_proc_macro: None,
};
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();
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,
// 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,
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.
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>,
}
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();
}
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");
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
});
/// 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];
#[derive(RustcEncodable, RustcDecodable)]
pub struct CrateRoot {
- pub rustc_version: String,
pub name: Symbol,
pub triple: String,
pub hash: hir::svh::Svh,
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>,
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)
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,
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,
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) {
}
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>> {
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 {
binding = Some(potential_binding);
break
}
- potential_binding.parent
+ scope = &potential_binding.parent;
}
};
}
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) {
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()),
}
})
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);
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 {
}
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)
}
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);
}
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 {
// 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);
opt.kind.describe(),
pass_name,
if loc.is_empty() { "[unknown]" } else { &*loc },
- llvm::twine_to_string(opt.message)));
+ opt.message));
}
}
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;
use syntax_pos::{Span, DUMMY_SP};
use syntax::attr;
use rustc::hir;
+use rustc::ty::layout::{self, Layout};
use syntax::ast;
thread_local! {
.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);
}
}
+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,
/// 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`.
/// 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:
///
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() => {
})
}
-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.
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),
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.
/// 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);
}
}
-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 {
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
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.
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
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),
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),
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 {
});
}
-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)
}
}
}
}
-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);
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
}
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::*;
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};
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> {
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));
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
pub struct ExternalCrate {
pub name: String,
- pub attrs: Vec<Attribute>,
+ pub attrs: Attributes,
pub primitives: Vec<PrimitiveType>,
}
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),
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,
/// 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 {
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
}
}
-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)
}
}
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),
}
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
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(),
output: output
}
},
- (..) => {
+ _ => {
PathParameters::AngleBracketed {
lifetimes: lifetimes,
types: types.clean(cx),
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 =>
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);
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())
}
},
output: self.decl.output.clean(cx),
variadic: false,
- attrs: Vec::new()
+ attrs: Attributes::default()
};
Method {
generics: self.generics.clean(cx),
},
output: self.decl.output.clean(cx),
variadic: false,
- attrs: Vec::new()
+ attrs: Attributes::default()
};
TyMethod {
unsafety: self.unsafety.clone(),
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),
pub inputs: Arguments,
pub output: FunctionRetTy,
pub variadic: bool,
- pub attrs: Vec<Attribute>,
+ pub attrs: Attributes,
}
impl FnDecl {
},
output: self.output.clean(cx),
variadic: self.variadic,
- attrs: Vec::new()
+ attrs: Attributes::default()
}
}
}
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| {
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),
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
}
}
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
}
}
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!()
};
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 {
// 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 {
}
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
};
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,
}
}
}
- 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;
}
}
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));
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)),
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) => {
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,
});
}
- 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,
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())
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)),
}
}
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),
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),
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),
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),
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),
}),
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),
};
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,
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),
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),
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),
// 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),
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 {
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() {
};
if let Some(did) = did {
if !did.is_local() {
- inline::build_impl(cx, tcx, did, ret);
+ inline::build_impl(cx, did, ret);
}
}
}
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,
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,
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,
}
}
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 {
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),
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
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
}
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)]
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,
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() {
// <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.
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
};
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(),
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)
};
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;
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;
// 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;
}
_ => {}
// 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> {
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));
}
}
}
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))?;
}
}
pub mod visit_lib;
pub mod test;
-use clean::Attributes;
+use clean::AttributesExt;
struct Output {
krate: clean::Crate,
!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))
}
}
/// 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");
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");
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()
}
// 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];
+ }
+ }
+}
use rustc::util::nodemap::DefIdSet;
use std::mem;
-use clean::{self, Attributes};
+use clean::{self, AttributesExt, NestedAttributesExt};
use clean::Item;
use plugins;
use fold;
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 {
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;
// 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::*;
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 {
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());
}
}
-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("&") {
- s = s.replace("&", "&");
+ 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(">") {
- s.replace(">", ">")
- .replace("<", "<")
- } 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);
+ });
}
}
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
}
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) {
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;
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 {
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) |
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);
}
}
// 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,
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
// 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
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" }
[features]
backtrace = []
-jemalloc = ["alloc_jemalloc"]
debug-jemalloc = ["alloc_jemalloc/debug"]
+jemalloc = ["alloc_jemalloc"]
+panic-unwind = ["panic_unwind"]
///
/// 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> {
///
/// impl Error for SuperErrorSideKick {
/// fn description(&self) -> &str {
- /// "I'm SuperError side kick!"
+ /// "I'm SuperError side kick"
/// }
/// }
///
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 {
}
/// 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 {
}
/// 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);
/// 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;
/// 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;
match hook {
Hook::Default => Box::new(default_hook),
- Hook::Custom(ptr) => {Box::from_raw(ptr)} // FIXME #30530
+ Hook::Custom(ptr) => Box::from_raw(ptr),
}
}
}
/// 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.
/// 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> {
/// 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> {
/// 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> {
# 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"]
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(
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
--- /dev/null
+-include ../tools.mk
+all: code
+krate2: krate2.rs
+ $(RUSTC) $<
+code: foo.rs krate2
+ $(RUSTC) foo.rs -Zsave-analysis || exit 0
--- /dev/null
+// 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
+}
--- /dev/null
+// 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);
+}
--- /dev/null
+// 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
+}
--- /dev/null
+// 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);
+}
--- /dev/null
+// 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");
+}
--- /dev/null
+// 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 { } }
+}
--- /dev/null
+// 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());
+}
--- /dev/null
+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
--- /dev/null
+// 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;
+}
--- /dev/null
+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
--- /dev/null
+// 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]);
+}
--- /dev/null
+print-type-size type: `SevenBytes`: 7 bytes, alignment: 1 bytes
+print-type-size field `.0`: 7 bytes
--- /dev/null
+// 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();
+}
--- /dev/null
+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
--- /dev/null
+// 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();
+}
--- /dev/null
+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
--- /dev/null
+// 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() { }
--- /dev/null
+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
--- /dev/null
+// 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;
+}
--- /dev/null
+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