if [ -n "$CFG_ANTLR4" ]
then
CFG_ANTLR4_JAR="\"$(find /usr/ -name antlr-complete.jar 2>/dev/null | head -n 1)\""
- if [ "x" -eq "x$CFG_ANTLR4_JAR" ]
+ if [ "x" = "x$CFG_ANTLR4_JAR" ]
then
CFG_ANTLR4_JAR="\"$(find ~ -name antlr-complete.jar 2>/dev/null | head -n 1)\""
fi
-Subproject commit 3bc0272cab9fdcfc2ef4df9625ec3c9d5909db79
+Subproject commit a8fc4c169fac43a5dc204d4fd56ddb1739f8c178
[**The Rust Reference**][ref]. While Rust does not have a
specification, the reference tries to describe its working in
-detail. It tends to be out of date.
+detail. It is accurate, but not necessarily complete.
[**Standard Library API Reference**][api]. Documentation for the
standard library.
#![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];
#[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>
#[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")]
pub struct Peekable<I: Iterator> {
iter: I,
- peeked: Option<I::Item>,
+ /// Remember a peeked value, even if it was None.
+ peeked: Option<Option<I::Item>>,
}
+// Peekable must remember if a None has been seen in the `.peek()` method.
+// It ensures that `.peek(); .peek();` or `.peek(); .next();` only advances the
+// underlying iterator at most once. This does not by itself make the iterator
+// fused.
#[stable(feature = "rust1", since = "1.0.0")]
impl<I: Iterator> Iterator for Peekable<I> {
type Item = I::Item;
#[inline]
fn next(&mut self) -> Option<I::Item> {
- match self.peeked {
- Some(_) => self.peeked.take(),
+ match self.peeked.take() {
+ Some(v) => v,
None => self.iter.next(),
}
}
#[inline]
#[rustc_inherit_overflow_checks]
- fn count(self) -> usize {
- (if self.peeked.is_some() { 1 } else { 0 }) + self.iter.count()
+ fn count(mut self) -> usize {
+ match self.peeked.take() {
+ Some(None) => 0,
+ Some(Some(_)) => 1 + self.iter.count(),
+ None => self.iter.count(),
+ }
}
#[inline]
fn nth(&mut self, n: usize) -> Option<I::Item> {
- match self.peeked {
- Some(_) if n == 0 => self.peeked.take(),
- Some(_) => {
- self.peeked = None;
- self.iter.nth(n-1)
- },
- None => self.iter.nth(n)
+ match self.peeked.take() {
+ // the .take() below is just to avoid "move into pattern guard"
+ Some(ref mut v) if n == 0 => v.take(),
+ Some(None) => None,
+ Some(Some(_)) => self.iter.nth(n - 1),
+ None => self.iter.nth(n),
}
}
#[inline]
- fn last(self) -> Option<I::Item> {
- self.iter.last().or(self.peeked)
+ fn last(mut self) -> Option<I::Item> {
+ let peek_opt = match self.peeked.take() {
+ Some(None) => return None,
+ Some(v) => v,
+ None => None,
+ };
+ self.iter.last().or(peek_opt)
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
+ let peek_len = match self.peeked {
+ Some(None) => return (0, Some(0)),
+ Some(Some(_)) => 1,
+ None => 0,
+ };
let (lo, hi) = self.iter.size_hint();
- if self.peeked.is_some() {
- let lo = lo.saturating_add(1);
- let hi = hi.and_then(|x| x.checked_add(1));
- (lo, hi)
- } else {
- (lo, hi)
- }
+ let lo = lo.saturating_add(peek_len);
+ let hi = hi.and_then(|x| x.checked_add(peek_len));
+ (lo, hi)
}
}
#[stable(feature = "rust1", since = "1.0.0")]
pub fn peek(&mut self) -> Option<&I::Item> {
if self.peeked.is_none() {
- self.peeked = self.iter.next();
+ self.peeked = Some(self.iter.next());
+ }
+ match self.peeked {
+ Some(Some(ref value)) => Some(value),
+ Some(None) => None,
+ _ => unreachable!(),
}
- self.peeked.as_ref()
}
}
#[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> {}
let mut it = ys.iter().peekable();
assert_eq!(it.peek(), Some(&&0));
assert_eq!(it.last(), Some(&0));
+
+ let mut it = ys.iter().peekable();
+ assert_eq!(it.next(), Some(&0));
+ assert_eq!(it.peek(), None);
+ assert_eq!(it.last(), None);
+}
+
+/// This is an iterator that follows the Iterator contract,
+/// but it is not fused. After having returned None once, it will start
+/// producing elements if .next() is called again.
+pub struct CycleIter<'a, T: 'a> {
+ index: usize,
+ data: &'a [T],
+}
+
+pub fn cycle<T>(data: &[T]) -> CycleIter<T> {
+ CycleIter {
+ index: 0,
+ data: data,
+ }
+}
+
+impl<'a, T> Iterator for CycleIter<'a, T> {
+ type Item = &'a T;
+ fn next(&mut self) -> Option<Self::Item> {
+ let elt = self.data.get(self.index);
+ self.index += 1;
+ self.index %= 1 + self.data.len();
+ elt
+ }
+}
+
+#[test]
+fn test_iterator_peekable_remember_peek_none_1() {
+ // Check that the loop using .peek() terminates
+ let data = [1, 2, 3];
+ let mut iter = cycle(&data).peekable();
+
+ let mut n = 0;
+ while let Some(_) = iter.next() {
+ let is_the_last = iter.peek().is_none();
+ assert_eq!(is_the_last, n == data.len() - 1);
+ n += 1;
+ if n > data.len() { break; }
+ }
+ assert_eq!(n, data.len());
+}
+
+#[test]
+fn test_iterator_peekable_remember_peek_none_2() {
+ let data = [0];
+ let mut iter = cycle(&data).peekable();
+ iter.next();
+ assert_eq!(iter.peek(), None);
+ assert_eq!(iter.last(), None);
+}
+
+#[test]
+fn test_iterator_peekable_remember_peek_none_3() {
+ let data = [0];
+ let mut iter = cycle(&data).peekable();
+ iter.peek();
+ assert_eq!(iter.nth(0), Some(&0));
+
+ let mut iter = cycle(&data).peekable();
+ iter.next();
+ assert_eq!(iter.peek(), None);
+ assert_eq!(iter.nth(0), None);
}
#[test]
expr_exit
}
- hir::ExprLoop(ref body, _) => {
+ hir::ExprLoop(ref body, _, _) => {
//
// [pred]
// |
self.add_unreachable_node()
}
- hir::ExprBreak(label) => {
+ hir::ExprBreak(label, ref opt_expr) => {
+ let v = self.opt_expr(opt_expr, pred);
let loop_scope = self.find_scope(expr, label.map(|l| l.node));
- let b = self.add_ast_node(expr.id, &[pred]);
+ let b = self.add_ast_node(expr.id, &[v]);
self.add_exiting_edge(expr, b,
loop_scope, loop_scope.break_index);
self.add_unreachable_node()
}
hir::ExprArray(ref elems) => {
- self.straightline(expr, pred, elems.iter().map(|e| &**e))
+ self.straightline(expr, pred, elems.iter().map(|e| &*e))
}
hir::ExprCall(ref func, ref args) => {
- self.call(expr, pred, &func, args.iter().map(|e| &**e))
+ self.call(expr, pred, &func, args.iter().map(|e| &*e))
}
hir::ExprMethodCall(.., ref args) => {
- self.call(expr, pred, &args[0], args[1..].iter().map(|e| &**e))
+ self.call(expr, pred, &args[0], args[1..].iter().map(|e| &*e))
}
hir::ExprIndex(ref l, ref r) |
}
hir::ExprTup(ref exprs) => {
- self.straightline(expr, pred, exprs.iter().map(|e| &**e))
+ self.straightline(expr, pred, exprs.iter().map(|e| &*e))
}
hir::ExprStruct(_, ref fields, ref base) => {
}
hir::ExprInlineAsm(_, ref outputs, ref inputs) => {
- let post_outputs = self.exprs(outputs.iter().map(|e| &**e), pred);
- let post_inputs = self.exprs(inputs.iter().map(|e| &**e), post_outputs);
+ let post_outputs = self.exprs(outputs.iter().map(|e| &*e), pred);
+ let post_inputs = self.exprs(inputs.iter().map(|e| &*e), post_outputs);
self.add_ast_node(expr.id, &[post_inputs])
}
visitor.visit_block(block);
walk_opt_sp_name(visitor, opt_sp_name);
}
- ExprLoop(ref block, ref opt_sp_name) => {
+ ExprLoop(ref block, ref opt_sp_name, _) => {
visitor.visit_block(block);
walk_opt_sp_name(visitor, opt_sp_name);
}
}
visitor.visit_path(path, expression.id)
}
- ExprBreak(ref opt_sp_name) | ExprAgain(ref opt_sp_name) => {
+ ExprBreak(ref opt_sp_name, ref opt_expr) => {
+ walk_opt_sp_name(visitor, opt_sp_name);
+ walk_list!(visitor, visit_expr, opt_expr);
+ }
+ ExprAgain(ref opt_sp_name) => {
walk_opt_sp_name(visitor, opt_sp_name);
}
ExprRet(ref optional_expression) => {
hir::Arm {
attrs: self.lower_attrs(&arm.attrs),
pats: arm.pats.iter().map(|x| self.lower_pat(x)).collect(),
- guard: arm.guard.as_ref().map(|ref x| self.lower_expr(x)),
- body: self.lower_expr(&arm.body),
+ guard: arm.guard.as_ref().map(|ref x| P(self.lower_expr(x))),
+ body: P(self.lower_expr(&arm.body)),
}
}
hir::TyObjectSum(self.lower_ty(ty), self.lower_bounds(bounds))
}
TyKind::Array(ref ty, ref e) => {
- hir::TyArray(self.lower_ty(ty), self.lower_expr(e))
+ hir::TyArray(self.lower_ty(ty), P(self.lower_expr(e)))
}
TyKind::Typeof(ref expr) => {
- hir::TyTypeof(self.lower_expr(expr))
+ hir::TyTypeof(P(self.lower_expr(expr)))
}
TyKind::PolyTraitRef(ref bounds) => {
hir::TyPolyTraitRef(self.lower_bounds(bounds))
name: v.node.name.name,
attrs: self.lower_attrs(&v.node.attrs),
data: self.lower_variant_data(&v.node.data),
- disr_expr: v.node.disr_expr.as_ref().map(|e| self.lower_expr(e)),
+ disr_expr: v.node.disr_expr.as_ref().map(|e| P(self.lower_expr(e))),
},
span: v.span,
}
id: l.id,
ty: l.ty.as_ref().map(|t| self.lower_ty(t)),
pat: self.lower_pat(&l.pat),
- init: l.init.as_ref().map(|e| self.lower_expr(e)),
+ init: l.init.as_ref().map(|e| P(self.lower_expr(e))),
span: l.span,
attrs: l.attrs.clone(),
})
fn lower_field(&mut self, f: &Field) -> hir::Field {
hir::Field {
name: respan(f.ident.span, f.ident.node.name),
- expr: self.lower_expr(&f.expr),
+ expr: P(self.lower_expr(&f.expr)),
span: f.span,
is_shorthand: f.is_shorthand,
}
ItemKind::Static(ref t, m, ref e) => {
hir::ItemStatic(self.lower_ty(t),
self.lower_mutability(m),
- self.lower_expr(e))
+ P(self.lower_expr(e)))
}
ItemKind::Const(ref t, ref e) => {
- hir::ItemConst(self.lower_ty(t), self.lower_expr(e))
+ hir::ItemConst(self.lower_ty(t), P(self.lower_expr(e)))
}
ItemKind::Fn(ref decl, unsafety, constness, abi, ref generics, ref body) => {
let body = self.lower_block(body);
self.lower_constness(constness),
abi,
self.lower_generics(generics),
- self.expr_block(body, ThinVec::new()))
+ P(self.expr_block(body, ThinVec::new())))
}
ItemKind::Mod(ref m) => hir::ItemMod(self.lower_mod(m)),
ItemKind::ForeignMod(ref nm) => hir::ItemForeignMod(self.lower_foreign_mod(nm)),
node: match i.node {
TraitItemKind::Const(ref ty, ref default) => {
hir::ConstTraitItem(this.lower_ty(ty),
- default.as_ref().map(|x| this.lower_expr(x)))
+ default.as_ref().map(|x| P(this.lower_expr(x))))
}
TraitItemKind::Method(ref sig, ref body) => {
hir::MethodTraitItem(this.lower_method_sig(sig),
body.as_ref().map(|x| {
let body = this.lower_block(x);
- this.expr_block(body, ThinVec::new())
+ P(this.expr_block(body, ThinVec::new()))
}))
}
TraitItemKind::Type(ref bounds, ref default) => {
defaultness: this.lower_defaultness(i.defaultness, true /* [1] */),
node: match i.node {
ImplItemKind::Const(ref ty, ref expr) => {
- hir::ImplItemKind::Const(this.lower_ty(ty), this.lower_expr(expr))
+ hir::ImplItemKind::Const(this.lower_ty(ty), P(this.lower_expr(expr)))
}
ImplItemKind::Method(ref sig, ref body) => {
let body = this.lower_block(body);
hir::ImplItemKind::Method(this.lower_method_sig(sig),
- this.expr_block(body, ThinVec::new()))
+ P(this.expr_block(body, ThinVec::new())))
}
ImplItemKind::Type(ref ty) => hir::ImplItemKind::Type(this.lower_ty(ty)),
ImplItemKind::Macro(..) => panic!("Shouldn't exist any more"),
}
})
}
- PatKind::Lit(ref e) => hir::PatKind::Lit(self.lower_expr(e)),
+ PatKind::Lit(ref e) => hir::PatKind::Lit(P(self.lower_expr(e))),
PatKind::TupleStruct(ref path, ref pats, ddpos) => {
hir::PatKind::TupleStruct(self.lower_path(path),
pats.iter().map(|x| self.lower_pat(x)).collect(), ddpos)
hir::PatKind::Ref(self.lower_pat(inner), self.lower_mutability(mutbl))
}
PatKind::Range(ref e1, ref e2) => {
- hir::PatKind::Range(self.lower_expr(e1), self.lower_expr(e2))
+ hir::PatKind::Range(P(self.lower_expr(e1)), P(self.lower_expr(e2)))
}
PatKind::Slice(ref before, ref slice, ref after) => {
hir::PatKind::Slice(before.iter().map(|x| self.lower_pat(x)).collect(),
})
}
- fn lower_expr(&mut self, e: &Expr) -> P<hir::Expr> {
- P(hir::Expr {
+ fn lower_expr(&mut self, e: &Expr) -> hir::Expr {
+ hir::Expr {
id: e.id,
node: match e.node {
// Issue #22181:
//
// But for now there are type-inference issues doing that.
ExprKind::Box(ref e) => {
- hir::ExprBox(self.lower_expr(e))
+ hir::ExprBox(P(self.lower_expr(e)))
}
// Desugar ExprBox: `in (PLACE) EXPR`
// std::intrinsics::move_val_init(raw_place, pop_unsafe!( EXPR ));
// InPlace::finalize(place)
// })
- let placer_expr = self.lower_expr(placer);
- let value_expr = self.lower_expr(value_expr);
+ let placer_expr = P(self.lower_expr(placer));
+ let value_expr = P(self.lower_expr(value_expr));
let placer_ident = self.str_to_ident("placer");
let place_ident = self.str_to_ident("place");
let make_call = |this: &mut LoweringContext, p, args| {
let path = this.std_path(e.span, p);
let path = this.expr_path(path, ThinVec::new());
- this.expr_call(e.span, path, args)
+ P(this.expr_call(e.span, path, args))
};
let mk_stmt_let = |this: &mut LoweringContext, bind, expr| {
// let placer = <placer_expr> ;
let (s1, placer_binding) = {
- let placer_expr = self.signal_block_expr(hir_vec![],
- placer_expr,
- e.span,
- hir::PopUnstableBlock,
- ThinVec::new());
+ let placer_expr = P(self.signal_block_expr(hir_vec![],
+ placer_expr,
+ e.span,
+ hir::PopUnstableBlock,
+ ThinVec::new()));
mk_stmt_let(self, placer_ident, placer_expr)
};
// let p_ptr = Place::pointer(&mut place);
let (s3, p_ptr_binding) = {
- let agent = self.expr_ident(e.span, place_ident, place_binding);
+ let agent = P(self.expr_ident(e.span, place_ident, place_binding));
let args = hir_vec![self.expr_mut_addr_of(e.span, agent)];
let call = make_call(self, &place_pointer, args);
mk_stmt_let(self, p_ptr_ident, call)
// pop_unsafe!(EXPR));
let pop_unsafe_expr = {
- let value_expr = self.signal_block_expr(hir_vec![],
- value_expr,
- e.span,
- hir::PopUnstableBlock,
- ThinVec::new());
+ let value_expr = P(self.signal_block_expr(hir_vec![],
+ value_expr,
+ e.span,
+ hir::PopUnstableBlock,
+ ThinVec::new()));
self.signal_block_expr(hir_vec![],
value_expr,
e.span,
let place = self.expr_ident(e.span, place_ident, place_binding);
let call = make_call(self, &inplace_finalize, hir_vec![place]);
- self.signal_block_expr(hir_vec![call_move_val_init],
- call,
- e.span,
- hir::PushUnsafeBlock(hir::CompilerGenerated),
- ThinVec::new())
+ P(self.signal_block_expr(hir_vec![call_move_val_init],
+ call,
+ e.span,
+ hir::PushUnsafeBlock(hir::CompilerGenerated),
+ ThinVec::new()))
};
return self.signal_block_expr(hir_vec![s1, s2, s3],
hir::ExprArray(exprs.iter().map(|x| self.lower_expr(x)).collect())
}
ExprKind::Repeat(ref expr, ref count) => {
- let expr = self.lower_expr(expr);
- let count = self.lower_expr(count);
+ let expr = P(self.lower_expr(expr));
+ let count = P(self.lower_expr(count));
hir::ExprRepeat(expr, count)
}
ExprKind::Tup(ref elts) => {
hir::ExprTup(elts.iter().map(|x| self.lower_expr(x)).collect())
}
ExprKind::Call(ref f, ref args) => {
- let f = self.lower_expr(f);
+ let f = P(self.lower_expr(f));
hir::ExprCall(f, args.iter().map(|x| self.lower_expr(x)).collect())
}
ExprKind::MethodCall(i, ref tps, ref args) => {
}
ExprKind::Binary(binop, ref lhs, ref rhs) => {
let binop = self.lower_binop(binop);
- let lhs = self.lower_expr(lhs);
- let rhs = self.lower_expr(rhs);
+ let lhs = P(self.lower_expr(lhs));
+ let rhs = P(self.lower_expr(rhs));
hir::ExprBinary(binop, lhs, rhs)
}
ExprKind::Unary(op, ref ohs) => {
let op = self.lower_unop(op);
- let ohs = self.lower_expr(ohs);
+ let ohs = P(self.lower_expr(ohs));
hir::ExprUnary(op, ohs)
}
ExprKind::Lit(ref l) => hir::ExprLit(P((**l).clone())),
ExprKind::Cast(ref expr, ref ty) => {
- let expr = self.lower_expr(expr);
+ let expr = P(self.lower_expr(expr));
hir::ExprCast(expr, self.lower_ty(ty))
}
ExprKind::Type(ref expr, ref ty) => {
- let expr = self.lower_expr(expr);
+ let expr = P(self.lower_expr(expr));
hir::ExprType(expr, self.lower_ty(ty))
}
ExprKind::AddrOf(m, ref ohs) => {
let m = self.lower_mutability(m);
- let ohs = self.lower_expr(ohs);
+ let ohs = P(self.lower_expr(ohs));
hir::ExprAddrOf(m, ohs)
}
// More complicated than you might expect because the else branch
ExprKind::IfLet(..) => {
// wrap the if-let expr in a block
let span = els.span;
- let els = self.lower_expr(els);
+ let els = P(self.lower_expr(els));
let id = self.next_id();
let blk = P(hir::Block {
stmts: hir_vec![],
rules: hir::DefaultBlock,
span: span,
});
- self.expr_block(blk, ThinVec::new())
+ P(self.expr_block(blk, ThinVec::new()))
}
- _ => self.lower_expr(els),
+ _ => P(self.lower_expr(els)),
}
});
- hir::ExprIf(self.lower_expr(cond), self.lower_block(blk), else_opt)
+ hir::ExprIf(P(self.lower_expr(cond)), self.lower_block(blk), else_opt)
}
ExprKind::While(ref cond, ref body, opt_ident) => {
- hir::ExprWhile(self.lower_expr(cond), self.lower_block(body),
+ hir::ExprWhile(P(self.lower_expr(cond)), self.lower_block(body),
self.lower_opt_sp_ident(opt_ident))
}
ExprKind::Loop(ref body, opt_ident) => {
- hir::ExprLoop(self.lower_block(body), self.lower_opt_sp_ident(opt_ident))
+ hir::ExprLoop(self.lower_block(body),
+ self.lower_opt_sp_ident(opt_ident),
+ hir::LoopSource::Loop)
}
ExprKind::Match(ref expr, ref arms) => {
- hir::ExprMatch(self.lower_expr(expr),
+ hir::ExprMatch(P(self.lower_expr(expr)),
arms.iter().map(|x| self.lower_arm(x)).collect(),
hir::MatchSource::Normal)
}
self.with_parent_def(e.id, |this| {
hir::ExprClosure(this.lower_capture_clause(capture_clause),
this.lower_fn_decl(decl),
- this.lower_expr(body),
+ P(this.lower_expr(body)),
fn_decl_span)
})
}
ExprKind::Block(ref blk) => hir::ExprBlock(self.lower_block(blk)),
ExprKind::Assign(ref el, ref er) => {
- hir::ExprAssign(self.lower_expr(el), self.lower_expr(er))
+ hir::ExprAssign(P(self.lower_expr(el)), P(self.lower_expr(er)))
}
ExprKind::AssignOp(op, ref el, ref er) => {
hir::ExprAssignOp(self.lower_binop(op),
- self.lower_expr(el),
- self.lower_expr(er))
+ P(self.lower_expr(el)),
+ P(self.lower_expr(er)))
}
ExprKind::Field(ref el, ident) => {
- hir::ExprField(self.lower_expr(el), respan(ident.span, ident.node.name))
+ hir::ExprField(P(self.lower_expr(el)), respan(ident.span, ident.node.name))
}
ExprKind::TupField(ref el, ident) => {
- hir::ExprTupField(self.lower_expr(el), ident)
+ hir::ExprTupField(P(self.lower_expr(el)), ident)
}
ExprKind::Index(ref el, ref er) => {
- hir::ExprIndex(self.lower_expr(el), self.lower_expr(er))
+ hir::ExprIndex(P(self.lower_expr(el)), P(self.lower_expr(er)))
}
ExprKind::Range(ref e1, ref e2, lims) => {
fn make_struct(this: &mut LoweringContext,
ast_expr: &Expr,
path: &[&str],
- fields: &[(&str, &P<Expr>)]) -> P<hir::Expr> {
+ fields: &[(&str, &P<Expr>)]) -> hir::Expr {
let struct_path = this.std_path(ast_expr.span,
&iter::once(&"ops").chain(path)
.map(|s| *s)
this.expr_path(struct_path, ast_expr.attrs.clone())
} else {
let fields = fields.into_iter().map(|&(s, e)| {
- let expr = this.lower_expr(&e);
- let signal_block = this.signal_block_expr(hir_vec![],
- expr,
- e.span,
- hir::PopUnstableBlock,
- ThinVec::new());
+ let expr = P(this.lower_expr(&e));
+ let signal_block = P(this.signal_block_expr(hir_vec![],
+ expr,
+ e.span,
+ hir::PopUnstableBlock,
+ ThinVec::new()));
this.field(Symbol::intern(s), signal_block, ast_expr.span)
}).collect();
let attrs = ast_expr.attrs.clone();
});
hir::ExprPath(hir_qself, self.lower_path(path))
}
- ExprKind::Break(opt_ident) => hir::ExprBreak(self.lower_opt_sp_ident(opt_ident)),
+ ExprKind::Break(opt_ident, ref opt_expr) => {
+ hir::ExprBreak(self.lower_opt_sp_ident(opt_ident),
+ opt_expr.as_ref().map(|x| P(self.lower_expr(x))))
+ }
ExprKind::Continue(opt_ident) => hir::ExprAgain(self.lower_opt_sp_ident(opt_ident)),
- ExprKind::Ret(ref e) => hir::ExprRet(e.as_ref().map(|x| self.lower_expr(x))),
+ ExprKind::Ret(ref e) => hir::ExprRet(e.as_ref().map(|x| P(self.lower_expr(x)))),
ExprKind::InlineAsm(ref asm) => {
let hir_asm = hir::InlineAsm {
inputs: asm.inputs.iter().map(|&(ref c, _)| c.clone()).collect(),
ExprKind::Struct(ref path, ref fields, ref maybe_expr) => {
hir::ExprStruct(P(self.lower_path(path)),
fields.iter().map(|x| self.lower_field(x)).collect(),
- maybe_expr.as_ref().map(|x| self.lower_expr(x)))
+ maybe_expr.as_ref().map(|x| P(self.lower_expr(x))))
}
ExprKind::Paren(ref ex) => {
- return self.lower_expr(ex).map(|mut ex| {
- // include parens in span, but only if it is a super-span.
- if e.span.contains(ex.span) {
- ex.span = e.span;
- }
- // merge attributes into the inner expression.
- let mut attrs = e.attrs.clone();
- attrs.extend::<Vec<_>>(ex.attrs.into());
- ex.attrs = attrs;
- ex
- });
+ let mut ex = self.lower_expr(ex);
+ // include parens in span, but only if it is a super-span.
+ if e.span.contains(ex.span) {
+ ex.span = e.span;
+ }
+ // merge attributes into the inner expression.
+ let mut attrs = e.attrs.clone();
+ attrs.extend::<Vec<_>>(ex.attrs.into());
+ ex.attrs = attrs;
+ return ex;
}
// Desugar ExprIfLet
// `<pat> => <body>`
let pat_arm = {
let body = self.lower_block(body);
- let body_expr = self.expr_block(body, ThinVec::new());
+ let body_expr = P(self.expr_block(body, ThinVec::new()));
let pat = self.lower_pat(pat);
self.arm(hir_vec![pat], body_expr)
};
// `[_ if <else_opt_if_cond> => <else_opt_if_body>,]`
- let mut else_opt = else_opt.as_ref().map(|e| self.lower_expr(e));
+ let mut else_opt = else_opt.as_ref().map(|e| P(self.lower_expr(e)));
let else_if_arms = {
let mut arms = vec![];
loop {
attrs: hir_vec![],
pats: hir_vec![pat_under],
guard: Some(cond),
- body: self.expr_block(then, ThinVec::new()),
+ body: P(self.expr_block(then, ThinVec::new())),
});
else_opt.map(|else_opt| (else_opt, true))
}
arms.extend(else_if_arms);
arms.push(else_arm);
- let sub_expr = self.lower_expr(sub_expr);
+ let sub_expr = P(self.lower_expr(sub_expr));
// add attributes to the outer returned expr node
return self.expr(e.span,
hir::ExprMatch(sub_expr,
// `<pat> => <body>`
let pat_arm = {
let body = self.lower_block(body);
- let body_expr = self.expr_block(body, ThinVec::new());
+ let body_expr = P(self.expr_block(body, ThinVec::new()));
let pat = self.lower_pat(pat);
self.arm(hir_vec![pat], body_expr)
};
// `match <sub_expr> { ... }`
let arms = hir_vec![pat_arm, break_arm];
- let sub_expr = self.lower_expr(sub_expr);
+ let sub_expr = P(self.lower_expr(sub_expr));
let match_expr = self.expr(e.span,
hir::ExprMatch(sub_expr,
arms,
ThinVec::new());
// `[opt_ident]: loop { ... }`
- let loop_block = self.block_expr(match_expr);
- let loop_expr = hir::ExprLoop(loop_block, self.lower_opt_sp_ident(opt_ident));
+ let loop_block = P(self.block_expr(P(match_expr)));
+ let loop_expr = hir::ExprLoop(loop_block, self.lower_opt_sp_ident(opt_ident),
+ hir::LoopSource::WhileLet);
// add attributes to the outer returned expr node
let attrs = e.attrs.clone();
- return P(hir::Expr { id: e.id, node: loop_expr, span: e.span, attrs: attrs });
+ return hir::Expr { id: e.id, node: loop_expr, span: e.span, attrs: attrs };
}
// Desugar ExprForLoop
// `match ::std::iter::Iterator::next(&mut iter) { ... }`
let match_expr = {
let next_path = self.std_path(e.span, &["iter", "Iterator", "next"]);
- let iter = self.expr_ident(e.span, iter, iter_pat.id);
+ let iter = P(self.expr_ident(e.span, iter, iter_pat.id));
let ref_mut_iter = self.expr_mut_addr_of(e.span, iter);
let next_path = self.expr_path(next_path, ThinVec::new());
- let next_expr = self.expr_call(e.span, next_path, hir_vec![ref_mut_iter]);
+ let next_expr = P(self.expr_call(e.span, next_path,
+ hir_vec![ref_mut_iter]));
let arms = hir_vec![pat_arm, break_arm];
- self.expr(e.span,
- hir::ExprMatch(next_expr, arms, hir::MatchSource::ForLoopDesugar),
- ThinVec::new())
+ P(self.expr(e.span,
+ hir::ExprMatch(next_expr, arms,
+ hir::MatchSource::ForLoopDesugar),
+ ThinVec::new()))
};
// `[opt_ident]: loop { ... }`
- let loop_block = self.block_expr(match_expr);
- let loop_expr = hir::ExprLoop(loop_block, self.lower_opt_sp_ident(opt_ident));
+ let loop_block = P(self.block_expr(match_expr));
+ let loop_expr = hir::ExprLoop(loop_block, self.lower_opt_sp_ident(opt_ident),
+ hir::LoopSource::ForLoop);
let loop_expr = P(hir::Expr {
id: e.id,
node: loop_expr,
&["iter", "IntoIterator", "into_iter"]);
let into_iter = self.expr_path(into_iter_path, ThinVec::new());
- self.expr_call(e.span, into_iter, hir_vec![head])
+ P(self.expr_call(e.span, into_iter, hir_vec![head]))
};
- let match_expr = self.expr_match(e.span,
- into_iter_expr,
- hir_vec![iter_arm],
- hir::MatchSource::ForLoopDesugar);
+ let match_expr = P(self.expr_match(e.span,
+ into_iter_expr,
+ hir_vec![iter_arm],
+ hir::MatchSource::ForLoopDesugar));
// `{ let _result = ...; _result }`
// underscore prevents an unused_variables lint if the head diverges
let (let_stmt, let_stmt_binding) =
self.stmt_let(e.span, false, result_ident, match_expr);
- let result = self.expr_ident(e.span, result_ident, let_stmt_binding);
- let block = self.block_all(e.span, hir_vec![let_stmt], Some(result));
+ let result = P(self.expr_ident(e.span, result_ident, let_stmt_binding));
+ let block = P(self.block_all(e.span, hir_vec![let_stmt], Some(result)));
// add the attributes to the outer returned expr node
return self.expr_block(block, e.attrs.clone());
}
// { Carrier::translate( { <expr> } ) }
let discr = {
// expand <expr>
- let sub_expr = self.lower_expr(sub_expr);
+ let sub_expr = P(self.lower_expr(sub_expr));
let sub_expr = self.signal_block_expr(hir_vec![],
sub_expr,
e.span,
let path = self.std_path(e.span, &["ops", "Carrier", "translate"]);
let path = self.expr_path(path, ThinVec::new());
- let call = self.expr_call(e.span, path, hir_vec![sub_expr]);
+ let call = P(self.expr_call(e.span, path, hir_vec![sub_expr]));
- self.signal_block_expr(hir_vec![],
- call,
- e.span,
- hir::PushUnstableBlock,
- ThinVec::new())
+ P(self.signal_block_expr(hir_vec![],
+ call,
+ e.span,
+ hir::PushUnstableBlock,
+ ThinVec::new()))
};
// Ok(val) => val
let ok_arm = {
let val_ident = self.str_to_ident("val");
let val_pat = self.pat_ident(e.span, val_ident);
- let val_expr = self.expr_ident(e.span, val_ident, val_pat.id);
+ let val_expr = P(self.expr_ident(e.span, val_ident, val_pat.id));
let ok_pat = self.pat_ok(e.span, val_pat);
self.arm(hir_vec![ok_pat], val_expr)
let from_err_expr = {
let path = self.std_path(e.span, &["ops", "Carrier", "from_error"]);
let from_err = self.expr_path(path, ThinVec::new());
- self.expr_call(e.span, from_err, hir_vec![from_expr])
+ P(self.expr_call(e.span, from_err, hir_vec![from_expr]))
};
- let ret_expr = self.expr(e.span,
- hir::Expr_::ExprRet(Some(from_err_expr)),
- ThinVec::new());
+ let ret_expr = P(self.expr(e.span,
+ hir::Expr_::ExprRet(Some(from_err_expr)),
+ ThinVec::new()));
let ret_stmt = self.stmt_expr(ret_expr);
- let block = self.signal_block_stmt(ret_stmt, e.span,
- hir::PushUnstableBlock, ThinVec::new());
+ let block = P(self.signal_block_stmt(ret_stmt, e.span,
+ hir::PushUnstableBlock,
+ ThinVec::new()));
let err_pat = self.pat_err(e.span, err_local);
self.arm(hir_vec![err_pat], block)
},
span: e.span,
attrs: e.attrs.clone(),
- })
+ }
}
fn lower_stmt(&mut self, s: &Stmt) -> hir::Stmt {
},
StmtKind::Expr(ref e) => {
Spanned {
- node: hir::StmtExpr(self.lower_expr(e), s.id),
+ node: hir::StmtExpr(P(self.lower_expr(e)), s.id),
span: s.span,
}
}
StmtKind::Semi(ref e) => {
Spanned {
- node: hir::StmtSemi(self.lower_expr(e), s.id),
+ node: hir::StmtSemi(P(self.lower_expr(e)), s.id),
span: s.span,
}
}
}
fn expr_break(&mut self, span: Span, attrs: ThinVec<Attribute>) -> P<hir::Expr> {
- self.expr(span, hir::ExprBreak(None), attrs)
+ P(self.expr(span, hir::ExprBreak(None, None), attrs))
}
- fn expr_call(&mut self, span: Span, e: P<hir::Expr>, args: hir::HirVec<P<hir::Expr>>)
- -> P<hir::Expr> {
+ fn expr_call(&mut self, span: Span, e: P<hir::Expr>, args: hir::HirVec<hir::Expr>)
+ -> hir::Expr {
self.expr(span, hir::ExprCall(e, args), ThinVec::new())
}
- fn expr_ident(&mut self, span: Span, id: Name, binding: NodeId) -> P<hir::Expr> {
+ fn expr_ident(&mut self, span: Span, id: Name, binding: NodeId) -> hir::Expr {
let expr_path = hir::ExprPath(None, self.path_ident(span, id));
let expr = self.expr(span, expr_path, ThinVec::new());
expr
}
- fn expr_mut_addr_of(&mut self, span: Span, e: P<hir::Expr>) -> P<hir::Expr> {
+ fn expr_mut_addr_of(&mut self, span: Span, e: P<hir::Expr>) -> hir::Expr {
self.expr(span, hir::ExprAddrOf(hir::MutMutable, e), ThinVec::new())
}
fn expr_path(&mut self, path: hir::Path, attrs: ThinVec<Attribute>) -> P<hir::Expr> {
let def = self.resolver.resolve_generated_global_path(&path, true);
- let expr = self.expr(path.span, hir::ExprPath(None, path), attrs);
+ let expr = P(self.expr(path.span, hir::ExprPath(None, path), attrs));
self.resolver.record_resolution(expr.id, def);
expr
}
arg: P<hir::Expr>,
arms: hir::HirVec<hir::Arm>,
source: hir::MatchSource)
- -> P<hir::Expr> {
+ -> hir::Expr {
self.expr(span, hir::ExprMatch(arg, arms, source), ThinVec::new())
}
- fn expr_block(&mut self, b: P<hir::Block>, attrs: ThinVec<Attribute>) -> P<hir::Expr> {
+ fn expr_block(&mut self, b: P<hir::Block>, attrs: ThinVec<Attribute>) -> hir::Expr {
self.expr(b.span, hir::ExprBlock(b), attrs)
}
- fn expr_tuple(&mut self, sp: Span, exprs: hir::HirVec<P<hir::Expr>>) -> P<hir::Expr> {
- self.expr(sp, hir::ExprTup(exprs), ThinVec::new())
+ fn expr_tuple(&mut self, sp: Span, exprs: hir::HirVec<hir::Expr>) -> P<hir::Expr> {
+ P(self.expr(sp, hir::ExprTup(exprs), ThinVec::new()))
}
fn expr_struct(&mut self,
e: Option<P<hir::Expr>>,
attrs: ThinVec<Attribute>) -> P<hir::Expr> {
let def = self.resolver.resolve_generated_global_path(&path, false);
- let expr = self.expr(sp, hir::ExprStruct(P(path), fields, e), attrs);
+ let expr = P(self.expr(sp, hir::ExprStruct(P(path), fields, e), attrs));
self.resolver.record_resolution(expr.id, def);
expr
}
- fn expr(&mut self, span: Span, node: hir::Expr_, attrs: ThinVec<Attribute>) -> P<hir::Expr> {
- P(hir::Expr {
+ fn expr(&mut self, span: Span, node: hir::Expr_, attrs: ThinVec<Attribute>) -> hir::Expr {
+ hir::Expr {
id: self.next_id(),
node: node,
span: span,
attrs: attrs,
- })
+ }
}
fn stmt_let(&mut self, sp: Span, mutbl: bool, ident: Name, ex: P<hir::Expr>)
}
}
- fn block_expr(&mut self, expr: P<hir::Expr>) -> P<hir::Block> {
+ fn block_expr(&mut self, expr: P<hir::Expr>) -> hir::Block {
self.block_all(expr.span, hir::HirVec::new(), Some(expr))
}
fn block_all(&mut self, span: Span, stmts: hir::HirVec<hir::Stmt>, expr: Option<P<hir::Expr>>)
- -> P<hir::Block> {
- P(hir::Block {
+ -> hir::Block {
+ hir::Block {
stmts: stmts,
expr: expr,
id: self.next_id(),
rules: hir::DefaultBlock,
span: span,
- })
+ }
}
fn pat_ok(&mut self, span: Span, pat: P<hir::Pat>) -> P<hir::Pat> {
span: Span,
rule: hir::BlockCheckMode,
attrs: ThinVec<Attribute>)
- -> P<hir::Expr> {
+ -> hir::Expr {
let id = self.next_id();
let block = P(hir::Block {
rules: rule,
span: Span,
rule: hir::BlockCheckMode,
attrs: ThinVec<Attribute>)
- -> P<hir::Expr> {
+ -> hir::Expr {
let id = self.next_id();
let block = P(hir::Block {
rules: rule,
/// A `box x` expression.
ExprBox(P<Expr>),
/// An array (`[a, b, c, d]`)
- ExprArray(HirVec<P<Expr>>),
+ ExprArray(HirVec<Expr>),
/// A function call
///
/// The first field resolves to the function itself (usually an `ExprPath`),
/// and the second field is the list of arguments
- ExprCall(P<Expr>, HirVec<P<Expr>>),
+ ExprCall(P<Expr>, HirVec<Expr>),
/// A method call (`x.foo::<Bar, Baz>(a, b, c, d)`)
///
/// The `Spanned<Name>` is the identifier for the method name.
///
/// Thus, `x.foo::<Bar, Baz>(a, b, c, d)` is represented as
/// `ExprMethodCall(foo, [Bar, Baz], [x, a, b, c, d])`.
- ExprMethodCall(Spanned<Name>, HirVec<P<Ty>>, HirVec<P<Expr>>),
+ ExprMethodCall(Spanned<Name>, HirVec<P<Ty>>, HirVec<Expr>),
/// A tuple (`(a, b, c ,d)`)
- ExprTup(HirVec<P<Expr>>),
+ ExprTup(HirVec<Expr>),
/// A binary operation (For example: `a + b`, `a * b`)
ExprBinary(BinOp, P<Expr>, P<Expr>),
/// A unary operation (For example: `!x`, `*x`)
/// Conditionless loop (can be exited with break, continue, or return)
///
/// `'label: loop { block }`
- ExprLoop(P<Block>, Option<Spanned<Name>>),
+ ExprLoop(P<Block>, Option<Spanned<Name>>, LoopSource),
/// A `match` block, with a source that indicates whether or not it is
/// the result of a desugaring, and if so, which kind.
ExprMatch(P<Expr>, HirVec<Arm>, MatchSource),
/// A referencing operation (`&a` or `&mut a`)
ExprAddrOf(Mutability, P<Expr>),
/// A `break`, with an optional label to break
- ExprBreak(Option<Spanned<Name>>),
+ ExprBreak(Option<Spanned<Name>>, Option<P<Expr>>),
/// A `continue`, with an optional label
ExprAgain(Option<Spanned<Name>>),
/// A `return`, with an optional value to be returned
ExprRet(Option<P<Expr>>),
/// Inline assembly (from `asm!`), with its outputs and inputs.
- ExprInlineAsm(P<InlineAsm>, HirVec<P<Expr>>, HirVec<P<Expr>>),
+ ExprInlineAsm(P<InlineAsm>, HirVec<Expr>, HirVec<Expr>),
/// A struct or struct-like variant literal expression.
///
TryDesugar,
}
+/// The loop type that yielded an ExprLoop
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
+pub enum LoopSource {
+ /// A `loop { .. }` loop
+ Loop,
+ /// A `while let _ = _ { .. }` loop
+ WhileLet,
+ /// A `for _ in _ { .. }` loop
+ ForLoop,
+}
+
+
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
pub enum CaptureClause {
CaptureByValue,
self.end()
}
- pub fn commasep_exprs(&mut self, b: Breaks, exprs: &[P<hir::Expr>]) -> io::Result<()> {
+ pub fn commasep_exprs(&mut self, b: Breaks, exprs: &[hir::Expr]) -> io::Result<()> {
self.commasep_cmnt(b, exprs, |s, e| s.print_expr(&e), |e| e.span)
}
}
- fn print_call_post(&mut self, args: &[P<hir::Expr>]) -> io::Result<()> {
+ fn print_call_post(&mut self, args: &[hir::Expr]) -> io::Result<()> {
self.popen()?;
self.commasep_exprs(Inconsistent, args)?;
self.pclose()
Ok(())
}
- fn print_expr_vec(&mut self, exprs: &[P<hir::Expr>]) -> io::Result<()> {
+ fn print_expr_vec(&mut self, exprs: &[hir::Expr]) -> io::Result<()> {
self.ibox(indent_unit)?;
word(&mut self.s, "[")?;
- self.commasep_exprs(Inconsistent, &exprs[..])?;
+ self.commasep_exprs(Inconsistent, exprs)?;
word(&mut self.s, "]")?;
self.end()
}
Ok(())
}
- fn print_expr_tup(&mut self, exprs: &[P<hir::Expr>]) -> io::Result<()> {
+ fn print_expr_tup(&mut self, exprs: &[hir::Expr]) -> io::Result<()> {
self.popen()?;
- self.commasep_exprs(Inconsistent, &exprs[..])?;
+ self.commasep_exprs(Inconsistent, exprs)?;
if exprs.len() == 1 {
word(&mut self.s, ",")?;
}
self.pclose()
}
- fn print_expr_call(&mut self, func: &hir::Expr, args: &[P<hir::Expr>]) -> io::Result<()> {
+ fn print_expr_call(&mut self, func: &hir::Expr, args: &[hir::Expr]) -> io::Result<()> {
self.print_expr_maybe_paren(func)?;
self.print_call_post(args)
}
fn print_expr_method_call(&mut self,
name: Spanned<ast::Name>,
tys: &[P<hir::Ty>],
- args: &[P<hir::Expr>])
+ args: &[hir::Expr])
-> io::Result<()> {
let base_args = &args[1..];
self.print_expr(&args[0])?;
self.print_expr(expr)?;
}
hir::ExprArray(ref exprs) => {
- self.print_expr_vec(&exprs[..])?;
+ self.print_expr_vec(exprs)?;
}
hir::ExprRepeat(ref element, ref count) => {
self.print_expr_repeat(&element, &count)?;
self.print_expr_struct(path, &fields[..], wth)?;
}
hir::ExprTup(ref exprs) => {
- self.print_expr_tup(&exprs[..])?;
+ self.print_expr_tup(exprs)?;
}
hir::ExprCall(ref func, ref args) => {
- self.print_expr_call(&func, &args[..])?;
+ self.print_expr_call(&func, args)?;
}
hir::ExprMethodCall(name, ref tys, ref args) => {
- self.print_expr_method_call(name, &tys[..], &args[..])?;
+ self.print_expr_method_call(name, &tys[..], args)?;
}
hir::ExprBinary(op, ref lhs, ref rhs) => {
self.print_expr_binary(op, &lhs, &rhs)?;
space(&mut self.s)?;
self.print_block(&blk)?;
}
- hir::ExprLoop(ref blk, opt_sp_name) => {
+ hir::ExprLoop(ref blk, opt_sp_name, _) => {
if let Some(sp_name) = opt_sp_name {
self.print_name(sp_name.node)?;
self.word_space(":")?;
hir::ExprPath(Some(ref qself), ref path) => {
self.print_qpath(path, qself, true)?
}
- hir::ExprBreak(opt_name) => {
+ hir::ExprBreak(opt_name, ref opt_expr) => {
word(&mut self.s, "break")?;
space(&mut self.s)?;
if let Some(name) = opt_name {
self.print_name(name.node)?;
space(&mut self.s)?;
}
+ if let Some(ref expr) = *opt_expr {
+ self.print_expr(expr)?;
+ space(&mut self.s)?;
+ }
}
hir::ExprAgain(opt_name) => {
word(&mut self.s, "continue")?;
declare_lint! {
pub HR_LIFETIME_IN_ASSOC_TYPE,
- Warn,
+ Deny,
"binding for associated type references higher-ranked lifetime \
that does not appear in the trait input types"
}
"detects extra requirements in impls that were erroneously allowed"
}
+declare_lint! {
+ pub LEGACY_DIRECTORY_OWNERSHIP,
+ Warn,
+ "non-inline, non-`#[path]` modules (e.g. `mod foo;`) were erroneously allowed in some files \
+ not named `mod.rs`"
+}
+
/// Does nothing as a lint pass, but registers some `Lint`s
/// which are used by other parts of the compiler.
#[derive(Copy, Clone)]
LIFETIME_UNDERSCORE,
SAFE_EXTERN_STATICS,
PATTERNS_IN_FNS_WITHOUT_BODY,
- EXTRA_REQUIREMENT_IN_IMPL
+ EXTRA_REQUIREMENT_IN_IMPL,
+ LEGACY_DIRECTORY_OWNERSHIP
)
}
}
pub crate_hash: Svh,
}
-// Where a crate came from on the local filesystem. One of these two options
+// Where a crate came from on the local filesystem. One of these three options
// must be non-None.
#[derive(PartialEq, Clone, Debug)]
pub struct CrateSource {
pub dylib: Option<(PathBuf, PathKind)>,
pub rlib: Option<(PathBuf, PathKind)>,
+ pub rmeta: Option<(PathBuf, PathKind)>,
}
#[derive(RustcEncodable, RustcDecodable, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Debug)]
Explicit,
}
+#[derive(PartialEq, Clone, Debug)]
+pub enum LibSource {
+ Some(PathBuf),
+ MetadataOnly,
+ None,
+}
+
+impl LibSource {
+ pub fn is_some(&self) -> bool {
+ if let LibSource::Some(_) = *self {
+ true
+ } else {
+ false
+ }
+ }
+
+ pub fn option(&self) -> Option<PathBuf> {
+ match *self {
+ LibSource::Some(ref p) => Some(p.clone()),
+ LibSource::MetadataOnly | LibSource::None => None,
+ }
+ }
+}
+
#[derive(Copy, Debug, PartialEq, Clone, RustcEncodable, RustcDecodable)]
pub enum LinkagePreference {
RequireDynamic,
// utility functions
fn metadata_filename(&self) -> &str;
fn metadata_section_name(&self, target: &Target) -> &str;
- fn used_crates(&self, prefer: LinkagePreference) -> Vec<(CrateNum, Option<PathBuf>)>;
+ fn used_crates(&self, prefer: LinkagePreference) -> Vec<(CrateNum, LibSource)>;
fn used_crate_source(&self, cnum: CrateNum) -> CrateSource;
fn extern_mod_stmt_cnum(&self, emod_id: ast::NodeId) -> Option<CrateNum>;
fn encode_metadata<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
// utility functions
fn metadata_filename(&self) -> &str { bug!("metadata_filename") }
fn metadata_section_name(&self, target: &Target) -> &str { bug!("metadata_section_name") }
- fn used_crates(&self, prefer: LinkagePreference) -> Vec<(CrateNum, Option<PathBuf>)>
+ fn used_crates(&self, prefer: LinkagePreference) -> Vec<(CrateNum, LibSource)>
{ vec![] }
fn used_crate_source(&self, cnum: CrateNum) -> CrateSource { bug!("used_crate_source") }
fn extern_mod_stmt_cnum(&self, emod_id: ast::NodeId) -> Option<CrateNum> { None }
// No linkage happens with rlibs, we just needed the metadata (which we
// got long ago), so don't bother with anything.
- config::CrateTypeRlib => return Vec::new(),
+ config::CrateTypeRlib | config::CrateTypeMetadata => return Vec::new(),
// Staticlibs and cdylibs must have all static dependencies. If any fail
// to be found, we generate some nice pretty errors.
if src.dylib.is_none() &&
!formats.contains_key(&cnum) &&
sess.cstore.dep_kind(cnum) == DepKind::Explicit {
- assert!(src.rlib.is_some());
+ assert!(src.rlib.is_some() || src.rmeta.is_some());
info!("adding staticlib: {}", sess.cstore.crate_name(cnum));
add_library(sess, cnum, RequireStatic, &mut formats);
ret[cnum.as_usize() - 1] = Linkage::Static;
self.delegate.consume(consume_id, consume_span, cmt, mode);
}
- fn consume_exprs(&mut self, exprs: &[P<hir::Expr>]) {
+ fn consume_exprs(&mut self, exprs: &[hir::Expr]) {
for expr in exprs {
self.consume_expr(&expr);
}
self.consume_exprs(inputs);
}
- hir::ExprBreak(..) |
hir::ExprAgain(..) |
hir::ExprLit(..) => {}
- hir::ExprLoop(ref blk, _) => {
+ hir::ExprLoop(ref blk, _, _) => {
self.walk_block(&blk);
}
self.walk_block(&blk);
}
- hir::ExprRet(ref opt_expr) => {
+ hir::ExprBreak(_, ref opt_expr) | hir::ExprRet(ref opt_expr) => {
if let Some(ref expr) = *opt_expr {
self.consume_expr(&expr);
}
use std::io;
use std::rc::Rc;
use syntax::ast::{self, NodeId};
-use syntax::ptr::P;
use syntax::symbol::keywords;
use syntax_pos::Span;
hir::ExprIndex(..) | hir::ExprField(..) | hir::ExprTupField(..) |
hir::ExprArray(..) | hir::ExprCall(..) | hir::ExprMethodCall(..) |
hir::ExprTup(..) | hir::ExprBinary(..) | hir::ExprAddrOf(..) |
- hir::ExprCast(..) | hir::ExprUnary(..) | hir::ExprBreak(_) |
+ hir::ExprCast(..) | hir::ExprUnary(..) | hir::ExprBreak(..) |
hir::ExprAgain(_) | hir::ExprLit(_) | hir::ExprRet(..) |
hir::ExprBlock(..) | hir::ExprAssign(..) | hir::ExprAssignOp(..) |
hir::ExprStruct(..) | hir::ExprRepeat(..) |
self.define_bindings_in_pat(&local.pat, succ)
}
- fn propagate_through_exprs(&mut self, exprs: &[P<Expr>], succ: LiveNode)
+ fn propagate_through_exprs(&mut self, exprs: &[Expr], succ: LiveNode)
-> LiveNode {
exprs.iter().rev().fold(succ, |succ, expr| {
self.propagate_through_expr(&expr, succ)
// Note that labels have been resolved, so we don't need to look
// at the label ident
- hir::ExprLoop(ref blk, _) => {
+ hir::ExprLoop(ref blk, _, _) => {
self.propagate_through_loop(expr, LoopLoop, &blk, succ)
}
self.propagate_through_opt_expr(o_e.as_ref().map(|e| &**e), exit_ln)
}
- hir::ExprBreak(opt_label) => {
+ hir::ExprBreak(opt_label, ref opt_expr) => {
// Find which label this break jumps to
let sc = self.find_loop_scope(opt_label.map(|l| l.node), expr.id, expr.span);
// look it up in the break loop nodes table
match self.break_ln.get(&sc) {
- Some(&b) => b,
+ Some(&b) => self.propagate_through_opt_expr(opt_expr.as_ref().map(|e| &**e), b),
None => span_bug!(expr.span, "break to unknown label")
}
}
match self.cont_ln.get(&sc) {
Some(&b) => b,
- None => span_bug!(expr.span, "loop to unknown label")
+ None => span_bug!(expr.span, "continue to unknown label")
}
}
// Uninteresting cases: just propagate in rev exec order
hir::ExprArray(ref exprs) => {
- self.propagate_through_exprs(&exprs[..], succ)
+ self.propagate_through_exprs(exprs, succ)
}
hir::ExprRepeat(ref element, ref count) => {
} else {
succ
};
- let succ = self.propagate_through_exprs(&args[..], succ);
+ let succ = self.propagate_through_exprs(args, succ);
self.propagate_through_expr(&f, succ)
}
} else {
succ
};
- self.propagate_through_exprs(&args[..], succ)
+ self.propagate_through_exprs(args, succ)
}
hir::ExprTup(ref exprs) => {
- self.propagate_through_exprs(&exprs[..], succ)
+ self.propagate_through_exprs(exprs, succ)
}
hir::ExprBinary(op, ref l, ref r) if op.node.is_lazy() => {
fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> ReachableContext<'a, 'tcx> {
let any_library = tcx.sess.crate_types.borrow().iter().any(|ty| {
*ty == config::CrateTypeRlib || *ty == config::CrateTypeDylib ||
- *ty == config::CrateTypeProcMacro
+ *ty == config::CrateTypeProcMacro || *ty == config::CrateTypeMetadata
});
ReachableContext {
tcx: tcx,
terminating(then.id);
}
- hir::ExprLoop(ref body, _) => {
+ hir::ExprLoop(ref body, _, _) => {
terminating(body.id);
}
fn expression_label(ex: &hir::Expr) -> Option<(ast::Name, Span)> {
match ex.node {
hir::ExprWhile(.., Some(label)) |
- hir::ExprLoop(_, Some(label)) => Some((label.node, label.span)),
+ hir::ExprLoop(_, Some(label), _) => Some((label.node, label.span)),
_ => None,
}
}
config::CrateTypeCdylib |
config::CrateTypeExecutable |
config::CrateTypeStaticlib => true,
- config::CrateTypeRlib => false,
+ config::CrateTypeRlib |
+ config::CrateTypeMetadata => false,
}
});
if !needs_check {
--- /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);
+ }
+ }
+ }
+}
DepInfo,
}
-#[derive(Clone, Copy, Debug, PartialEq, Eq)]
-pub enum ErrorOutputType {
- HumanReadable(ColorConfig),
- Json,
-}
-
-impl Default for ErrorOutputType {
- fn default() -> ErrorOutputType {
- ErrorOutputType::HumanReadable(ColorConfig::Auto)
- }
-}
-
impl OutputType {
fn is_compatible_with_codegen_units_and_single_output_file(&self) -> bool {
match *self {
}
}
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub enum ErrorOutputType {
+ HumanReadable(ColorConfig),
+ Json,
+}
+
+impl Default for ErrorOutputType {
+ fn default() -> ErrorOutputType {
+ ErrorOutputType::HumanReadable(ColorConfig::Auto)
+ }
+}
+
// Use tree-based collections to cheaply get a deterministic Hash implementation.
// DO NOT switch BTreeMap out for an unsorted container type! That would break
// dependency tracking for commandline arguments.
CrateTypeStaticlib,
CrateTypeCdylib,
CrateTypeProcMacro,
+ CrateTypeMetadata,
}
#[derive(Clone, Hash)]
"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],
assumed.", "[KIND=]NAME"),
opt::multi_s("", "crate-type", "Comma separated list of types of crates
for the compiler to emit",
- "[bin|lib|rlib|dylib|cdylib|staticlib]"),
+ "[bin|lib|rlib|dylib|cdylib|staticlib|metadata]"),
opt::opt_s("", "crate-name", "Specify the name of the crate being built",
"NAME"),
opt::multi_s("", "emit", "Comma separated list of types of output for \
"cdylib" => CrateTypeCdylib,
"bin" => CrateTypeExecutable,
"proc-macro" => CrateTypeProcMacro,
+ "metadata" => CrateTypeMetadata,
_ => {
return Err(format!("unknown crate type: `{}`",
part));
CrateTypeStaticlib => "staticlib".fmt(f),
CrateTypeCdylib => "cdylib".fmt(f),
CrateTypeProcMacro => "proc-macro".fmt(f),
+ CrateTypeMetadata => "metadata".fmt(f),
}
}
}
// 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;
use syntax_pos::{DUMMY_SP, Span};
use rustc_const_math::ConstInt;
+use rustc_data_structures::accumulate_vec::IntoIter as AccIntoIter;
use hir;
use hir::itemlikevisit::ItemLikeVisitor;
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)]
/// Iterator that walks the immediate children of `self`. Hence
/// `Foo<Bar<i32>, u32>` yields the sequence `[Bar<i32>, u32]`
/// (but not `i32`, like `walk`).
- pub fn walk_shallow(&'tcx self) -> IntoIter<Ty<'tcx>> {
+ pub fn walk_shallow(&'tcx self) -> AccIntoIter<walk::TypeWalkerArray<'tcx>> {
walk::walk_shallow(self)
}
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,
}
}
//! WARNING: this does not keep track of the region depth.
use ty::{self, Ty};
-use std::iter::Iterator;
-use std::vec::IntoIter;
+use rustc_data_structures::small_vec::SmallVec;
+use rustc_data_structures::accumulate_vec::IntoIter as AccIntoIter;
+
+// The TypeWalker's stack is hot enough that it's worth going to some effort to
+// avoid heap allocations.
+pub type TypeWalkerArray<'tcx> = [Ty<'tcx>; 8];
+pub type TypeWalkerStack<'tcx> = SmallVec<TypeWalkerArray<'tcx>>;
pub struct TypeWalker<'tcx> {
- stack: Vec<Ty<'tcx>>,
+ stack: TypeWalkerStack<'tcx>,
last_subtree: usize,
}
impl<'tcx> TypeWalker<'tcx> {
pub fn new(ty: Ty<'tcx>) -> TypeWalker<'tcx> {
- TypeWalker { stack: vec![ty], last_subtree: 1, }
+ TypeWalker { stack: SmallVec::one(ty), last_subtree: 1, }
}
/// Skips the subtree of types corresponding to the last type
}
}
-pub fn walk_shallow<'tcx>(ty: Ty<'tcx>) -> IntoIter<Ty<'tcx>> {
- let mut stack = vec![];
+pub fn walk_shallow<'tcx>(ty: Ty<'tcx>) -> AccIntoIter<TypeWalkerArray<'tcx>> {
+ let mut stack = SmallVec::new();
push_subtypes(&mut stack, ty);
stack.into_iter()
}
// known to be significant to any code, but it seems like the
// natural order one would expect (basically, the order of the
// types as they are written).
-fn push_subtypes<'tcx>(stack: &mut Vec<Ty<'tcx>>, parent_ty: Ty<'tcx>) {
+fn push_subtypes<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent_ty: Ty<'tcx>) {
match parent_ty.sty {
ty::TyBool | ty::TyChar | ty::TyInt(_) | ty::TyUint(_) | ty::TyFloat(_) |
ty::TyStr | ty::TyInfer(_) | ty::TyParam(_) | ty::TyNever | ty::TyError => {
}
}
-fn push_sig_subtypes<'tcx>(stack: &mut Vec<Ty<'tcx>>, sig: &ty::PolyFnSig<'tcx>) {
+fn push_sig_subtypes<'tcx>(stack: &mut TypeWalkerStack<'tcx>, sig: &ty::PolyFnSig<'tcx>) {
stack.push(sig.0.output);
stack.extend(sig.0.inputs.iter().cloned().rev());
}
use std::path::Path;
use std::time::{Duration, Instant};
-use hir;
-use hir::intravisit;
-use hir::intravisit::Visitor;
-
// The name of the associated type for `Fn` return types
pub const FN_OUTPUT_NAME: &'static str = "Output";
Indenter { _cannot_construct_outside_of_this_module: () }
}
-struct LoopQueryVisitor<P> where P: FnMut(&hir::Expr_) -> bool {
- p: P,
- flag: bool,
-}
-
-impl<'v, P> Visitor<'v> for LoopQueryVisitor<P> where P: FnMut(&hir::Expr_) -> bool {
- fn visit_expr(&mut self, e: &hir::Expr) {
- self.flag |= (self.p)(&e.node);
- match e.node {
- // Skip inner loops, since a break in the inner loop isn't a
- // break inside the outer loop
- hir::ExprLoop(..) | hir::ExprWhile(..) => {}
- _ => intravisit::walk_expr(self, e)
- }
- }
-}
-
-// Takes a predicate p, returns true iff p is true for any subexpressions
-// of b -- skipping any inner loops (loop, while, loop_body)
-pub fn loop_query<P>(b: &hir::Block, p: P) -> bool where P: FnMut(&hir::Expr_) -> bool {
- let mut v = LoopQueryVisitor {
- p: p,
- flag: false,
- };
- intravisit::walk_block(&mut v, b);
- return v.flag;
-}
-
-struct BlockQueryVisitor<P> where P: FnMut(&hir::Expr) -> bool {
- p: P,
- flag: bool,
-}
-
-impl<'v, P> Visitor<'v> for BlockQueryVisitor<P> where P: FnMut(&hir::Expr) -> bool {
- fn visit_expr(&mut self, e: &hir::Expr) {
- self.flag |= (self.p)(e);
- intravisit::walk_expr(self, e)
- }
-}
-
-// Takes a predicate p, returns true iff p is true for any subexpressions
-// of b -- skipping any inner loops (loop, while, loop_body)
-pub fn block_query<P>(b: &hir::Block, p: P) -> bool where P: FnMut(&hir::Expr) -> bool {
- let mut v = BlockQueryVisitor {
- p: p,
- flag: false,
- };
- intravisit::walk_block(&mut v, &b);
- return v.flag;
-}
-
pub trait MemoizationMap {
type Key: Clone;
type Value: Clone;
// 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 {} \
_ => bug!()
};
let pats = args.iter()
- .map(|expr| const_expr_to_pat(tcx, &**expr, pat_id, span))
+ .map(|expr| const_expr_to_pat(tcx, &*expr, pat_id, span))
.collect::<Result<_, _>>()?;
PatKind::TupleStruct(path, pats, None)
}
self.set_len(len + 1);
}
}
+
+ pub fn truncate(&mut self, len: usize) {
+ unsafe {
+ while len < self.len() {
+ // Decrement len before the drop_in_place(), so a panic on Drop
+ // doesn't re-drop the just-failed value.
+ let newlen = self.len() - 1;
+ self.set_len(newlen);
+ ::std::ptr::drop_in_place(self.get_unchecked_mut(newlen));
+ }
+ }
+ }
}
impl<A: Array> Deref for SmallVec<A> {
})??
};
+ 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,
time(time_passes,
"loop checking",
- || loops::check_crate(sess, &hir_map));
+ || loops::check_crate(sess, &resolutions.def_map, &hir_map));
time(time_passes,
"static item recursion checking",
Some(ref n) if *n == "rlib" => {
Some(config::CrateTypeRlib)
}
+ Some(ref n) if *n == "metadata" => {
+ Some(config::CrateTypeMetadata)
+ }
Some(ref n) if *n == "dylib" => {
Some(config::CrateTypeDylib)
}
ExprType(..) => (SawExprType, false),
ExprIf(..) => (SawExprIf, false),
ExprWhile(..) => (SawExprWhile, false),
- ExprLoop(_, id) => (SawExprLoop(id.map(|id| id.node.as_str())), false),
+ ExprLoop(_, id, _) => (SawExprLoop(id.map(|id| id.node.as_str())), false),
ExprMatch(..) => (SawExprMatch, false),
ExprClosure(cc, _, _, _) => (SawExprClosure(cc), false),
ExprBlock(..) => (SawExprBlock, false),
ExprIndex(..) => (SawExprIndex, true),
ExprPath(ref qself, _) => (SawExprPath(qself.as_ref().map(|q| q.position)), false),
ExprAddrOf(m, _) => (SawExprAddrOf(m), false),
- ExprBreak(id) => (SawExprBreak(id.map(|id| id.node.as_str())), false),
+ ExprBreak(id, _) => (SawExprBreak(id.map(|id| id.node.as_str())), false),
ExprAgain(id) => (SawExprAgain(id.map(|id| id.node.as_str())), false),
ExprRet(..) => (SawExprRet, false),
ExprInlineAsm(ref a,..) => (SawExprInlineAsm(a), false),
id: LintId::of(EXTRA_REQUIREMENT_IN_IMPL),
reference: "issue #37166 <https://github.com/rust-lang/rust/issues/37166>",
},
+ FutureIncompatibleInfo {
+ id: LintId::of(LEGACY_DIRECTORY_OWNERSHIP),
+ reference: "issue #37872 <https://github.com/rust-lang/rust/issues/37872>",
+ },
]);
// Register renamed and removed lints
pub struct Library {
pub dylib: Option<(PathBuf, PathKind)>,
pub rlib: Option<(PathBuf, PathKind)>,
+ pub rmeta: Option<(PathBuf, PathKind)>,
pub metadata: MetadataBlob,
}
info!(" cnum: {}", data.cnum);
info!(" hash: {}", data.hash());
info!(" reqd: {:?}", data.dep_kind.get());
- let CrateSource { dylib, rlib } = data.source.clone();
+ let CrateSource { dylib, rlib, rmeta } = data.source.clone();
dylib.map(|dl| info!(" dylib: {}", dl.0.display()));
rlib.map(|rl| info!(" rlib: {}", rl.0.display()));
- })
+ rmeta.map(|rl| info!(" rmeta: {}", rl.0.display()));
+ });
}
#[derive(Debug)]
ident: ident.to_string(),
dylib: lib.dylib.clone().map(|p| p.0),
rlib: lib.rlib.clone().map(|p| p.0),
+ rmeta: lib.rmeta.clone().map(|p| p.0),
})
} else {
None
// Maintain a reference to the top most crate.
let root = if root.is_some() { root } else { &crate_paths };
- let Library { dylib, rlib, metadata } = lib;
+ let Library { dylib, rlib, rmeta, metadata } = lib;
let cnum_map = self.resolve_crate_deps(root, &crate_root, &metadata, cnum, span, dep_kind);
source: cstore::CrateSource {
dylib: dylib,
rlib: rlib,
+ rmeta: rmeta,
},
});
config::CrateTypeProcMacro |
config::CrateTypeCdylib |
config::CrateTypeStaticlib => need_lib_alloc = true,
- config::CrateTypeRlib => {}
+ config::CrateTypeRlib |
+ config::CrateTypeMetadata => {}
}
}
if !need_lib_alloc && !need_exe_alloc { return }
use std::cell::{RefCell, Cell};
use std::rc::Rc;
-use std::path::PathBuf;
use flate::Bytes;
use syntax::{ast, attr};
use syntax::ext::base::SyntaxExtension;
pub use rustc::middle::cstore::{NativeLibrary, LinkagePreference};
pub use rustc::middle::cstore::{NativeStatic, NativeFramework, NativeUnknown};
-pub use rustc::middle::cstore::{CrateSource, LinkMeta};
+pub use rustc::middle::cstore::{CrateSource, LinkMeta, LibSource};
// A map from external crate numbers (as decoded from some crate file) to
// local crate numbers (as generated during this session). Each external
pub enum MetadataBlob {
Inflated(Bytes),
Archive(locator::ArchiveMetadata),
+ Raw(Vec<u8>),
}
/// Holds information about a syntax_pos::FileMap imported from another crate.
// positions.
pub fn do_get_used_crates(&self,
prefer: LinkagePreference)
- -> Vec<(CrateNum, Option<PathBuf>)> {
+ -> Vec<(CrateNum, LibSource)> {
let mut ordering = Vec::new();
for (&num, _) in self.metas.borrow().iter() {
self.push_dependencies_in_postorder(&mut ordering, num);
LinkagePreference::RequireDynamic => data.source.dylib.clone().map(|p| p.0),
LinkagePreference::RequireStatic => data.source.rlib.clone().map(|p| p.0),
};
+ let path = match path {
+ Some(p) => LibSource::Some(p),
+ None => {
+ if data.source.rmeta.is_some() {
+ LibSource::MetadataOnly
+ } else {
+ LibSource::None
+ }
+ }
+ };
Some((cnum, path))
})
.collect::<Vec<_>>();
use locator;
use schema;
-use rustc::middle::cstore::{InlinedItem, CrateStore, CrateSource, DepKind, ExternCrate};
+use rustc::middle::cstore::{InlinedItem, CrateStore, CrateSource, LibSource, DepKind, ExternCrate};
use rustc::middle::cstore::{NativeLibrary, LinkMeta, LinkagePreference, LoadedMacro};
use rustc::hir::def::{self, Def};
use rustc::middle::lang_items;
use rustc::util::nodemap::{NodeSet, DefIdMap};
use rustc_back::PanicStrategy;
-use std::path::PathBuf;
use syntax::ast;
use syntax::attr;
use syntax::parse::new_parser_from_source_str;
locator::meta_section_name(target)
}
- fn used_crates(&self, prefer: LinkagePreference) -> Vec<(CrateNum, Option<PathBuf>)>
+ fn used_crates(&self, prefer: LinkagePreference) -> Vec<(CrateNum, LibSource)>
{
self.do_get_used_crates(prefer)
}
impl<'a, 'tcx> Metadata<'a, 'tcx> for &'a MetadataBlob {
fn raw_bytes(self) -> &'a [u8] {
match *self {
- MetadataBlob::Inflated(ref vec) => &vec[..],
+ MetadataBlob::Inflated(ref vec) => vec,
MetadataBlob::Archive(ref ar) => ar.as_slice(),
+ MetadataBlob::Raw(ref vec) => vec,
}
}
}
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.
//! is a platform-defined dynamic library. Each library has a metadata somewhere
//! inside of it.
//!
+//! A third kind of dependency is an rmeta file. These are metadata files and do
+//! not contain any code, etc. To a first approximation, these are treated in the
+//! same way as rlibs. Where there is both an rlib and an rmeta file, the rlib
+//! gets priority (even if the rmeta file is newer). An rmeta file is only
+//! useful for checking a downstream crate, attempting to link one will cause an
+//! error.
+//!
//! When translating a crate name to a crate on the filesystem, we all of a
//! sudden need to take into account both rlibs and dylibs! Linkage later on may
//! use either one of these files, as each has their pros/cons. The job of crate
use std::cmp;
use std::fmt;
-use std::fs;
-use std::io;
+use std::fs::{self, File};
+use std::io::{self, Read};
use std::path::{Path, PathBuf};
use std::ptr;
use std::slice;
pub ident: String,
pub dylib: Option<PathBuf>,
pub rlib: Option<PathBuf>,
+ pub rmeta: Option<PathBuf>,
}
pub const METADATA_FILENAME: &'static str = "rust.metadata.bin";
#[derive(Copy, Clone, PartialEq)]
enum CrateFlavor {
Rlib,
+ Rmeta,
Dylib,
}
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(match *self {
CrateFlavor::Rlib => "rlib",
+ CrateFlavor::Rmeta => "rmeta",
CrateFlavor::Dylib => "dylib",
})
}
impl CratePaths {
fn paths(&self) -> Vec<PathBuf> {
- match (&self.dylib, &self.rlib) {
- (&None, &None) => vec![],
- (&Some(ref p), &None) |
- (&None, &Some(ref p)) => vec![p.clone()],
- (&Some(ref p1), &Some(ref p2)) => vec![p1.clone(), p2.clone()],
- }
+ self.dylib.iter().chain(self.rlib.iter()).chain(self.rmeta.iter()).cloned().collect()
}
}
None => return FileDoesntMatch,
Some(file) => file,
};
- let (hash, rlib) = if file.starts_with(&rlib_prefix[..]) && file.ends_with(".rlib") {
- (&file[(rlib_prefix.len())..(file.len() - ".rlib".len())], true)
- } else if file.starts_with(&dylib_prefix) &&
- file.ends_with(&dypair.1) {
- (&file[(dylib_prefix.len())..(file.len() - dypair.1.len())], false)
- } else {
- if file.starts_with(&staticlib_prefix[..]) && file.ends_with(&staticpair.1) {
- staticlibs.push(CrateMismatch {
- path: path.to_path_buf(),
- got: "static".to_string(),
- });
- }
- return FileDoesntMatch;
- };
+ let (hash, found_kind) =
+ if file.starts_with(&rlib_prefix[..]) && file.ends_with(".rlib") {
+ (&file[(rlib_prefix.len())..(file.len() - ".rlib".len())], CrateFlavor::Rlib)
+ } else if file.starts_with(&rlib_prefix[..]) && file.ends_with(".rmeta") {
+ (&file[(rlib_prefix.len())..(file.len() - ".rmeta".len())], CrateFlavor::Rmeta)
+ } else if file.starts_with(&dylib_prefix) &&
+ file.ends_with(&dypair.1) {
+ (&file[(dylib_prefix.len())..(file.len() - dypair.1.len())], CrateFlavor::Dylib)
+ } else {
+ if file.starts_with(&staticlib_prefix[..]) && file.ends_with(&staticpair.1) {
+ staticlibs.push(CrateMismatch {
+ path: path.to_path_buf(),
+ got: "static".to_string(),
+ });
+ }
+ return FileDoesntMatch;
+ };
info!("lib candidate: {}", path.display());
let hash_str = hash.to_string();
let slot = candidates.entry(hash_str)
- .or_insert_with(|| (FxHashMap(), FxHashMap()));
- let (ref mut rlibs, ref mut dylibs) = *slot;
+ .or_insert_with(|| (FxHashMap(), FxHashMap(), FxHashMap()));
+ let (ref mut rlibs, ref mut rmetas, ref mut dylibs) = *slot;
fs::canonicalize(path)
.map(|p| {
- if rlib {
- rlibs.insert(p, kind);
- } else {
- dylibs.insert(p, kind);
+ match found_kind {
+ CrateFlavor::Rlib => { rlibs.insert(p, kind); }
+ CrateFlavor::Rmeta => { rmetas.insert(p, kind); }
+ CrateFlavor::Dylib => { dylibs.insert(p, kind); }
}
FileMatches
})
// libraries corresponds to the crate id and hash criteria that this
// search is being performed for.
let mut libraries = FxHashMap();
- for (_hash, (rlibs, dylibs)) in candidates {
+ for (_hash, (rlibs, rmetas, dylibs)) in candidates {
let mut slot = None;
let rlib = self.extract_one(rlibs, CrateFlavor::Rlib, &mut slot);
+ let rmeta = self.extract_one(rmetas, CrateFlavor::Rmeta, &mut slot);
let dylib = self.extract_one(dylibs, CrateFlavor::Dylib, &mut slot);
if let Some((h, m)) = slot {
libraries.insert(h,
Library {
dylib: dylib,
rlib: rlib,
+ rmeta: rmeta,
metadata: m,
});
}
}
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");
let sess = self.sess;
let dylibname = self.dylibname();
let mut rlibs = FxHashMap();
+ let mut rmetas = FxHashMap();
let mut dylibs = FxHashMap();
{
let locs = locs.map(|l| PathBuf::from(l)).filter(|loc| {
return false;
}
};
- if file.starts_with("lib") && file.ends_with(".rlib") {
+ if file.starts_with("lib") &&
+ (file.ends_with(".rlib") || file.ends_with(".rmeta")) {
return true;
} else {
let (ref prefix, ref suffix) = dylibname;
for loc in locs {
if loc.file_name().unwrap().to_str().unwrap().ends_with(".rlib") {
rlibs.insert(fs::canonicalize(&loc).unwrap(), PathKind::ExternFlag);
+ } else if loc.file_name().unwrap().to_str().unwrap().ends_with(".rmeta") {
+ rmetas.insert(fs::canonicalize(&loc).unwrap(), PathKind::ExternFlag);
} else {
dylibs.insert(fs::canonicalize(&loc).unwrap(), PathKind::ExternFlag);
}
// Extract the rlib/dylib pair.
let mut slot = None;
let rlib = self.extract_one(rlibs, CrateFlavor::Rlib, &mut slot);
+ let rmeta = self.extract_one(rmetas, CrateFlavor::Rmeta, &mut slot);
let dylib = self.extract_one(dylibs, CrateFlavor::Dylib, &mut slot);
- if rlib.is_none() && dylib.is_none() {
+ if rlib.is_none() && rmeta.is_none() && dylib.is_none() {
return None;
}
match slot {
Some(Library {
dylib: dylib,
rlib: rlib,
+ rmeta: rmeta,
metadata: metadata,
})
}
Ok(blob)
}
};
+ } else if flavor == CrateFlavor::Rmeta {
+ let mut file = File::open(filename).map_err(|_|
+ format!("could not open file: '{}'", filename.display()))?;
+ let mut buf = vec![];
+ file.read_to_end(&mut buf).map_err(|_|
+ format!("failed to read rlib metadata: '{}'", filename.display()))?;
+ let blob = MetadataBlob::Raw(buf);
+ verify_decompressed_encoding_version(&blob, filename)?;
+ return Ok(blob);
}
unsafe {
let buf = common::path2cstr(filename);
let filename = path.file_name().unwrap().to_str().unwrap();
let flavor = if filename.ends_with(".rlib") {
CrateFlavor::Rlib
+ } else if filename.ends_with(".rmeta") {
+ CrateFlavor::Rmeta
} else {
CrateFlavor::Dylib
};
/// 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,
this.cfg.terminate(block, source_info,
TerminatorKind::Goto { target: loop_block });
- let might_break = this.in_loop_scope(loop_block, exit_block, move |this| {
- // conduct the test, if necessary
- let body_block;
- if let Some(cond_expr) = opt_cond_expr {
- // This loop has a condition, ergo its exit_block is reachable.
- this.find_loop_scope(expr_span, None).might_break = true;
+ this.in_loop_scope(
+ loop_block, exit_block, destination.clone(),
+ move |this| {
+ // conduct the test, if necessary
+ let body_block;
+ if let Some(cond_expr) = opt_cond_expr {
+ let loop_block_end;
+ let cond = unpack!(
+ loop_block_end = this.as_operand(loop_block, cond_expr));
+ body_block = this.cfg.start_new_block();
+ this.cfg.terminate(loop_block_end, source_info,
+ TerminatorKind::If {
+ cond: cond,
+ targets: (body_block, exit_block)
+ });
- let loop_block_end;
- let cond = unpack!(loop_block_end = this.as_operand(loop_block, cond_expr));
- body_block = this.cfg.start_new_block();
- this.cfg.terminate(loop_block_end, source_info,
- TerminatorKind::If {
- cond: cond,
- targets: (body_block, exit_block)
- });
- } else {
- body_block = loop_block;
- }
+ // if the test is false, there's no `break` to assign `destination`, so
+ // we have to do it; this overwrites any `break`-assigned value but it's
+ // always `()` anyway
+ this.cfg.push_assign_unit(exit_block, source_info, destination);
+ } else {
+ body_block = loop_block;
+ }
- // The “return” value of the loop body must always be an unit, but we cannot
- // reuse that as a “return” value of the whole loop expressions, because some
- // loops are diverging (e.g. `loop {}`). Thus, we introduce a unit temporary as
- // the destination for the loop body and assign the loop’s own “return” value
- // immediately after the iteration is finished.
- let tmp = this.get_unit_temp();
- // Execute the body, branching back to the test.
- let body_block_end = unpack!(this.into(&tmp, body_block, body));
- this.cfg.terminate(body_block_end, source_info,
- TerminatorKind::Goto { target: loop_block });
- });
- // If the loop may reach its exit_block, we assign an empty tuple to the
- // destination to keep the MIR well-formed.
- if might_break {
- this.cfg.push_assign_unit(exit_block, source_info, destination);
- }
+ // The “return” value of the loop body must always be an unit. We therefore
+ // introduce a unit temporary as the destination for the loop body.
+ let tmp = this.get_unit_temp();
+ // Execute the body, branching back to the test.
+ let body_block_end = unpack!(this.into(&tmp, body_block, body));
+ this.cfg.terminate(body_block_end, source_info,
+ TerminatorKind::Goto { target: loop_block });
+ }
+ );
exit_block.unit()
}
ExprKind::Call { ty, fun, args } => {
use build::{BlockAnd, BlockAndExtension, Builder};
use build::scope::LoopScope;
use hair::*;
-use rustc::middle::region::CodeExtent;
use rustc::mir::*;
-use syntax_pos::Span;
impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
block.unit()
}
ExprKind::Continue { label } => {
- this.break_or_continue(expr_span, label, block,
- |loop_scope| loop_scope.continue_block)
+ let LoopScope { continue_block, extent, .. } =
+ *this.find_loop_scope(expr_span, label);
+ this.exit_scope(expr_span, extent, block, continue_block);
+ this.cfg.start_new_block().unit()
}
- ExprKind::Break { label } => {
- this.break_or_continue(expr_span, label, block, |loop_scope| {
- loop_scope.might_break = true;
- loop_scope.break_block
- })
+ ExprKind::Break { label, value } => {
+ let (break_block, extent, destination) = {
+ let LoopScope {
+ break_block,
+ extent,
+ ref break_destination,
+ ..
+ } = *this.find_loop_scope(expr_span, label);
+ (break_block, extent, break_destination.clone())
+ };
+ if let Some(value) = value {
+ unpack!(block = this.into(&destination, block, value))
+ } else {
+ this.cfg.push_assign_unit(block, source_info, &destination)
+ }
+ this.exit_scope(expr_span, extent, block, break_block);
+ this.cfg.start_new_block().unit()
}
ExprKind::Return { value } => {
block = match value {
}
}
- fn break_or_continue<F>(&mut self,
- span: Span,
- label: Option<CodeExtent>,
- block: BasicBlock,
- exit_selector: F)
- -> BlockAnd<()>
- where F: FnOnce(&mut LoopScope) -> BasicBlock
- {
- let (exit_block, extent) = {
- let loop_scope = self.find_loop_scope(span, label);
- (exit_selector(loop_scope), loop_scope.extent)
- };
- self.exit_scope(span, extent, block, exit_block);
- self.cfg.start_new_block().unit()
- }
-
}
/// the current set of loops; see the `scope` module for more
/// details
- loop_scopes: Vec<scope::LoopScope>,
+ loop_scopes: Vec<scope::LoopScope<'tcx>>,
/// the vector of all scopes that we have created thus far;
/// we track this for debuginfo later
}
#[derive(Clone, Debug)]
-pub struct LoopScope {
+pub struct LoopScope<'tcx> {
/// Extent of the loop
pub extent: CodeExtent,
/// Where the body of the loop begins
/// Block to branch into when the loop terminates (either by being `break`-en out from, or by
/// having its condition to become false)
pub break_block: BasicBlock,
- /// Indicates the reachability of the break_block for this loop
- pub might_break: bool
+ /// The destination of the loop expression itself (i.e. where to put the result of a `break`
+ /// expression)
+ pub break_destination: Lvalue<'tcx>,
}
impl<'tcx> Scope<'tcx> {
///
/// Returns the might_break attribute of the LoopScope used.
pub fn in_loop_scope<F>(&mut self,
- loop_block: BasicBlock,
- break_block: BasicBlock,
- f: F)
- -> bool
+ loop_block: BasicBlock,
+ break_block: BasicBlock,
+ break_destination: Lvalue<'tcx>,
+ f: F)
where F: FnOnce(&mut Builder<'a, 'gcx, 'tcx>)
{
let extent = self.extent_of_innermost_scope();
extent: extent.clone(),
continue_block: loop_block,
break_block: break_block,
- might_break: false
+ break_destination: break_destination,
};
self.loop_scopes.push(loop_scope);
f(self);
let loop_scope = self.loop_scopes.pop().unwrap();
assert!(loop_scope.extent == extent);
- loop_scope.might_break
}
/// Convenience wrapper that pushes a scope and then executes `f`
pub fn find_loop_scope(&mut self,
span: Span,
label: Option<CodeExtent>)
- -> &mut LoopScope {
+ -> &mut LoopScope<'tcx> {
let loop_scopes = &mut self.loop_scopes;
match label {
None => {
},
hir::ExprRet(ref v) =>
ExprKind::Return { value: v.to_ref() },
- hir::ExprBreak(label) =>
- ExprKind::Break { label: label.map(|_| loop_label(cx, expr)) },
+ hir::ExprBreak(label, ref value) =>
+ ExprKind::Break { label: label.map(|_| loop_label(cx, expr)),
+ value: value.to_ref() },
hir::ExprAgain(label) =>
ExprKind::Continue { label: label.map(|_| loop_label(cx, expr)) },
hir::ExprMatch(ref discr, ref arms, _) =>
hir::ExprWhile(ref cond, ref body, _) =>
ExprKind::Loop { condition: Some(cond.to_ref()),
body: block::to_expr_ref(cx, body) },
- hir::ExprLoop(ref body, _) =>
+ hir::ExprLoop(ref body, _, _) =>
ExprKind::Loop { condition: None,
body: block::to_expr_ref(cx, body) },
hir::ExprField(ref source, name) => {
},
Break {
label: Option<CodeExtent>,
+ value: Option<ExprRef<'tcx>>,
},
Continue {
label: Option<CodeExtent>,
ExprKind::Loop(_, Some(ident)) |
ExprKind::WhileLet(.., Some(ident)) |
ExprKind::ForLoop(.., Some(ident)) |
- ExprKind::Break(Some(ident)) |
+ ExprKind::Break(Some(ident), _) |
ExprKind::Continue(Some(ident)) => {
self.check_label(ident.node, ident.span, expr.id);
}
ItemKind::Mod(_) => {
// Ensure that `path` attributes on modules are recorded as used (c.f. #35584).
attr::first_attr_value_str_by_name(&item.attrs, "path");
+ if let Some(attr) =
+ item.attrs.iter().find(|attr| attr.name() == "warn_directory_ownership") {
+ let lint = lint::builtin::LEGACY_DIRECTORY_OWNERSHIP;
+ let msg = "cannot declare a new module at this location";
+ self.session.add_lint(lint, item.id, item.span, msg.to_string());
+ attr::mark_used(attr);
+ }
}
ItemKind::Union(ref vdata, _) => {
if !vdata.is_struct() {
hir::ExprLoop(..) |
// More control flow (also not very meaningful).
- hir::ExprBreak(_) |
+ hir::ExprBreak(..) |
hir::ExprAgain(_) |
hir::ExprRet(_) |
register_diagnostics! {
E0472, // asm! is unsupported on this target
E0561, // patterns aren't allowed in function pointer types
+ E0571, // `break` with a value in a non-`loop`-loop
}
use rustc::session::Session;
use rustc::dep_graph::DepNode;
+use rustc::hir::def::{Def, DefMap};
use rustc::hir::map::Map;
use rustc::hir::intravisit::{self, Visitor};
use rustc::hir;
use syntax_pos::Span;
+#[derive(Clone, Copy, PartialEq)]
+enum LoopKind {
+ Loop(hir::LoopSource),
+ WhileLoop,
+}
+
+impl LoopKind {
+ fn name(self) -> &'static str {
+ match self {
+ LoopKind::Loop(hir::LoopSource::Loop) => "loop",
+ LoopKind::Loop(hir::LoopSource::WhileLet) => "while let",
+ LoopKind::Loop(hir::LoopSource::ForLoop) => "for",
+ LoopKind::WhileLoop => "while",
+ }
+ }
+}
+
#[derive(Clone, Copy, PartialEq)]
enum Context {
Normal,
- Loop,
+ Loop(LoopKind),
Closure,
}
#[derive(Copy, Clone)]
-struct CheckLoopVisitor<'a> {
+struct CheckLoopVisitor<'a, 'ast: 'a> {
sess: &'a Session,
+ def_map: &'a DefMap,
+ hir_map: &'a Map<'ast>,
cx: Context,
}
-pub fn check_crate(sess: &Session, map: &Map) {
+pub fn check_crate(sess: &Session, def_map: &DefMap, map: &Map) {
let _task = map.dep_graph.in_task(DepNode::CheckLoops);
let krate = map.krate();
krate.visit_all_item_likes(&mut CheckLoopVisitor {
sess: sess,
+ def_map: def_map,
+ hir_map: map,
cx: Normal,
}.as_deep_visitor());
}
-impl<'a, 'v> Visitor<'v> for CheckLoopVisitor<'a> {
+impl<'a, 'ast, 'v> Visitor<'v> for CheckLoopVisitor<'a, 'ast> {
fn visit_item(&mut self, i: &hir::Item) {
self.with_context(Normal, |v| intravisit::walk_item(v, i));
}
fn visit_expr(&mut self, e: &hir::Expr) {
match e.node {
hir::ExprWhile(ref e, ref b, _) => {
- self.visit_expr(&e);
- self.with_context(Loop, |v| v.visit_block(&b));
+ self.with_context(Loop(LoopKind::WhileLoop), |v| {
+ v.visit_expr(&e);
+ v.visit_block(&b);
+ });
}
- hir::ExprLoop(ref b, _) => {
- self.with_context(Loop, |v| v.visit_block(&b));
+ hir::ExprLoop(ref b, _, source) => {
+ self.with_context(Loop(LoopKind::Loop(source)), |v| v.visit_block(&b));
}
hir::ExprClosure(.., ref b, _) => {
self.with_context(Closure, |v| v.visit_expr(&b));
}
- hir::ExprBreak(_) => self.require_loop("break", e.span),
+ hir::ExprBreak(ref opt_label, ref opt_expr) => {
+ if opt_expr.is_some() {
+ let loop_kind = if opt_label.is_some() {
+ let loop_def = self.def_map.get(&e.id).unwrap().full_def();
+ if loop_def == Def::Err {
+ None
+ } else if let Def::Label(loop_id) = loop_def {
+ Some(match self.hir_map.expect_expr(loop_id).node {
+ hir::ExprWhile(..) => LoopKind::WhileLoop,
+ hir::ExprLoop(_, _, source) => LoopKind::Loop(source),
+ ref r => span_bug!(e.span,
+ "break label resolved to a non-loop: {:?}", r),
+ })
+ } else {
+ span_bug!(e.span, "break resolved to a non-label")
+ }
+ } else if let Loop(kind) = self.cx {
+ Some(kind)
+ } else {
+ // `break` outside a loop - caught below
+ None
+ };
+ match loop_kind {
+ None | Some(LoopKind::Loop(hir::LoopSource::Loop)) => (),
+ Some(kind) => {
+ struct_span_err!(self.sess, e.span, E0571,
+ "`break` with value from a `{}` loop",
+ kind.name())
+ .span_label(e.span,
+ &format!("can only break with a value inside `loop`"))
+ .emit();
+ }
+ }
+ }
+ self.require_loop("break", e.span);
+ }
hir::ExprAgain(_) => self.require_loop("continue", e.span),
_ => intravisit::walk_expr(self, e),
}
}
}
-impl<'a> CheckLoopVisitor<'a> {
+impl<'a, 'ast> CheckLoopVisitor<'a, 'ast> {
fn with_context<F>(&mut self, cx: Context, f: F)
- where F: FnOnce(&mut CheckLoopVisitor<'a>)
+ where F: FnOnce(&mut CheckLoopVisitor<'a, 'ast>)
{
let old_cx = self.cx;
self.cx = cx;
fn require_loop(&self, name: &str, span: Span) {
match self.cx {
- Loop => {}
+ Loop(_) => {}
Closure => {
struct_span_err!(self.sess, span, E0267, "`{}` inside of a closure", name)
.span_label(span, &format!("cannot break inside of a closure"))
visit::walk_expr(self, expr);
}
- ExprKind::Break(Some(label)) | ExprKind::Continue(Some(label)) => {
+ ExprKind::Break(Some(label), _) | ExprKind::Continue(Some(label)) => {
match self.search_label(label.node) {
None => {
self.record_def(expr.id, err_path_resolution());
resolve_error(self,
label.span,
- ResolutionError::UndeclaredLabel(&label.node.name.as_str()))
+ ResolutionError::UndeclaredLabel(&label.node.name.as_str()));
}
Some(def @ Def::Label(_)) => {
// Since this def is a label, it is never read.
- self.record_def(expr.id, PathResolution::new(def))
+ self.record_def(expr.id, PathResolution::new(def));
}
Some(_) => {
- span_bug!(expr.span, "label wasn't mapped to a label def!")
+ span_bug!(expr.span, "label wasn't mapped to a label def!");
}
}
+
+ // visit `break` argument if any
+ visit::walk_expr(self, expr);
}
ExprKind::IfLet(ref pattern, ref subexpression, ref if_block, ref optional_else) => {
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);
}
fn llvm_archive_kind(&self) -> Result<ArchiveKind, &str> {
- let kind = &self.config.sess.target.target.options.archive_format[..];
+ let kind = &*self.config.sess.target.target.options.archive_format;
kind.parse().map_err(|_| kind)
}
use session::filesearch;
use session::search_paths::PathKind;
use session::Session;
-use middle::cstore::{self, LinkMeta, NativeLibrary};
+use middle::cstore::{self, LinkMeta, NativeLibrary, LibSource};
use middle::cstore::{LinkagePreference, NativeLibraryKind};
use middle::dependency_format::Linkage;
use CrateTranslation;
}
"rust_out".to_string()
-
}
pub fn build_link_meta(incremental_hashes_map: &IncrementalHashesMap,
config::CrateTypeRlib => {
outputs.out_directory.join(&format!("lib{}.rlib", libname))
}
+ config::CrateTypeMetadata => {
+ outputs.out_directory.join(&format!("lib{}.rmeta", libname))
+ }
config::CrateTypeCdylib |
config::CrateTypeProcMacro |
config::CrateTypeDylib => {
.or_else(|| fmts.get(&config::CrateTypeCdylib))
.or_else(|| fmts.get(&config::CrateTypeProcMacro));
let fmts = fmts.unwrap_or_else(|| {
- bug!("could not find formats for rlibs")
+ bug!("could not find formats for rlibs");
});
for (cnum, path) in crates {
match fmts[cnum.as_usize() - 1] {
}
let name = sess.cstore.crate_name(cnum).clone();
let path = match path {
- Some(p) => p,
- None => {
+ LibSource::Some(p) => p,
+ LibSource::MetadataOnly => {
+ sess.fatal(&format!("could not find rlib for: `{}`, found rmeta (metadata) file",
+ name));
+ }
+ LibSource::None => {
sess.fatal(&format!("could not find rlib for: `{}`", name));
}
};
config::CrateTypeStaticlib => {
link_staticlib(sess, &objects, &out_filename, tmpdir.path());
}
+ config::CrateTypeMetadata => {
+ emit_metadata(sess, trans, &out_filename);
+ }
_ => {
link_natively(sess, crate_type, &objects, &out_filename, trans,
outputs, tmpdir.path());
}
}
+fn emit_metadata<'a>(sess: &'a Session, trans: &CrateTranslation, out_filename: &Path) {
+ let result = fs::File::create(out_filename).and_then(|mut f| f.write_all(&trans.metadata));
+ if let Err(e) = result {
+ sess.fatal(&format!("failed to write {}: {}", out_filename.display(), e));
+ }
+}
+
// Create an 'rlib'
//
// An rlib in its current incarnation is essentially a renamed .a file. The
tmpdir: &Path) -> ArchiveBuilder<'a> {
info!("preparing rlib from {:?} to {:?}", objects, out_filename);
let mut ab = ArchiveBuilder::new(archive_config(sess, out_filename, None));
+
for obj in objects {
ab.add_file(obj);
}
// here so concurrent builds in the same directory don't try to use
// the same filename for metadata (stomping over one another)
let metadata = tmpdir.join(sess.cstore.metadata_filename());
- match fs::File::create(&metadata).and_then(|mut f| {
- f.write_all(&trans.metadata)
- }) {
- Ok(..) => {}
- Err(e) => {
- sess.fatal(&format!("failed to write {}: {}",
- metadata.display(), e));
- }
- }
+ emit_metadata(sess, trans, &metadata);
ab.add_file(&metadata);
// For LTO purposes, the bytecode of this library is also inserted
use std::fs;
use rustc::hir::def_id::CrateNum;
+use rustc::middle::cstore::LibSource;
pub struct RPathConfig<'a> {
- pub used_crates: Vec<(CrateNum, Option<PathBuf>)>,
+ pub used_crates: Vec<(CrateNum, LibSource)>,
pub out_filename: PathBuf,
pub is_like_osx: bool,
pub has_rpath: bool,
debug!("preparing the RPATH!");
let libs = config.used_crates.clone();
- let libs = libs.into_iter().filter_map(|(_, l)| l).collect::<Vec<_>>();
+ let libs = libs.into_iter().filter_map(|(_, l)| l.option()).collect::<Vec<_>>();
let rpaths = get_rpaths(config, &libs[..]);
flags.extend_from_slice(&rpaths_to_flags(&rpaths[..]));
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! {
config::CrateTypeStaticlib |
config::CrateTypeCdylib => MetadataKind::None,
- config::CrateTypeRlib => MetadataKind::Uncompressed,
+ config::CrateTypeRlib |
+ config::CrateTypeMetadata => MetadataKind::Uncompressed,
config::CrateTypeDylib |
config::CrateTypeProcMacro => MetadataKind::Compressed,
assert_module_sources::assert_module_sources(tcx, &modules);
// Skip crate items and just output metadata in -Z no-trans mode.
- if tcx.sess.opts.debugging_opts.no_trans {
+ if tcx.sess.opts.debugging_opts.no_trans ||
+ tcx.sess.crate_types.borrow().iter().all(|ct| ct == &config::CrateTypeMetadata) {
let linker_info = LinkerInfo::new(&shared_ccx, &[]);
return CrateTranslation {
modules: modules,
.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,
use rustc::{infer, traits};
use rustc::ty::{self, LvaluePreference, Ty};
use syntax::symbol::Symbol;
-use syntax::ptr::P;
use syntax_pos::Span;
use rustc::hir;
pub fn check_call(&self,
call_expr: &'gcx hir::Expr,
callee_expr: &'gcx hir::Expr,
- arg_exprs: &'gcx [P<hir::Expr>],
+ arg_exprs: &'gcx [hir::Expr],
expected: Expectation<'tcx>)
-> Ty<'tcx> {
let original_callee_ty = self.check_expr(callee_expr);
fn confirm_builtin_call(&self,
call_expr: &hir::Expr,
callee_ty: Ty<'tcx>,
- arg_exprs: &'gcx [P<hir::Expr>],
+ arg_exprs: &'gcx [hir::Expr],
expected: Expectation<'tcx>)
-> Ty<'tcx> {
let error_fn_sig;
fn confirm_deferred_closure_call(&self,
call_expr: &hir::Expr,
- arg_exprs: &'gcx [P<hir::Expr>],
+ arg_exprs: &'gcx [hir::Expr],
expected: Expectation<'tcx>,
fn_sig: ty::FnSig<'tcx>)
-> Ty<'tcx> {
fn confirm_overloaded_call(&self,
call_expr: &hir::Expr,
callee_expr: &'gcx hir::Expr,
- arg_exprs: &'gcx [P<hir::Expr>],
+ arg_exprs: &'gcx [hir::Expr],
expected: Expectation<'tcx>,
method_callee: ty::MethodCallee<'tcx>)
-> Ty<'tcx> {
/// Cast of thin to fat raw ptr (eg. `*const () as *const [u8]`)
SizedUnsizedCast,
IllegalCast,
+ NeedDeref,
NeedViaPtr,
NeedViaThinPtr,
NeedViaInt,
fn report_cast_error(&self, fcx: &FnCtxt<'a, 'gcx, 'tcx>, e: CastError) {
match e {
+ CastError::NeedDeref => {
+ let cast_ty = fcx.ty_to_string(self.cast_ty);
+ let mut err = fcx.type_error_struct(self.cast_span,
+ |actual| {
+ format!("casting `{}` as `{}` is invalid",
+ actual,
+ cast_ty)
+ },
+ self.expr_ty);
+ err.span_label(self.expr.span,
+ &format!("cannot cast `{}` as `{}`",
+ fcx.ty_to_string(self.expr_ty),
+ cast_ty));
+ if let Ok(snippet) = fcx.sess().codemap().span_to_snippet(self.expr.span) {
+ err.span_label(self.expr.span,
+ &format!("did you mean `*{}`?", snippet));
+ }
+ err.emit();
+ }
CastError::NeedViaThinPtr |
CastError::NeedViaPtr => {
let mut err = fcx.type_error_struct(self.span,
(Ptr(m_e), Ptr(m_c)) => self.check_ptr_ptr_cast(fcx, m_e, m_c), // ptr-ptr-cast
(Ptr(m_expr), Int(_)) => self.check_ptr_addr_cast(fcx, m_expr), // ptr-addr-cast
(FnPtr, Int(_)) => Ok(CastKind::FnPtrAddrCast),
- (RPtr(_), Int(_)) |
- (RPtr(_), Float) => Err(CastError::NeedViaPtr),
+ (RPtr(p), Int(_)) |
+ (RPtr(p), Float) => {
+ match p.ty.sty {
+ ty::TypeVariants::TyInt(_) |
+ ty::TypeVariants::TyUint(_) |
+ ty::TypeVariants::TyFloat(_) => {
+ Err(CastError::NeedDeref)
+ }
+ ty::TypeVariants::TyInfer(t) => {
+ match t {
+ ty::InferTy::IntVar(_) |
+ ty::InferTy::FloatVar(_) |
+ ty::InferTy::FreshIntTy(_) |
+ ty::InferTy::FreshFloatTy(_) => {
+ Err(CastError::NeedDeref)
+ }
+ _ => Err(CastError::NeedViaPtr),
+ }
+ }
+ _ => Err(CastError::NeedViaPtr),
+ }
+ }
// * -> ptr
(Int(_), Ptr(mt)) => self.check_addr_ptr_cast(fcx, mt), // addr-ptr-cast
(FnPtr, Ptr(mt)) => self.check_fptr_ptr_cast(fcx, mt),
use CrateCtxt;
use TypeAndSubsts;
use lint;
-use util::common::{block_query, ErrorReported, indenter, loop_query};
+use util::common::{ErrorReported, indenter};
use util::nodemap::{DefIdMap, FxHashMap, FxHashSet, NodeMap};
use std::cell::{Cell, Ref, RefCell};
}
}
+#[derive(Clone)]
+pub struct LoopCtxt<'gcx, 'tcx> {
+ unified: Ty<'tcx>,
+ coerce_to: Ty<'tcx>,
+ break_exprs: Vec<&'gcx hir::Expr>,
+ may_break: bool,
+}
+
+#[derive(Clone)]
+pub struct EnclosingLoops<'gcx, 'tcx> {
+ stack: Vec<LoopCtxt<'gcx, 'tcx>>,
+ by_id: NodeMap<usize>,
+}
+
+impl<'gcx, 'tcx> EnclosingLoops<'gcx, 'tcx> {
+ fn find_loop(&mut self, id: Option<ast::NodeId>) -> Option<&mut LoopCtxt<'gcx, 'tcx>> {
+ if let Some(id) = id {
+ if let Some(ix) = self.by_id.get(&id).cloned() {
+ Some(&mut self.stack[ix])
+ } else {
+ None
+ }
+ } else {
+ self.stack.last_mut()
+ }
+ }
+}
+
#[derive(Clone)]
pub struct FnCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
ast_ty_to_ty_cache: RefCell<NodeMap<Ty<'tcx>>>,
/// Whether any child nodes have any type errors.
has_errors: Cell<bool>,
+ enclosing_loops: RefCell<EnclosingLoops<'gcx, 'tcx>>,
+
inh: &'a Inherited<'a, 'gcx, 'tcx>,
}
ast::CRATE_NODE_ID)),
diverges: Cell::new(Diverges::Maybe),
has_errors: Cell::new(false),
+ enclosing_loops: RefCell::new(EnclosingLoops {
+ stack: Vec::new(),
+ by_id: NodeMap(),
+ }),
inh: inh,
}
}
sp: Span,
method_fn_ty: Ty<'tcx>,
callee_expr: &'gcx hir::Expr,
- args_no_rcvr: &'gcx [P<hir::Expr>],
+ args_no_rcvr: &'gcx [hir::Expr],
tuple_arguments: TupleArgumentsFlag,
expected: Expectation<'tcx>)
-> Ty<'tcx> {
sp: Span,
fn_inputs: &[Ty<'tcx>],
expected_arg_tys: &[Ty<'tcx>],
- args: &'gcx [P<hir::Expr>],
+ args: &'gcx [hir::Expr],
variadic: bool,
tuple_arguments: TupleArgumentsFlag) {
let tcx = self.tcx;
fn check_method_call(&self,
expr: &'gcx hir::Expr,
method_name: Spanned<ast::Name>,
- args: &'gcx [P<hir::Expr>],
+ args: &'gcx [hir::Expr],
tps: &[P<hir::Ty>],
expected: Expectation<'tcx>,
lvalue_pref: LvaluePreference) -> Ty<'tcx> {
}
tcx.mk_nil()
}
- hir::ExprBreak(_) => { tcx.types.never }
+ hir::ExprBreak(ref label_opt, ref expr_opt) => {
+ let loop_id = if label_opt.is_some() {
+ let loop_def = tcx.expect_def(expr.id);
+ if let Def::Label(loop_id) = loop_def {
+ Some(Some(loop_id))
+ } else if loop_def == Def::Err {
+ // an error was already printed, so just ignore it
+ None
+ } else {
+ span_bug!(expr.span, "break label resolved to a non-label");
+ }
+ } else {
+ Some(None)
+ };
+ if let Some(loop_id) = loop_id {
+ let coerce_to = {
+ let mut enclosing_loops = self.enclosing_loops.borrow_mut();
+ enclosing_loops.find_loop(loop_id).map(|ctxt| ctxt.coerce_to)
+ };
+ if let Some(coerce_to) = coerce_to {
+ let e_ty;
+ let cause;
+ if let Some(ref e) = *expr_opt {
+ // Recurse without `enclosing_loops` borrowed.
+ e_ty = self.check_expr_with_hint(e, coerce_to);
+ cause = self.misc(e.span);
+ // Notably, the recursive call may alter coerce_to - must not keep using it!
+ } else {
+ // `break` without argument acts like `break ()`.
+ e_ty = tcx.mk_nil();
+ cause = self.misc(expr.span);
+ }
+ let mut enclosing_loops = self.enclosing_loops.borrow_mut();
+ let ctxt = enclosing_loops.find_loop(loop_id).unwrap();
+
+ let result = if let Some(ref e) = *expr_opt {
+ // Special-case the first element, as it has no "previous expressions".
+ let result = if !ctxt.may_break {
+ self.try_coerce(e, e_ty, ctxt.coerce_to)
+ } else {
+ self.try_find_coercion_lub(&cause, || ctxt.break_exprs.iter().cloned(),
+ ctxt.unified, e, e_ty)
+ };
+
+ ctxt.break_exprs.push(e);
+ result
+ } else {
+ self.eq_types(true, &cause, e_ty, ctxt.unified)
+ .map(|InferOk { obligations, .. }| {
+ // FIXME(#32730) propagate obligations
+ assert!(obligations.is_empty());
+ e_ty
+ })
+ };
+ match result {
+ Ok(ty) => ctxt.unified = ty,
+ Err(err) => {
+ self.report_mismatched_types(&cause, ctxt.unified, e_ty, err);
+ }
+ }
+
+ ctxt.may_break = true;
+ }
+ // Otherwise, we failed to find the enclosing loop; this can only happen if the
+ // `break` was not inside a loop at all, which is caught by the loop-checking pass.
+ }
+ tcx.types.never
+ }
hir::ExprAgain(_) => { tcx.types.never }
hir::ExprRet(ref expr_opt) => {
if let Some(ref e) = *expr_opt {
expr.span, expected)
}
hir::ExprWhile(ref cond, ref body, _) => {
- self.check_expr_has_type(&cond, tcx.types.bool);
- let cond_diverging = self.diverges.get();
- self.check_block_no_value(&body);
+ let unified = self.tcx.mk_nil();
+ let coerce_to = unified;
+ let ctxt = LoopCtxt {
+ unified: unified,
+ coerce_to: coerce_to,
+ break_exprs: vec![],
+ may_break: true,
+ };
+ self.with_loop_ctxt(expr.id, ctxt, || {
+ self.check_expr_has_type(&cond, tcx.types.bool);
+ let cond_diverging = self.diverges.get();
+ self.check_block_no_value(&body);
- // We may never reach the body so it diverging means nothing.
- self.diverges.set(cond_diverging);
+ // We may never reach the body so it diverging means nothing.
+ self.diverges.set(cond_diverging);
+ });
if self.has_errors.get() {
tcx.types.err
tcx.mk_nil()
}
}
- hir::ExprLoop(ref body, _) => {
- self.check_block_no_value(&body);
- if may_break(tcx, expr.id, &body) {
+ hir::ExprLoop(ref body, _, _) => {
+ let unified = self.next_ty_var();
+ let coerce_to = expected.only_has_type(self).unwrap_or(unified);
+ let ctxt = LoopCtxt {
+ unified: unified,
+ coerce_to: coerce_to,
+ break_exprs: vec![],
+ may_break: false,
+ };
+
+ let ctxt = self.with_loop_ctxt(expr.id, ctxt, || {
+ self.check_block_no_value(&body);
+ });
+ if ctxt.may_break {
// No way to know whether it's diverging because
// of a `break` or an outer `break` or `return.
self.diverges.set(Diverges::Maybe);
- tcx.mk_nil()
+ ctxt.unified
} else {
tcx.types.never
}
self.check_block_with_expected(&b, expected)
}
hir::ExprCall(ref callee, ref args) => {
- self.check_call(expr, &callee, &args[..], expected)
+ self.check_call(expr, &callee, args, expected)
}
hir::ExprMethodCall(name, ref tps, ref args) => {
- self.check_method_call(expr, name, &args[..], &tps[..], expected, lvalue_pref)
+ self.check_method_call(expr, name, args, &tps[..], expected, lvalue_pref)
}
hir::ExprCast(ref e, ref t) => {
if let hir::TyArray(_, ref count_expr) = t.node {
let result = if i == 0 {
self.try_coerce(e, e_ty, coerce_to)
} else {
- let prev_elems = || args[..i].iter().map(|e| &**e);
+ let prev_elems = || args[..i].iter().map(|e| &*e);
self.try_find_coercion_lub(&cause, prev_elems, unified, e, e_ty)
};
self.tcx.types.err
})
}
-}
-// Returns true if b contains a break that can exit from b
-pub fn may_break(tcx: TyCtxt, id: ast::NodeId, b: &hir::Block) -> bool {
- // First: is there an unlabeled break immediately
- // inside the loop?
- (loop_query(&b, |e| {
- match *e {
- hir::ExprBreak(None) => true,
- _ => false
+ fn with_loop_ctxt<F: FnOnce()>(&self, id: ast::NodeId, ctxt: LoopCtxt<'gcx, 'tcx>, f: F)
+ -> LoopCtxt<'gcx, 'tcx> {
+ let index;
+ {
+ let mut enclosing_loops = self.enclosing_loops.borrow_mut();
+ index = enclosing_loops.stack.len();
+ enclosing_loops.by_id.insert(id, index);
+ enclosing_loops.stack.push(ctxt);
}
- })) ||
- // Second: is there a labeled break with label
- // <id> nested anywhere inside the loop?
- (block_query(b, |e| {
- if let hir::ExprBreak(Some(_)) = e.node {
- tcx.expect_def(e.id) == Def::Label(id)
- } else {
- false
+ f();
+ {
+ let mut enclosing_loops = self.enclosing_loops.borrow_mut();
+ debug_assert!(enclosing_loops.stack.len() == index + 1);
+ enclosing_loops.by_id.remove(&id).expect("missing loop context");
+ (enclosing_loops.stack.pop().expect("missing loop context"))
}
- }))
+ }
}
pub fn check_bounds_are_used<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
hir::ExprCall(ref callee, ref args) => {
if has_method_map {
self.constrain_call(expr, Some(&callee),
- args.iter().map(|e| &**e), false);
+ args.iter().map(|e| &*e), false);
} else {
self.constrain_callee(callee.id, expr, &callee);
self.constrain_call(expr, None,
- args.iter().map(|e| &**e), false);
+ args.iter().map(|e| &*e), false);
}
intravisit::walk_expr(self, expr);
hir::ExprMethodCall(.., ref args) => {
self.constrain_call(expr, Some(&args[0]),
- args[1..].iter().map(|e| &**e), false);
+ args[1..].iter().map(|e| &*e), false);
intravisit::walk_expr(self, expr);
}
self.check_expr_fn_block(expr, &body);
}
- hir::ExprLoop(ref body, _) => {
+ hir::ExprLoop(ref body, _, _) => {
let repeating_scope = self.set_repeating_scope(body.id);
intravisit::walk_expr(self, expr);
self.set_repeating_scope(repeating_scope);
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
os_imp::current_exe()
}
-/// An iterator over the arguments of a process, yielding a `String` value
+/// An iterator over the arguments of a process, yielding a [`String`] value
/// for each argument.
///
-/// This structure is created through the `std::env::args` method.
+/// This structure is created through the [`std::env::args`] method.
+///
+/// [`String`]: ../string/struct.String.html
+/// [`std::env::args`]: ./fn.args.html
#[stable(feature = "env", since = "1.0.0")]
pub struct Args { inner: ArgsOs }
-/// An iterator over the arguments of a process, yielding an `OsString` value
+/// An iterator over the arguments of a process, yielding an [`OsString`] value
/// for each argument.
///
-/// This structure is created through the `std::env::args_os` method.
+/// This structure is created through the [`std::env::args_os`] method.
+///
+/// [`OsString`]: ../ffi/struct.OsString.html
+/// [`std::env::args_os`]: ./fn.args_os.html
#[stable(feature = "env", since = "1.0.0")]
pub struct ArgsOs { inner: sys::args::Args }
///
/// The returned iterator will panic during iteration if any argument to the
/// process is not valid unicode. If this is not desired,
-/// use the `args_os` function instead.
+/// use the [`args_os`] function instead.
///
/// # Examples
///
/// println!("{}", argument);
/// }
/// ```
+///
+/// [`args_os`]: ./fn.args_os.html
#[stable(feature = "env", since = "1.0.0")]
pub fn args() -> Args {
Args { inner: args_os() }
inner: self.inner.duplicate()?
})
}
+
+ /// Changes the permissions on the underlying file.
+ ///
+ /// # Platform-specific behavior
+ ///
+ /// This function currently corresponds to the `fchmod` function on Unix and
+ /// the `SetFileInformationByHandle` function on Windows. Note that, this
+ /// [may change in the future][changes].
+ ///
+ /// [changes]: ../io/index.html#platform-specific-behavior
+ ///
+ /// # Errors
+ ///
+ /// This function will return an error if the user lacks permission change
+ /// attributes on the underlying file. It may also return an error in other
+ /// os-specific unspecified cases.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(set_permissions_atomic)]
+ /// # fn foo() -> std::io::Result<()> {
+ /// use std::fs::File;
+ ///
+ /// let file = File::open("foo.txt")?;
+ /// let mut perms = file.metadata()?.permissions();
+ /// perms.set_readonly(true);
+ /// file.set_permissions(perms)?;
+ /// # Ok(())
+ /// # }
+ /// ```
+ #[unstable(feature = "set_permissions_atomic", issue="37916")]
+ pub fn set_permissions(&self, perm: Permissions) -> io::Result<()> {
+ self.inner.set_permissions(perm.0)
+ }
}
impl AsInner<fs_imp::File> for File {
check!(fs::set_permissions(&file, p));
}
+ #[test]
+ fn fchmod_works() {
+ let tmpdir = tmpdir();
+ let path = tmpdir.join("in.txt");
+
+ let file = check!(File::create(&path));
+ let attr = check!(fs::metadata(&path));
+ assert!(!attr.permissions().readonly());
+ let mut p = attr.permissions();
+ p.set_readonly(true);
+ check!(file.set_permissions(p.clone()));
+ let attr = check!(fs::metadata(&path));
+ assert!(attr.permissions().readonly());
+
+ p.set_readonly(false);
+ check!(file.set_permissions(p));
+ }
+
#[test]
fn sync_doesnt_kill_anything() {
let tmpdir = tmpdir();
impl SocketAddrV4 {
/// Creates a new socket address from the (ip, port) pair.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::{SocketAddrV4, Ipv4Addr};
+ ///
+ /// let socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080);
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn new(ip: Ipv4Addr, port: u16) -> SocketAddrV4 {
SocketAddrV4 {
}
/// Returns the IP address associated with this socket address.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::{SocketAddrV4, Ipv4Addr};
+ ///
+ /// let socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080);
+ /// assert_eq!(socket.ip(), &Ipv4Addr::new(127, 0, 0, 1));
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn ip(&self) -> &Ipv4Addr {
unsafe {
}
/// Change the IP address associated with this socket address.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::{SocketAddrV4, Ipv4Addr};
+ ///
+ /// let mut socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080);
+ /// socket.set_ip(Ipv4Addr::new(192, 168, 0, 1));
+ /// assert_eq!(socket.ip(), &Ipv4Addr::new(192, 168, 0, 1));
+ /// ```
#[stable(feature = "sockaddr_setters", since = "1.9.0")]
pub fn set_ip(&mut self, new_ip: Ipv4Addr) {
self.inner.sin_addr = *new_ip.as_inner()
}
/// Returns the port number associated with this socket address.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::{SocketAddrV4, Ipv4Addr};
+ ///
+ /// let socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080);
+ /// assert_eq!(socket.port(), 8080);
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn port(&self) -> u16 {
ntoh(self.inner.sin_port)
}
/// Change the port number associated with this socket address.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::net::{SocketAddrV4, Ipv4Addr};
+ ///
+ /// let mut socket = SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 8080);
+ /// socket.set_port(4242);
+ /// assert_eq!(socket.port(), 4242);
+ /// ```
#[stable(feature = "sockaddr_setters", since = "1.9.0")]
pub fn set_port(&mut self, new_port: u16) {
self.inner.sin_port = hton(new_port);
pub fn fd(&self) -> &FileDesc { &self.0 }
pub fn into_fd(self) -> FileDesc { self.0 }
+
+ pub fn set_permissions(&self, perm: FilePermissions) -> io::Result<()> {
+ cvt_r(|| unsafe { libc::fchmod(self.0.raw(), perm.mode) })?;
+ Ok(())
+ }
}
impl DirBuilder {
MaximumFileInfoByHandlesClass
}
+#[repr(C)]
+pub struct FILE_BASIC_INFO {
+ pub CreationTime: LARGE_INTEGER,
+ pub LastAccessTime: LARGE_INTEGER,
+ pub LastWriteTime: LARGE_INTEGER,
+ pub ChangeTime: LARGE_INTEGER,
+ pub FileAttributes: DWORD,
+}
+
#[repr(C)]
pub struct FILE_END_OF_FILE_INFO {
pub EndOfFile: LARGE_INTEGER,
Ok(PathBuf::from(OsString::from_wide(subst)))
}
}
+
+ pub fn set_permissions(&self, perm: FilePermissions) -> io::Result<()> {
+ let mut info = c::FILE_BASIC_INFO {
+ CreationTime: 0,
+ LastAccessTime: 0,
+ LastWriteTime: 0,
+ ChangeTime: 0,
+ FileAttributes: perm.attrs,
+ };
+ let size = mem::size_of_val(&info);
+ cvt(unsafe {
+ c::SetFileInformationByHandle(self.handle.raw(),
+ c::FileBasicInfo,
+ &mut info as *mut _ as *mut _,
+ size as c::DWORD)
+ })?;
+ Ok(())
+ }
}
impl FromInner<c::HANDLE> for File {
/// A referencing operation (`&a` or `&mut a`)
AddrOf(Mutability, P<Expr>),
- /// A `break`, with an optional label to break
- Break(Option<SpannedIdent>),
+ /// A `break`, with an optional label to break, and an optional expression
+ Break(Option<SpannedIdent>, Option<P<Expr>>),
/// A `continue`, with an optional label
Continue(Option<SpannedIdent>),
/// A `return`, with an optional value to be returned
use ext::expand::{self, Expansion};
use ext::hygiene::Mark;
use fold::{self, Folder};
-use parse::{self, parser};
+use parse::{self, parser, DirectoryOwnership};
use parse::token;
use ptr::P;
use symbol::Symbol;
pub depth: usize,
pub backtrace: ExpnId,
pub module: Rc<ModuleData>,
-
- // True if non-inline modules without a `#[path]` are forbidden at the root of this expansion.
- pub no_noninline_mod: bool,
+ pub directory_ownership: DirectoryOwnership,
}
/// One of these is made during expansion and incrementally updated as we go;
depth: 0,
backtrace: NO_EXPANSION,
module: Rc::new(ModuleData { mod_path: Vec::new(), directory: PathBuf::new() }),
- no_noninline_mod: false,
+ directory_ownership: DirectoryOwnership::Owned,
},
}
}
fn expr_break(&self, sp: Span) -> P<ast::Expr> {
- self.expr(sp, ast::ExprKind::Break(None))
+ self.expr(sp, ast::ExprKind::Break(None, None))
}
use feature_gate::{self, Features};
use fold;
use fold::*;
-use parse::{ParseSess, PResult, lexer};
+use parse::{ParseSess, DirectoryOwnership, PResult, lexer};
use parse::parser::Parser;
use parse::token;
use print::pprust;
}
fn fold_block(&mut self, block: P<Block>) -> P<Block> {
- let no_noninline_mod = mem::replace(&mut self.cx.current_expansion.no_noninline_mod, true);
+ let old_directory_ownership = self.cx.current_expansion.directory_ownership;
+ self.cx.current_expansion.directory_ownership = DirectoryOwnership::UnownedViaBlock;
let result = noop_fold_block(block, self);
- self.cx.current_expansion.no_noninline_mod = no_noninline_mod;
+ self.cx.current_expansion.directory_ownership = old_directory_ownership;
result
}
return noop_fold_item(item, self);
}
- let orig_no_noninline_mod = self.cx.current_expansion.no_noninline_mod;
+ let orig_directory_ownership = self.cx.current_expansion.directory_ownership;
let mut module = (*self.cx.current_expansion.module).clone();
module.mod_path.push(item.ident);
if inline_module {
if let Some(path) = attr::first_attr_value_str_by_name(&item.attrs, "path") {
- self.cx.current_expansion.no_noninline_mod = false;
+ self.cx.current_expansion.directory_ownership = DirectoryOwnership::Owned;
module.directory.push(&*path.as_str());
} else {
module.directory.push(&*item.ident.name.as_str());
}
} else {
- self.cx.current_expansion.no_noninline_mod = false;
- module.directory =
+ let mut path =
PathBuf::from(self.cx.parse_sess.codemap().span_to_filename(inner));
- module.directory.pop();
+ let directory_ownership = match path.file_name().unwrap().to_str() {
+ Some("mod.rs") => DirectoryOwnership::Owned,
+ _ => DirectoryOwnership::UnownedViaMod(false),
+ };
+ path.pop();
+ module.directory = path;
+ self.cx.current_expansion.directory_ownership = directory_ownership;
}
let orig_module =
mem::replace(&mut self.cx.current_expansion.module, Rc::new(module));
let result = noop_fold_item(item, self);
self.cx.current_expansion.module = orig_module;
- self.cx.current_expansion.no_noninline_mod = orig_no_noninline_mod;
+ self.cx.current_expansion.directory_ownership = orig_directory_ownership;
return result;
}
// Ensure that test functions are accessible from the test harness.
use ext::base::*;
use ext::base;
use ext::build::AstBuilder;
-use parse::token;
+use parse::{token, DirectoryOwnership};
use parse;
use print::pprust;
use ptr::P;
};
// The file will be added to the code map by the parser
let path = res_rel_file(cx, sp, Path::new(&file));
- let p = parse::new_sub_parser_from_file(cx.parse_sess(), &path, true, None, sp);
+ let directory_ownership = DirectoryOwnership::Owned;
+ let p = parse::new_sub_parser_from_file(cx.parse_sess(), &path, directory_ownership, None, sp);
struct ExpandResult<'a> {
p: parse::parser::Parser<'a>,
use ext::tt::macro_parser::{parse, parse_failure_msg};
use parse::ParseSess;
use parse::lexer::new_tt_reader;
-use parse::parser::{Parser, Restrictions};
+use parse::parser::Parser;
use parse::token::{self, NtTT, Token};
use parse::token::Token::*;
use print;
let trncbr =
new_tt_reader(&cx.parse_sess.span_diagnostic, Some(named_matches), rhs);
let mut p = Parser::new(cx.parse_sess(), Box::new(trncbr));
- p.directory = cx.current_expansion.module.directory.clone();
- p.restrictions = match cx.current_expansion.no_noninline_mod {
- true => Restrictions::NO_NONINLINE_MOD,
- false => Restrictions::empty(),
- };
+ let module = &cx.current_expansion.module;
+ p.directory.path = module.directory.clone();
+ p.directory.ownership = cx.current_expansion.directory_ownership;
+ p.root_module_name =
+ module.mod_path.last().map(|id| (*id.name.as_str()).to_owned());
+
p.check_unknown_macro_variable();
// Let the context choose how to interpret the result.
// Weird, but useful for X-macros.
(active, link_cfg, "1.14.0", Some(37406)),
(active, use_extern_macros, "1.15.0", Some(35896)),
+
+ // Allows `break {expr}` with a value inside `loop`s.
+ (active, loop_break_value, "1.14.0", Some(37339)),
);
declare_features! (
}
}
}
+ ast::ExprKind::Break(_, Some(_)) => {
+ gate_feature_post!(&self, loop_break_value, e.span,
+ "`break` with a value is experimental");
+ }
_ => {}
}
visit::walk_expr(self, e);
});
ExprKind::Path(qself, folder.fold_path(path))
}
- ExprKind::Break(opt_ident) => ExprKind::Break(opt_ident.map(|label|
- respan(folder.new_span(label.span),
- folder.fold_ident(label.node)))
- ),
+ ExprKind::Break(opt_ident, opt_expr) => {
+ ExprKind::Break(opt_ident.map(|label| respan(folder.new_span(label.span),
+ folder.fold_ident(label.node))),
+ opt_expr.map(|e| folder.fold_expr(e)))
+ }
ExprKind::Continue(opt_ident) => ExprKind::Continue(opt_ident.map(|label|
respan(folder.new_span(label.span),
folder.fold_ident(label.node)))
}
}
+#[derive(Clone)]
+pub struct Directory {
+ pub path: PathBuf,
+ pub ownership: DirectoryOwnership,
+}
+
+#[derive(Copy, Clone)]
+pub enum DirectoryOwnership {
+ Owned,
+ UnownedViaBlock,
+ UnownedViaMod(bool /* legacy warnings? */),
+}
+
// a bunch of utility functions of the form parse_<thing>_from_<source>
// where <thing> includes crate, expr, item, stmt, tts, and one that
// uses a HOF to parse anything, and <source> includes file and
/// On an error, use the given span as the source of the problem.
pub fn new_sub_parser_from_file<'a>(sess: &'a ParseSess,
path: &Path,
- owns_directory: bool,
+ directory_ownership: DirectoryOwnership,
module_name: Option<String>,
sp: Span) -> Parser<'a> {
let mut p = filemap_to_parser(sess, file_to_filemap(sess, path, Some(sp)));
- p.owns_directory = owns_directory;
+ p.directory.ownership = directory_ownership;
p.root_module_name = module_name;
p
}
use ast::{ViewPath, ViewPathGlob, ViewPathList, ViewPathSimple};
use ast::{Visibility, WhereClause};
use ast::{BinOpKind, UnOp};
-use ast;
+use {ast, attr};
use codemap::{self, CodeMap, Spanned, spanned, respan};
use syntax_pos::{self, Span, BytePos, mk_sp};
use errors::{self, DiagnosticBuilder};
use parse::lexer::{Reader, TokenAndSpan};
use parse::obsolete::ObsoleteSyntax;
use parse::token::{self, MatchNt, SubstNt};
-use parse::{new_sub_parser_from_file, ParseSess};
+use parse::{new_sub_parser_from_file, ParseSess, Directory, DirectoryOwnership};
use util::parser::{AssocOp, Fixity};
use print::pprust;
use ptr::P;
flags Restrictions: u8 {
const RESTRICTION_STMT_EXPR = 1 << 0,
const RESTRICTION_NO_STRUCT_LITERAL = 1 << 1,
- const NO_NONINLINE_MOD = 1 << 2,
}
}
/// extra detail when the same error is seen twice
pub obsolete_set: HashSet<ObsoleteSyntax>,
/// Used to determine the path to externally loaded source files
- pub directory: PathBuf,
+ pub directory: Directory,
/// Stack of open delimiters and their spans. Used for error message.
pub open_braces: Vec<(token::DelimToken, Span)>,
- /// Flag if this parser "owns" the directory that it is currently parsing
- /// in. This will affect how nested files are looked up.
- pub owns_directory: bool,
/// Name of the root module this parser originated from. If `None`, then the
/// name is not known. This does not change while the parser is descending
/// into modules, and sub-parsers have new values for this name.
}
pub struct ModulePathSuccess {
- pub path: ::std::path::PathBuf,
- pub owns_directory: bool,
+ pub path: PathBuf,
+ pub directory_ownership: DirectoryOwnership,
+ warn: bool,
}
pub struct ModulePathError {
quote_depth: 0,
parsing_token_tree: false,
obsolete_set: HashSet::new(),
- directory: PathBuf::new(),
+ directory: Directory { path: PathBuf::new(), ownership: DirectoryOwnership::Owned },
open_braces: Vec::new(),
- owns_directory: true,
root_module_name: None,
expected_tokens: Vec::new(),
tts: Vec::new(),
parser.token = tok.tok;
parser.span = tok.sp;
if parser.span != syntax_pos::DUMMY_SP {
- parser.directory = PathBuf::from(sess.codemap().span_to_filename(parser.span));
- parser.directory.pop();
+ parser.directory.path = PathBuf::from(sess.codemap().span_to_filename(parser.span));
+ parser.directory.path.pop();
}
parser
}
ex = ExprKind::Ret(None);
}
} else if self.eat_keyword(keywords::Break) {
- if self.token.is_lifetime() {
- ex = ExprKind::Break(Some(Spanned {
+ let lt = if self.token.is_lifetime() {
+ let spanned_lt = Spanned {
node: self.get_lifetime(),
span: self.span
- }));
+ };
self.bump();
+ Some(spanned_lt)
} else {
- ex = ExprKind::Break(None);
- }
+ None
+ };
+ let e = if self.token.can_begin_expr()
+ && !(self.token == token::OpenDelim(token::Brace)
+ && self.restrictions.contains(
+ Restrictions::RESTRICTION_NO_STRUCT_LITERAL)) {
+ Some(self.parse_expr()?)
+ } else {
+ None
+ };
+ ex = ExprKind::Break(lt, e);
hi = self.prev_span.hi;
} else if self.token.is_keyword(keywords::Let) {
// Catch this syntax error here, instead of in `check_strict_keywords`, so
}
} else {
// FIXME: Bad copy of attrs
- let restrictions = self.restrictions | Restrictions::NO_NONINLINE_MOD;
- match self.with_res(restrictions,
- |this| this.parse_item_(attrs.clone(), false, true))? {
+ let old_directory_ownership =
+ mem::replace(&mut self.directory.ownership, DirectoryOwnership::UnownedViaBlock);
+ let item = self.parse_item_(attrs.clone(), false, true)?;
+ self.directory.ownership = old_directory_ownership;
+ match item {
Some(i) => Stmt {
id: ast::DUMMY_NODE_ID,
span: mk_sp(lo, i.span.hi),
self.bump();
if in_cfg {
// This mod is in an external file. Let's go get it!
- let (m, attrs) = self.eval_src_mod(id, &outer_attrs, id_span)?;
- Ok((id, m, Some(attrs)))
+ let ModulePathSuccess { path, directory_ownership, warn } =
+ self.submod_path(id, &outer_attrs, id_span)?;
+ let (module, mut attrs) =
+ self.eval_src_mod(path, directory_ownership, id.to_string(), id_span)?;
+ if warn {
+ let attr = ast::Attribute {
+ id: attr::mk_attr_id(),
+ style: ast::AttrStyle::Outer,
+ value: ast::MetaItem {
+ name: Symbol::intern("warn_directory_ownership"),
+ node: ast::MetaItemKind::Word,
+ span: syntax_pos::DUMMY_SP,
+ },
+ is_sugared_doc: false,
+ span: syntax_pos::DUMMY_SP,
+ };
+ attr::mark_known(&attr);
+ attrs.push(attr);
+ }
+ Ok((id, module, Some(attrs)))
} else {
let placeholder = ast::Mod { inner: syntax_pos::DUMMY_SP, items: Vec::new() };
Ok((id, ItemKind::Mod(placeholder), None))
}
} else {
- let directory = self.directory.clone();
- let restrictions = self.push_directory(id, &outer_attrs);
+ let old_directory = self.directory.clone();
+ self.push_directory(id, &outer_attrs);
self.expect(&token::OpenDelim(token::Brace))?;
let mod_inner_lo = self.span.lo;
let attrs = self.parse_inner_attributes()?;
- let m = self.with_res(restrictions, |this| {
- this.parse_mod_items(&token::CloseDelim(token::Brace), mod_inner_lo)
- })?;
- self.directory = directory;
- Ok((id, ItemKind::Mod(m), Some(attrs)))
+ let module = self.parse_mod_items(&token::CloseDelim(token::Brace), mod_inner_lo)?;
+ self.directory = old_directory;
+ Ok((id, ItemKind::Mod(module), Some(attrs)))
}
}
- fn push_directory(&mut self, id: Ident, attrs: &[Attribute]) -> Restrictions {
- if let Some(path) = ::attr::first_attr_value_str_by_name(attrs, "path") {
- self.directory.push(&*path.as_str());
- self.restrictions - Restrictions::NO_NONINLINE_MOD
+ fn push_directory(&mut self, id: Ident, attrs: &[Attribute]) {
+ if let Some(path) = attr::first_attr_value_str_by_name(attrs, "path") {
+ self.directory.path.push(&*path.as_str());
+ self.directory.ownership = DirectoryOwnership::Owned;
} else {
- self.directory.push(&*id.name.as_str());
- self.restrictions
+ self.directory.path.push(&*id.name.as_str());
}
}
pub fn submod_path_from_attr(attrs: &[ast::Attribute], dir_path: &Path) -> Option<PathBuf> {
- ::attr::first_attr_value_str_by_name(attrs, "path").map(|d| dir_path.join(&*d.as_str()))
+ attr::first_attr_value_str_by_name(attrs, "path").map(|d| dir_path.join(&*d.as_str()))
}
/// Returns either a path to a module, or .
let secondary_exists = codemap.file_exists(&secondary_path);
let result = match (default_exists, secondary_exists) {
- (true, false) => Ok(ModulePathSuccess { path: default_path, owns_directory: false }),
- (false, true) => Ok(ModulePathSuccess { path: secondary_path, owns_directory: true }),
+ (true, false) => Ok(ModulePathSuccess {
+ path: default_path,
+ directory_ownership: DirectoryOwnership::UnownedViaMod(false),
+ warn: false,
+ }),
+ (false, true) => Ok(ModulePathSuccess {
+ path: secondary_path,
+ directory_ownership: DirectoryOwnership::Owned,
+ warn: false,
+ }),
(false, false) => Err(ModulePathError {
err_msg: format!("file not found for module `{}`", mod_name),
help_msg: format!("name the file either {} or {} inside the directory {:?}",
id: ast::Ident,
outer_attrs: &[ast::Attribute],
id_sp: Span) -> PResult<'a, ModulePathSuccess> {
- if let Some(p) = Parser::submod_path_from_attr(outer_attrs, &self.directory) {
- return Ok(ModulePathSuccess { path: p, owns_directory: true });
+ if let Some(path) = Parser::submod_path_from_attr(outer_attrs, &self.directory.path) {
+ return Ok(ModulePathSuccess {
+ directory_ownership: match path.file_name().and_then(|s| s.to_str()) {
+ Some("mod.rs") => DirectoryOwnership::Owned,
+ _ => DirectoryOwnership::UnownedViaMod(true),
+ },
+ path: path,
+ warn: false,
+ });
}
- let paths = Parser::default_submod_path(id, &self.directory, self.sess.codemap());
+ let paths = Parser::default_submod_path(id, &self.directory.path, self.sess.codemap());
- if self.restrictions.contains(Restrictions::NO_NONINLINE_MOD) {
+ if let DirectoryOwnership::UnownedViaBlock = self.directory.ownership {
let msg =
"Cannot declare a non-inline module inside a block unless it has a path attribute";
let mut err = self.diagnostic().struct_span_err(id_sp, msg);
err.span_note(id_sp, &msg);
}
return Err(err);
- } else if !self.owns_directory {
+ } else if let DirectoryOwnership::UnownedViaMod(warn) = self.directory.ownership {
+ if warn {
+ if let Ok(result) = paths.result {
+ return Ok(ModulePathSuccess { warn: true, ..result });
+ }
+ }
let mut err = self.diagnostic().struct_span_err(id_sp,
"cannot declare a new module at this location");
- let this_module = match self.directory.file_name() {
+ let this_module = match self.directory.path.file_name() {
Some(file_name) => file_name.to_str().unwrap().to_owned(),
None => self.root_module_name.as_ref().unwrap().clone(),
};
&format!("... or maybe `use` the module `{}` instead \
of possibly redeclaring it",
paths.name));
- }
- return Err(err);
+ return Err(err);
+ } else {
+ return Err(err);
+ };
}
match paths.result {
/// Read a module from a source file.
fn eval_src_mod(&mut self,
- id: ast::Ident,
- outer_attrs: &[ast::Attribute],
+ path: PathBuf,
+ directory_ownership: DirectoryOwnership,
+ name: String,
id_sp: Span)
-> PResult<'a, (ast::ItemKind, Vec<ast::Attribute> )> {
- let ModulePathSuccess { path, owns_directory } = self.submod_path(id,
- outer_attrs,
- id_sp)?;
-
- self.eval_src_mod_from_path(path,
- owns_directory,
- id.to_string(),
- id_sp)
- }
-
- fn eval_src_mod_from_path(&mut self,
- path: PathBuf,
- owns_directory: bool,
- name: String,
- id_sp: Span) -> PResult<'a, (ast::ItemKind, Vec<ast::Attribute> )> {
let mut included_mod_stack = self.sess.included_mod_stack.borrow_mut();
if let Some(i) = included_mod_stack.iter().position(|p| *p == path) {
let mut err = String::from("circular modules: ");
included_mod_stack.push(path.clone());
drop(included_mod_stack);
- let mut p0 = new_sub_parser_from_file(self.sess, &path, owns_directory, Some(name), id_sp);
+ let mut p0 =
+ new_sub_parser_from_file(self.sess, &path, directory_ownership, Some(name), id_sp);
let mod_inner_lo = p0.span.lo;
let mod_attrs = p0.parse_inner_attributes()?;
let m0 = p0.parse_mod_items(&token::Eof, mod_inner_lo)?;
ast::ExprKind::Path(Some(ref qself), ref path) => {
try!(self.print_qpath(path, qself, true))
}
- ast::ExprKind::Break(opt_ident) => {
+ ast::ExprKind::Break(opt_ident, ref opt_expr) => {
try!(word(&mut self.s, "break"));
try!(space(&mut self.s));
if let Some(ident) = opt_ident {
try!(self.print_ident(ident.node));
try!(space(&mut self.s));
}
+ if let Some(ref expr) = *opt_expr {
+ try!(self.print_expr(expr));
+ try!(space(&mut self.s));
+ }
}
ast::ExprKind::Continue(opt_ident) => {
try!(word(&mut self.s, "continue"));
}
visitor.visit_path(path, expression.id)
}
- ExprKind::Break(ref opt_sp_ident) | ExprKind::Continue(ref opt_sp_ident) => {
+ ExprKind::Break(ref opt_sp_ident, ref opt_expr) => {
+ walk_opt_sp_ident(visitor, opt_sp_ident);
+ walk_list!(visitor, visit_expr, opt_expr);
+ }
+ ExprKind::Continue(ref opt_sp_ident) => {
walk_opt_sp_ident(visitor, opt_sp_ident);
}
ExprKind::Ret(ref optional_expression) => {
--- /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.
+
+// no-prefer-dynamic
+
+#![crate_type="metadata"]
+
+pub struct Foo {
+ pub field: i32,
+}
--- /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.
+
+#![crate_type="rlib"]
+
+pub struct Foo {
+ pub field: i32,
+}
let _ = cf as *const Bar;
//~^ ERROR casting
//~^^ NOTE vtable kinds
+
+ vec![0.0].iter().map(|s| s as f32).collect::<Vec<f32>>();
+ //~^ ERROR casting `&{float}` as `f32` is invalid
+ //~| NOTE cannot cast `&{float}` as `f32`
+ //~| NOTE did you mean `*s`?
}
--- /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.
+
+// error-pattern: cannot declare a new module at this location
+// error-pattern: will become a hard error
+// error-pattern: compilation successful
+
+#![feature(rustc_attrs)]
+
+#[path="mod_file_not_owning_aux3.rs"]
+mod foo;
+
+#[rustc_error]
+fn main() {}
--- /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.
+
+// Test that macro-expanded non-inline modules behave correctly
+
+macro_rules! mod_decl {
+ ($i:ident) => { mod $i; }
+}
+
+mod macro_expanded_mod_helper {
+ mod_decl!(foo); // This should search in the folder `macro_expanded_mod_helper`
+}
+
+fn main() {
+ mod_decl!(foo); //~ ERROR Cannot declare a non-inline module inside a block
+}
--- /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.
+
+// ignore-test
--- /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.
+
+// ignore-test
+
+mod_decl!(bar);
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// error-pattern: cannot declare a new module at this location
+
+mod mod_file_not_owning_aux1;
+
+fn main() {}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// ignore-test this is not a test
+
+macro_rules! m {
+ () => { mod mod_file_not_owning_aux2; }
+}
+m!();
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// ignore-test this is not a test
--- /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.
+
+// ignore-test this is not a test
+
+mod mod_file_not_owning_aux2;
--- /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.
+
+// Test that non-inline modules are not allowed inside blocks.
+
+fn main() {
+ mod foo; //~ ERROR Cannot declare a non-inline module inside a block
+}
--- /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.
+
+// error-pattern: cannot declare a new module at this location
+
+// This is not a directory owner since the file name is not "mod.rs".
+#[path = "mod_file_not_owning_aux1.rs"]
+mod foo;
--- /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.
+
+fn main() {
+ loop {
+ break 123; //~ ERROR `break` with a value is experimental
+ }
+}
--- /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.
+
+#![feature(loop_break_value)]
+#![feature(never_type)]
+
+fn main() {
+ let val: ! = loop { break break; };
+ //~^ ERROR mismatched types
+
+ loop {
+ if true {
+ break "asdf";
+ } else {
+ break 123; //~ ERROR mismatched types
+ }
+ };
+
+ let _: i32 = loop {
+ break "asdf"; //~ ERROR mismatched types
+ };
+
+ let _: i32 = 'outer_loop: loop {
+ loop {
+ break 'outer_loop "nope"; //~ ERROR mismatched types
+ break "ok";
+ };
+ };
+
+ 'while_loop: while true {
+ break;
+ break (); //~ ERROR `break` with value from a `while` loop
+ loop {
+ break 'while_loop 123;
+ //~^ ERROR `break` with value from a `while` loop
+ //~| ERROR mismatched types
+ break 456;
+ break 789;
+ };
+ }
+
+ 'while_let_loop: while let Some(_) = Some(()) {
+ if break () { //~ ERROR `break` with value from a `while let` loop
+ break;
+ break None;
+ //~^ ERROR `break` with value from a `while let` loop
+ //~| ERROR mismatched types
+ }
+ loop {
+ break 'while_let_loop "nope";
+ //~^ ERROR `break` with value from a `while let` loop
+ //~| ERROR mismatched types
+ break 33;
+ };
+ }
+
+ 'for_loop: for _ in &[1,2,3] {
+ break (); //~ ERROR `break` with value from a `for` loop
+ break [()];
+ //~^ ERROR `break` with value from a `for` loop
+ //~| ERROR mismatched types
+ loop {
+ break Some(3);
+ break 'for_loop Some(17);
+ //~^ ERROR `break` with value from a `for` loop
+ //~| ERROR mismatched types
+ };
+ }
+
+ let _: i32 = 'a: loop {
+ let _: () = 'b: loop {
+ break ('c: loop {
+ break;
+ break 'c 123; //~ ERROR mismatched types
+ });
+ break 'a 123;
+ };
+ };
+
+ loop {
+ break (break, break); //~ ERROR mismatched types
+ };
+
+ loop {
+ break;
+ break 2; //~ ERROR mismatched types
+ };
+
+ loop {
+ break 2;
+ break; //~ ERROR mismatched types
+ break 4;
+ };
+}
+++ /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.
-
-// Test that macro-expanded non-inline modules behave correctly
-
-macro_rules! mod_decl {
- ($i:ident) => { mod $i; }
-}
-
-mod macro_expanded_mod_helper {
- mod_decl!(foo); // This should search in the folder `macro_expanded_mod_helper`
-}
-
-fn main() {
- mod_decl!(foo); //~ ERROR Cannot declare a non-inline module inside a block
-}
+++ /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.
-
-// ignore-test
+++ /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.
-
-// ignore-test
-
-mod_decl!(bar);
+++ /dev/null
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// compile-flags: -Z parse-only
-
-// error-pattern: cannot declare a new module at this location
-
-mod mod_file_not_owning_aux1;
-
-fn main() {}
+++ /dev/null
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// ignore-test this is not a test
-
-mod mod_file_not_owning_aux2;
+++ /dev/null
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// ignore-test this is not a test
+++ /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.
-
-// Test that non-inline modules are not allowed inside blocks.
-
-fn main() {
- mod foo; //~ ERROR Cannot declare a non-inline module inside a block
-}
--- /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.
+
+// aux-build:rmeta_rlib.rs
+// no-prefer-dynamic
+// must-compile-successfully
+
+// Check that building a metadata crate works with a dependent, rlib crate.
+// This is a cfail test since there is no executable to run.
+
+#![crate_type="metadata"]
+
+extern crate rmeta_rlib;
+use rmeta_rlib::Foo;
+
+pub fn main() {
+ let _ = Foo { field: 42 };
+}
--- /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.
+
+// aux-build:rmeta_meta.rs
+// no-prefer-dynamic
+// must-compile-successfully
+
+// Check that building a metadata crate works with a dependent, metadata-only
+// crate.
+// This is a cfail test since there is no executable to run.
+
+#![crate_type="metadata"]
+
+extern crate rmeta_meta;
+use rmeta_meta::Foo;
+
+pub fn main() {
+ let _ = Foo { field: 42 };
+}
--- /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.
+
+// no-prefer-dynamic
+
+// Check that building a metadata crate finds an error.
+
+#![crate_type="metadata"]
+
+fn main() {
+ let _ = Foo; //~ ERROR unresolved name `Foo`
+}
--- /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.
+
+// aux-build:rmeta_meta.rs
+// no-prefer-dynamic
+// error-pattern: crate `rmeta_meta` required to be available in rlib, but it was not available
+
+// Check that building a non-metadata crate fails if a dependent crate is
+// metadata-only.
+
+extern crate rmeta_meta;
+use rmeta_meta::Foo;
+
+fn main() {
+ let _ = Foo { field: 42 };
+}
--- /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.
+
+// aux-build:rmeta_meta.rs
+// no-prefer-dynamic
+
+// Check that building a metadata crate finds an error with a dependent,
+// metadata-only crate.
+
+#![crate_type="metadata"]
+
+extern crate rmeta_meta;
+use rmeta_meta::Foo;
+
+fn main() {
+ let _ = Foo { field2: 42 }; //~ ERROR struct `rmeta_meta::Foo` has no field named `field2`
+}
--- /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.
+
+
+// This test case tests the incremental compilation hash (ICH) implementation
+// for struct constructor expressions.
+
+// The general pattern followed here is: Change one thing between rev1 and rev2
+// and make sure that the hash has changed, then change nothing between rev2 and
+// rev3 and make sure that the hash has not changed.
+
+// must-compile-successfully
+// revisions: cfail1 cfail2 cfail3
+// compile-flags: -Z query-dep-graph
+
+#![allow(warnings)]
+#![feature(rustc_attrs)]
+#![crate_type="rlib"]
+
+
+struct RegularStruct {
+ x: i32,
+ y: i64,
+ z: i16,
+}
+
+// Change field value (regular struct) -----------------------------------------
+#[cfg(cfail1)]
+fn change_field_value_regular_struct() -> RegularStruct {
+ RegularStruct {
+ x: 0,
+ y: 1,
+ z: 2,
+ }
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+fn change_field_value_regular_struct() -> RegularStruct {
+ RegularStruct {
+ x: 0,
+ y: 2,
+ z: 2,
+ }
+}
+
+
+
+// Change field order (regular struct) -----------------------------------------
+#[cfg(cfail1)]
+fn change_field_order_regular_struct() -> RegularStruct {
+ RegularStruct {
+ x: 3,
+ y: 4,
+ z: 5,
+ }
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+fn change_field_order_regular_struct() -> RegularStruct {
+ RegularStruct {
+ y: 4,
+ x: 3,
+ z: 5,
+ }
+}
+
+
+
+// Add field (regular struct) --------------------------------------------------
+#[cfg(cfail1)]
+fn add_field_regular_struct() -> RegularStruct {
+ let struct1 = RegularStruct {
+ x: 3,
+ y: 4,
+ z: 5,
+ };
+
+ RegularStruct {
+ x: 7,
+ .. struct1
+ }
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+fn add_field_regular_struct() -> RegularStruct {
+ let struct1 = RegularStruct {
+ x: 3,
+ y: 4,
+ z: 5,
+ };
+
+ RegularStruct {
+ x: 7,
+ y: 8,
+ .. struct1
+ }
+}
+
+
+
+// Change field label (regular struct) -----------------------------------------
+#[cfg(cfail1)]
+fn change_field_label_regular_struct() -> RegularStruct {
+ let struct1 = RegularStruct {
+ x: 3,
+ y: 4,
+ z: 5,
+ };
+
+ RegularStruct {
+ x: 7,
+ y: 9,
+ .. struct1
+ }
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+fn change_field_label_regular_struct() -> RegularStruct {
+ let struct1 = RegularStruct {
+ x: 3,
+ y: 4,
+ z: 5,
+ };
+
+ RegularStruct {
+ x: 7,
+ z: 9,
+ .. struct1
+ }
+}
+
+
+
+struct RegularStruct2 {
+ x: i8,
+ y: i8,
+ z: i8,
+}
+
+// Change constructor path (regular struct) ------------------------------------
+#[cfg(cfail1)]
+fn change_constructor_path_regular_struct() {
+ let _ = RegularStruct {
+ x: 0,
+ y: 1,
+ z: 2,
+ };
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+fn change_constructor_path_regular_struct() {
+ let _ = RegularStruct2 {
+ x: 0,
+ y: 1,
+ z: 2,
+ };
+}
+
+
+
+// Change constructor path indirectly (regular struct) -------------------------
+mod change_constructor_path_indirectly_regular_struct {
+ #[cfg(cfail1)]
+ use super::RegularStruct as Struct;
+ #[cfg(not(cfail1))]
+ use super::RegularStruct2 as Struct;
+
+ fn function() -> Struct {
+ Struct {
+ x: 0,
+ y: 1,
+ z: 2,
+ }
+ }
+}
+
+
+
+struct TupleStruct(i32, i64, i16);
+
+// Change field value (tuple struct) -------------------------------------------
+#[cfg(cfail1)]
+fn change_field_value_tuple_struct() -> TupleStruct {
+ TupleStruct(0, 1, 2)
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+fn change_field_value_tuple_struct() -> TupleStruct {
+ TupleStruct(0, 1, 3)
+}
+
+
+
+struct TupleStruct2(u16, u16, u16);
+
+// Change constructor path (tuple struct) --------------------------------------
+#[cfg(cfail1)]
+fn change_constructor_path_tuple_struct() {
+ let _ = TupleStruct(0, 1, 2);
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+fn change_constructor_path_tuple_struct() {
+ let _ = TupleStruct2(0, 1, 2);
+}
+
+
+
+// Change constructor path indirectly (tuple struct) ---------------------------
+mod change_constructor_path_indirectly_tuple_struct {
+ #[cfg(cfail1)]
+ use super::TupleStruct as Struct;
+ #[cfg(not(cfail1))]
+ use super::TupleStruct2 as Struct;
+
+ fn function() -> Struct {
+ Struct(0, 1, 2)
+ }
+}
// ignore-test: this is an auxiliary file for circular-modules-main.rs
+#[path = "circular_modules_main.rs"]
mod circular_modules_main;
pub fn say_hello() {
--- /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.
+
+// This test case tests whether we can handle code bases that contain a high
+// number of closures, something that needs special handling in the MingGW
+// toolchain.
+// See https://github.com/rust-lang/rust/issues/34793 for more information.
+
+// Make sure we don't optimize anything away:
+// compile-flags: -C no-prepopulate-passes
+
+// Expand something exponentially
+macro_rules! go_bacterial {
+ ($mac:ident) => ($mac!());
+ ($mac:ident 1 $($t:tt)*) => (
+ go_bacterial!($mac $($t)*);
+ go_bacterial!($mac $($t)*);
+ )
+}
+
+macro_rules! mk_closure {
+ () => ((move || {})())
+}
+
+macro_rules! mk_fn {
+ () => {
+ {
+ fn function() {
+ // Make 16 closures
+ go_bacterial!(mk_closure 1 1 1 1);
+ }
+ let _ = function();
+ }
+ }
+}
+
+fn main() {
+ // Make 2^12 functions, each containing 16 closures,
+ // resulting in 2^16 closures overall.
+ go_bacterial!(mk_fn 1 1 1 1 1 1 1 1 1 1 1 1);
+}
--- /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.
+
+// no-prefer-dynamic
+
+#![crate_type="rlib"]
+#![crate_name="rmeta_aux"]
+
+pub struct Foo {
+ pub field: i32,
+}
--- /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.
+
+// no-prefer-dynamic
+
+#![crate_type="metadata"]
+#![crate_name="rmeta_aux"]
+
+pub struct Foo {
+ pub field2: i32,
+}
--- /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.
+
+fn gimme_a_raw_pointer<T>(_: *const T) { }
+
+fn test<T>(t: T) { }
+
+fn main() {
+ // Clearly `pointer` must be of type `*const ()`.
+ let pointer = &() as *const _;
+ gimme_a_raw_pointer(pointer);
+
+ let t = test as fn (i32);
+ t(0i32);
+}
+
--- /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.
+
+#![feature(loop_break_value)]
+#![feature(never_type)]
+
+#[allow(unused)]
+fn never_returns() {
+ loop {
+ break loop {};
+ }
+}
+
+pub fn main() {
+ let value = 'outer: loop {
+ if 1 == 1 {
+ break 13;
+ } else {
+ let _never: ! = loop {
+ break loop {
+ break 'outer panic!();
+ }
+ };
+ }
+ };
+ assert_eq!(value, 13);
+
+ let x = [1, 3u32, 5];
+ let y = [17];
+ let z = [];
+ let coerced: &[_] = loop {
+ match 2 {
+ 1 => break &x,
+ 2 => break &y,
+ 3 => break &z,
+ _ => (),
+ }
+ };
+ assert_eq!(coerced, &[17u32]);
+
+ let trait_unified = loop {
+ break if true {
+ break Default::default()
+ } else {
+ break [13, 14]
+ };
+ };
+ assert_eq!(trait_unified, [0, 0]);
+
+ let trait_unified_2 = loop {
+ if false {
+ break [String::from("Hello")]
+ } else {
+ break Default::default()
+ };
+ };
+ assert_eq!(trait_unified_2, [""]);
+
+ let trait_unified_3 = loop {
+ break if false {
+ break [String::from("Hello")]
+ } else {
+ ["Yes".into()]
+ };
+ };
+ assert_eq!(trait_unified_3, ["Yes"]);
+
+ let regular_break = loop {
+ if true {
+ break;
+ } else {
+ break break Default::default();
+ }
+ };
+ assert_eq!(regular_break, ());
+
+ let regular_break_2 = loop {
+ if true {
+ break Default::default();
+ } else {
+ break;
+ }
+ };
+ assert_eq!(regular_break_2, ());
+
+ let regular_break_3 = loop {
+ break if true {
+ Default::default()
+ } else {
+ break;
+ }
+ };
+ assert_eq!(regular_break_3, ());
+
+ let regular_break_4 = loop {
+ break ();
+ break;
+ };
+ assert_eq!(regular_break_4, ());
+
+ let regular_break_5 = loop {
+ break;
+ break ();
+ };
+ assert_eq!(regular_break_5, ());
+
+ let nested_break_value = 'outer2: loop {
+ let _a: u32 = 'inner: loop {
+ if true {
+ break 'outer2 "hello";
+ } else {
+ break 'inner 17;
+ }
+ };
+ panic!();
+ };
+ assert_eq!(nested_break_value, "hello");
+
+ let break_from_while_cond = loop {
+ while break {
+ panic!();
+ }
+ break 123;
+ };
+ assert_eq!(break_from_while_cond, 123);
+}
+++ /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.
-
-// This test case tests whether we can handle code bases that contain a high
-// number of closures, something that needs special handling in the MingGW
-// toolchain.
-// See https://github.com/rust-lang/rust/issues/34793 for more information.
-
-// Expand something exponentially
-macro_rules! go_bacterial {
- ($mac:ident) => ($mac!());
- ($mac:ident 1 $($t:tt)*) => (
- go_bacterial!($mac $($t)*);
- go_bacterial!($mac $($t)*);
- )
-}
-
-macro_rules! mk_closure {
- () => ({
- let c = |a: u32| a + 4;
- let _ = c(2);
- })
-}
-
-macro_rules! mk_fn {
- () => {
- {
- fn function() {
- // Make 16 closures
- go_bacterial!(mk_closure 1 1 1 1);
- }
- let _ = function();
- }
- }
-}
-
-fn main() {
- // Make 2^12 functions, each containing 16 closures,
- // resulting in 2^16 closures overall.
- go_bacterial!(mk_fn 1 1 1 1 1 1 1 1 1 1 1 1);
-}
--- /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.
+
+// Test that using rlibs and rmeta dep crates work together. Specifically, that
+// there can be both an rmeta and an rlib file and rustc will prefer the rlib.
+
+// aux-build:rmeta_rmeta.rs
+// aux-build:rmeta_rlib.rs
+
+extern crate rmeta_aux;
+use rmeta_aux::Foo;
+
+pub fn main() {
+ let _ = Foo { field: 42 };
+}
--- /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