From 9fd075f5af12afe91a6be7398cfc85b2903c28bb Mon Sep 17 00:00:00 2001
From: Alex Crichton
Date: Thu, 5 Jun 2014 10:07:19 -0700
Subject: [PATCH 01/16] rustc: Encode argument names for traits
This ensures that rustdoc can properly document inlined traits across crates.
Closes #14670
---
src/librustc/metadata/encoder.rs | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs
index 2cc06f7a32dd..e2d0a858d42b 100644
--- a/src/librustc/metadata/encoder.rs
+++ b/src/librustc/metadata/encoder.rs
@@ -1196,6 +1196,7 @@ fn encode_info_for_item(ecx: &EncodeContext,
&Required(ref tm) => {
encode_attributes(ebml_w, tm.attrs.as_slice());
encode_method_sort(ebml_w, 'r');
+ encode_method_argument_names(ebml_w, &*tm.decl);
}
&Provided(m) => {
@@ -1210,6 +1211,7 @@ fn encode_info_for_item(ecx: &EncodeContext,
encode_method_sort(ebml_w, 'p');
encode_inlined_item(ecx, ebml_w,
IIMethodRef(def_id, true, m));
+ encode_method_argument_names(ebml_w, &*m.decl);
}
}
From f35328caed68528380cf5f19e4c04eba70f03638 Mon Sep 17 00:00:00 2001
From: Alex Crichton
Date: Thu, 5 Jun 2014 12:23:34 -0700
Subject: [PATCH 02/16] rustc: Avoid UB with signed division/remainder
Division and remainder by 0 are undefined behavior, and are detected at runtime.
This commit adds support for ensuring that MIN / -1 is also checked for at
runtime, as this would cause signed overflow, or undefined behvaior.
Closes #8460
---
src/librustc/middle/trans/base.rs | 83 +++++++++++++++++++++++--------
src/librustc/middle/trans/expr.rs | 8 +--
src/test/run-pass/issue-8460.rs | 35 +++++++++++++
3 files changed, 102 insertions(+), 24 deletions(-)
create mode 100644 src/test/run-pass/issue-8460.rs
diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs
index 96d059c2f84c..9be07eaaca93 100644
--- a/src/librustc/middle/trans/base.rs
+++ b/src/librustc/middle/trans/base.rs
@@ -80,6 +80,7 @@ use libc::{c_uint, uint64_t};
use std::c_str::ToCStr;
use std::cell::{Cell, RefCell};
use std::rc::Rc;
+use std::{i8, i16, i32, i64};
use syntax::abi::{X86, X86_64, Arm, Mips, Rust, RustIntrinsic};
use syntax::ast_util::{local_def, is_local};
use syntax::attr::AttrMetaMethods;
@@ -777,35 +778,77 @@ pub fn cast_shift_rhs(op: ast::BinOp,
}
}
-pub fn fail_if_zero<'a>(
+pub fn fail_if_zero_or_overflows<'a>(
cx: &'a Block<'a>,
span: Span,
divrem: ast::BinOp,
+ lhs: ValueRef,
rhs: ValueRef,
rhs_t: ty::t)
-> &'a Block<'a> {
- let text = if divrem == ast::BiDiv {
- "attempted to divide by zero"
+ let (zero_text, overflow_text) = if divrem == ast::BiDiv {
+ ("attempted to divide by zero",
+ "attempted to divide with overflow")
} else {
- "attempted remainder with a divisor of zero"
+ ("attempted remainder with a divisor of zero",
+ "attempted remainder with overflow")
};
- let is_zero = match ty::get(rhs_t).sty {
- ty::ty_int(t) => {
- let zero = C_integral(Type::int_from_ty(cx.ccx(), t), 0u64, false);
- ICmp(cx, lib::llvm::IntEQ, rhs, zero)
- }
- ty::ty_uint(t) => {
- let zero = C_integral(Type::uint_from_ty(cx.ccx(), t), 0u64, false);
- ICmp(cx, lib::llvm::IntEQ, rhs, zero)
- }
- _ => {
- cx.sess().bug(format!("fail-if-zero on unexpected type: {}",
- ty_to_str(cx.tcx(), rhs_t)).as_slice());
- }
+ let (is_zero, is_signed) = match ty::get(rhs_t).sty {
+ ty::ty_int(t) => {
+ let zero = C_integral(Type::int_from_ty(cx.ccx(), t), 0u64, false);
+ (ICmp(cx, lib::llvm::IntEQ, rhs, zero), true)
+ }
+ ty::ty_uint(t) => {
+ let zero = C_integral(Type::uint_from_ty(cx.ccx(), t), 0u64, false);
+ (ICmp(cx, lib::llvm::IntEQ, rhs, zero), false)
+ }
+ _ => {
+ cx.sess().bug(format!("fail-if-zero on unexpected type: {}",
+ ty_to_str(cx.tcx(), rhs_t)).as_slice());
+ }
};
- with_cond(cx, is_zero, |bcx| {
- controlflow::trans_fail(bcx, span, InternedString::new(text))
- })
+ let bcx = with_cond(cx, is_zero, |bcx| {
+ controlflow::trans_fail(bcx, span, InternedString::new(zero_text))
+ });
+
+ // To quote LLVM's documentation for the sdiv instruction:
+ //
+ // Division by zero leads to undefined behavior. Overflow also leads
+ // to undefined behavior; this is a rare case, but can occur, for
+ // example, by doing a 32-bit division of -2147483648 by -1.
+ //
+ // In order to avoid undefined behavior, we perform runtime checks for
+ // signed division/remainder which would trigger overflow. For unsigned
+ // integers, no action beyond checking for zero need be taken.
+ if is_signed {
+ let (llty, min) = match ty::get(rhs_t).sty {
+ ty::ty_int(t) => {
+ let llty = Type::int_from_ty(cx.ccx(), t);
+ let min = match t {
+ ast::TyI if llty == Type::i32(cx.ccx()) => i32::MIN as u64,
+ ast::TyI => i64::MIN as u64,
+ ast::TyI8 => i8::MIN as u64,
+ ast::TyI16 => i16::MIN as u64,
+ ast::TyI32 => i32::MIN as u64,
+ ast::TyI64 => i64::MIN as u64,
+ };
+ (llty, min)
+ }
+ _ => unreachable!(),
+ };
+ let minus_one = ICmp(bcx, lib::llvm::IntEQ, rhs,
+ C_integral(llty, -1, false));
+ with_cond(bcx, minus_one, |bcx| {
+ let is_min = ICmp(bcx, lib::llvm::IntEQ, lhs,
+ C_integral(llty, min, true));
+ with_cond(bcx, is_min, |bcx| {
+ controlflow::trans_fail(bcx, span,
+ InternedString::new(overflow_text))
+ })
+ })
+ } else {
+ bcx
+ }
}
pub fn trans_external_path(ccx: &CrateContext, did: ast::DefId, t: ty::t) -> ValueRef {
diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs
index d9ae9b083817..9f90de61cfeb 100644
--- a/src/librustc/middle/trans/expr.rs
+++ b/src/librustc/middle/trans/expr.rs
@@ -1297,8 +1297,8 @@ fn trans_eager_binop<'a>(
FDiv(bcx, lhs, rhs)
} else {
// Only zero-check integers; fp /0 is NaN
- bcx = base::fail_if_zero(bcx, binop_expr.span,
- op, rhs, rhs_t);
+ bcx = base::fail_if_zero_or_overflows(bcx, binop_expr.span,
+ op, lhs, rhs, rhs_t);
if is_signed {
SDiv(bcx, lhs, rhs)
} else {
@@ -1311,8 +1311,8 @@ fn trans_eager_binop<'a>(
FRem(bcx, lhs, rhs)
} else {
// Only zero-check integers; fp %0 is NaN
- bcx = base::fail_if_zero(bcx, binop_expr.span,
- op, rhs, rhs_t);
+ bcx = base::fail_if_zero_or_overflows(bcx, binop_expr.span,
+ op, lhs, rhs, rhs_t);
if is_signed {
SRem(bcx, lhs, rhs)
} else {
diff --git a/src/test/run-pass/issue-8460.rs b/src/test/run-pass/issue-8460.rs
new file mode 100644
index 000000000000..762152c92038
--- /dev/null
+++ b/src/test/run-pass/issue-8460.rs
@@ -0,0 +1,35 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 or the MIT license
+// , at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::{int, i8, i16, i32, i64};
+use std::task;
+
+fn main() {
+ assert!(task::try(proc() int::MIN / -1).is_err());
+ assert!(task::try(proc() i8::MIN / -1).is_err());
+ assert!(task::try(proc() i16::MIN / -1).is_err());
+ assert!(task::try(proc() i32::MIN / -1).is_err());
+ assert!(task::try(proc() i64::MIN / -1).is_err());
+ assert!(task::try(proc() 1i / 0).is_err());
+ assert!(task::try(proc() 1i8 / 0).is_err());
+ assert!(task::try(proc() 1i16 / 0).is_err());
+ assert!(task::try(proc() 1i32 / 0).is_err());
+ assert!(task::try(proc() 1i64 / 0).is_err());
+ assert!(task::try(proc() int::MIN % -1).is_err());
+ assert!(task::try(proc() i8::MIN % -1).is_err());
+ assert!(task::try(proc() i16::MIN % -1).is_err());
+ assert!(task::try(proc() i32::MIN % -1).is_err());
+ assert!(task::try(proc() i64::MIN % -1).is_err());
+ assert!(task::try(proc() 1i % 0).is_err());
+ assert!(task::try(proc() 1i8 % 0).is_err());
+ assert!(task::try(proc() 1i16 % 0).is_err());
+ assert!(task::try(proc() 1i32 % 0).is_err());
+ assert!(task::try(proc() 1i64 % 0).is_err());
+}
From 735e518a815bd06fa99ea343351041ba22751fe4 Mon Sep 17 00:00:00 2001
From: Luqman Aden
Date: Thu, 5 Jun 2014 18:06:33 -0400
Subject: [PATCH 03/16] librustc: Update AutoObject adjustment in writeback.
---
src/librustc/middle/typeck/check/regionck.rs | 2 +-
src/librustc/middle/typeck/check/writeback.rs | 9 +++++-
src/test/run-pass/issue-11612.rs | 30 +++++++++++++++++++
3 files changed, 39 insertions(+), 2 deletions(-)
create mode 100644 src/test/run-pass/issue-11612.rs
diff --git a/src/librustc/middle/typeck/check/regionck.rs b/src/librustc/middle/typeck/check/regionck.rs
index e1db465424af..e488a946d4a1 100644
--- a/src/librustc/middle/typeck/check/regionck.rs
+++ b/src/librustc/middle/typeck/check/regionck.rs
@@ -432,7 +432,7 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) {
// function check_cast_for_escaping_regions() in kind.rs
// explaining how it goes about doing that.
- let source_ty = rcx.fcx.expr_ty(expr);
+ let source_ty = rcx.resolve_node_type(expr.id);
constrain_regions_in_type(rcx, trait_region,
infer::RelateObjectBound(expr.span), source_ty);
}
diff --git a/src/librustc/middle/typeck/check/writeback.rs b/src/librustc/middle/typeck/check/writeback.rs
index 63dc122f7cbf..b93550384ae3 100644
--- a/src/librustc/middle/typeck/check/writeback.rs
+++ b/src/librustc/middle/typeck/check/writeback.rs
@@ -260,7 +260,14 @@ impl<'cx> WritebackCx<'cx> {
})
}
- adjustment => adjustment
+ ty::AutoObject(trait_store, bb, def_id, substs) => {
+ ty::AutoObject(
+ self.resolve(&trait_store, reason),
+ self.resolve(&bb, reason),
+ def_id,
+ self.resolve(&substs, reason)
+ )
+ }
};
debug!("Adjustments for node {}: {:?}", id, resolved_adjustment);
self.tcx().adjustments.borrow_mut().insert(
diff --git a/src/test/run-pass/issue-11612.rs b/src/test/run-pass/issue-11612.rs
new file mode 100644
index 000000000000..5fb2274a446f
--- /dev/null
+++ b/src/test/run-pass/issue-11612.rs
@@ -0,0 +1,30 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 or the MIT license
+// , at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// #11612
+// We weren't updating the auto adjustments with all the resolved
+// type information after type check.
+
+trait A {}
+
+struct B<'a, T> {
+ f: &'a T
+}
+
+impl<'a, T> A for B<'a, T> {}
+
+fn foo(_: &A) {}
+
+fn bar(b: &B) {
+ foo(b); // Coercion should work
+ foo(b as &A); // Explicit cast should work as well
+}
+
+fn main() {}
From 6a43af3f84ef97d4d0e5b55c5336a4256bd1ebb7 Mon Sep 17 00:00:00 2001
From: Michael Woerister
Date: Thu, 5 Jun 2014 10:24:34 +0200
Subject: [PATCH 04/16] Add workaround for archive reading bug in LLDB.
LLDB contains a bug that makes it crash if an archive it reads
contains a file the name of which is exactly 16 bytes long. This
bug recently has made it impossible to debug Rust applications with
LLDB because some standard libraries triggered it indirectly:
For rlibs, rustc includes the LLVM bytecode in the archive, giving
it the extension ".bc.deflate". For liballoc (for example) this
results in the 16 character filename "alloc.bc.deflate", which is
bad.
This commit replaces the ".bc.deflate" suffix with
".bytecode.deflate" which itself is already longer than 16 bytes,
thus making sure that the bug won't be run into anymore.
The bug could still be run into with 14 character filenames because
then the .o files will trigger it. However, this is much more rare
and working around it would introduce more complexity than necessary
at the moment. It can always be done later on, if the need arises.
Fixes #14356.
---
src/librustc/back/archive.rs | 2 +-
src/librustc/back/link.rs | 6 +++++-
src/librustc/back/lto.rs | 4 ++--
3 files changed, 8 insertions(+), 4 deletions(-)
diff --git a/src/librustc/back/archive.rs b/src/librustc/back/archive.rs
index 0b6540640b4c..edb0a538a03d 100644
--- a/src/librustc/back/archive.rs
+++ b/src/librustc/back/archive.rs
@@ -109,7 +109,7 @@ impl<'a> Archive<'a> {
pub fn add_rlib(&mut self, rlib: &Path, name: &str,
lto: bool) -> io::IoResult<()> {
let object = format!("{}.o", name);
- let bytecode = format!("{}.bc.deflate", name);
+ let bytecode = format!("{}.bytecode.deflate", name);
let mut ignore = vec!(bytecode.as_slice(), METADATA_FILENAME);
if lto {
ignore.push(object.as_slice());
diff --git a/src/librustc/back/link.rs b/src/librustc/back/link.rs
index 546182aac34e..b432034b81b5 100644
--- a/src/librustc/back/link.rs
+++ b/src/librustc/back/link.rs
@@ -958,8 +958,12 @@ fn link_rlib<'a>(sess: &'a Session,
// For LTO purposes, the bytecode of this library is also inserted
// into the archive.
+ // Note that we make sure that the bytecode filename in the archive is always at least
+ // 16 bytes long by adding a 16 byte extension to it. This is to work around a bug in
+ // LLDB that would cause it to crash if the name of a file in an archive was exactly
+ // 16 bytes.
let bc = obj_filename.with_extension("bc");
- let bc_deflated = obj_filename.with_extension("bc.deflate");
+ let bc_deflated = obj_filename.with_extension("bytecode.deflate");
match fs::File::open(&bc).read_to_end().and_then(|data| {
fs::File::create(&bc_deflated)
.write(match flate::deflate_bytes(data.as_slice()) {
diff --git a/src/librustc/back/lto.rs b/src/librustc/back/lto.rs
index 09dfc9189679..7449622366fc 100644
--- a/src/librustc/back/lto.rs
+++ b/src/librustc/back/lto.rs
@@ -55,10 +55,10 @@ pub fn run(sess: &session::Session, llmod: ModuleRef,
let archive = ArchiveRO::open(&path).expect("wanted an rlib");
debug!("reading {}", name);
let bc = time(sess.time_passes(),
- format!("read {}.bc.deflate", name).as_slice(),
+ format!("read {}.bytecode.deflate", name).as_slice(),
(),
|_| {
- archive.read(format!("{}.bc.deflate",
+ archive.read(format!("{}.bytecode.deflate",
name).as_slice())
});
let bc = bc.expect("missing compressed bytecode in archive!");
From 2290dbb8cc9c72e1b6b64b7325430f031e2cd87b Mon Sep 17 00:00:00 2001
From: Alex Crichton
Date: Thu, 5 Jun 2014 15:31:45 -0700
Subject: [PATCH 05/16] rustc: Avoid 16-byte filenames in rlibs
In addition to avoiding 16-byte filenames with bytecode files, this commit also
avoids 16-byte filenames with object files pulled in from native libraries.
---
src/librustc/back/archive.rs | 9 +++++++++
src/librustc/back/link.rs | 9 +++++----
2 files changed, 14 insertions(+), 4 deletions(-)
diff --git a/src/librustc/back/archive.rs b/src/librustc/back/archive.rs
index edb0a538a03d..4d921fb97dc5 100644
--- a/src/librustc/back/archive.rs
+++ b/src/librustc/back/archive.rs
@@ -166,6 +166,15 @@ impl<'a> Archive<'a> {
if filename.contains(".SYMDEF") { continue }
let filename = format!("r-{}-{}", name, filename);
+ // LLDB (as mentioned in back::link) crashes on filenames of exactly
+ // 16 bytes in length. If we're including an object file with
+ // exactly 16-bytes of characters, give it some prefix so that it's
+ // not 16 bytes.
+ let filename = if filename.len() == 16 {
+ format!("lldb-fix-{}", filename)
+ } else {
+ filename
+ };
let new_filename = file.with_filename(filename);
try!(fs::rename(file, &new_filename));
inputs.push(new_filename);
diff --git a/src/librustc/back/link.rs b/src/librustc/back/link.rs
index b432034b81b5..14369c7bbcd2 100644
--- a/src/librustc/back/link.rs
+++ b/src/librustc/back/link.rs
@@ -958,10 +958,11 @@ fn link_rlib<'a>(sess: &'a Session,
// For LTO purposes, the bytecode of this library is also inserted
// into the archive.
- // Note that we make sure that the bytecode filename in the archive is always at least
- // 16 bytes long by adding a 16 byte extension to it. This is to work around a bug in
- // LLDB that would cause it to crash if the name of a file in an archive was exactly
- // 16 bytes.
+ //
+ // Note that we make sure that the bytecode filename in the archive
+ // is never exactly 16 bytes long by adding a 16 byte extension to
+ // it. This is to work around a bug in LLDB that would cause it to
+ // crash if the name of a file in an archive was exactly 16 bytes.
let bc = obj_filename.with_extension("bc");
let bc_deflated = obj_filename.with_extension("bytecode.deflate");
match fs::File::open(&bc).read_to_end().and_then(|data| {
From 06f3f9a0c9f25c92b7362a4af6067df8902bd057 Mon Sep 17 00:00:00 2001
From: Alex Crichton
Date: Thu, 5 Jun 2014 17:20:59 -0700
Subject: [PATCH 06/16] rustdoc: Inline static documentation across crates
---
src/librustdoc/clean/inline.rs | 14 ++++++++++++
src/librustdoc/html/format.rs | 41 ++++++++++++++++------------------
src/librustdoc/html/render.rs | 5 +++--
3 files changed, 36 insertions(+), 24 deletions(-)
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index 9db9a0e7612a..e9ea3a7b304e 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -88,6 +88,10 @@ fn try_inline_def(cx: &core::DocContext,
record_extern_fqn(cx, did, clean::TypeModule);
clean::ModuleItem(build_module(cx, tcx, did))
}
+ ast::DefStatic(did, mtbl) => {
+ record_extern_fqn(cx, did, clean::TypeStatic);
+ clean::StaticItem(build_static(tcx, did, mtbl))
+ }
_ => return None,
};
let fqn = csearch::get_item_path(tcx, did);
@@ -343,3 +347,13 @@ fn build_module(cx: &core::DocContext, tcx: &ty::ctxt,
is_crate: false,
}
}
+
+fn build_static(tcx: &ty::ctxt,
+ did: ast::DefId,
+ mutable: bool) -> clean::Static {
+ clean::Static {
+ type_: ty::lookup_item_type(tcx, did).ty.clean(),
+ mutability: if mutable {clean::Mutable} else {clean::Immutable},
+ expr: "\n\n\n".to_string(), // trigger the "[definition]" links
+ }
+}
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index 51d2a67d6cbf..1706f00b70a6 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -35,6 +35,8 @@ pub struct VisSpace(pub Option);
pub struct FnStyleSpace(pub ast::FnStyle);
/// Wrapper struct for properly emitting a method declaration.
pub struct Method<'a>(pub &'a clean::SelfTy, pub &'a clean::FnDecl);
+/// Similar to VisSpace, but used for mutability
+pub struct MutableSpace(pub clean::Mutability);
impl VisSpace {
pub fn get(&self) -> Option {
@@ -438,24 +440,14 @@ impl fmt::Show for clean::Type {
clean::Unique(ref t) => write!(f, "~{}", **t),
clean::Managed(ref t) => write!(f, "@{}", **t),
clean::RawPointer(m, ref t) => {
- write!(f, "*{}{}",
- match m {
- clean::Mutable => "mut ",
- clean::Immutable => "",
- }, **t)
+ write!(f, "*{}{}", MutableSpace(m), **t)
}
clean::BorrowedRef{ lifetime: ref l, mutability, type_: ref ty} => {
let lt = match *l {
Some(ref l) => format!("{} ", *l),
_ => "".to_string(),
};
- write!(f, "&{}{}{}",
- lt,
- match mutability {
- clean::Mutable => "mut ",
- clean::Immutable => "",
- },
- **ty)
+ write!(f, "&{}{}{}", lt, MutableSpace(mutability), **ty)
}
}
}
@@ -494,17 +486,13 @@ impl<'a> fmt::Show for Method<'a> {
clean::SelfStatic => {},
clean::SelfValue => args.push_str("self"),
clean::SelfOwned => args.push_str("~self"),
- clean::SelfBorrowed(Some(ref lt), clean::Immutable) => {
- args.push_str(format!("&{} self", *lt).as_slice());
+ clean::SelfBorrowed(Some(ref lt), mtbl) => {
+ args.push_str(format!("&{} {}self", *lt,
+ MutableSpace(mtbl)).as_slice());
}
- clean::SelfBorrowed(Some(ref lt), clean::Mutable) => {
- args.push_str(format!("&{} mut self", *lt).as_slice());
- }
- clean::SelfBorrowed(None, clean::Mutable) => {
- args.push_str("&mut self");
- }
- clean::SelfBorrowed(None, clean::Immutable) => {
- args.push_str("&self");
+ clean::SelfBorrowed(None, mtbl) => {
+ args.push_str(format!("&{}self",
+ MutableSpace(mtbl)).as_slice());
}
}
for (i, input) in d.inputs.values.iter().enumerate() {
@@ -605,3 +593,12 @@ impl fmt::Show for clean::ViewListIdent {
}
}
}
+
+impl fmt::Show for MutableSpace {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match *self {
+ MutableSpace(clean::Immutable) => Ok(()),
+ MutableSpace(clean::Mutable) => write!(f, "mut "),
+ }
+ }
+}
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index 4ef3297912f9..086232104e36 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -51,7 +51,7 @@ use rustc::util::nodemap::NodeSet;
use clean;
use doctree;
use fold::DocFolder;
-use html::format::{VisSpace, Method, FnStyleSpace};
+use html::format::{VisSpace, Method, FnStyleSpace, MutableSpace};
use html::highlight;
use html::item_type::{ItemType, shortty};
use html::item_type;
@@ -1441,11 +1441,12 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context,
try!(write!(w, "
- {}static {}: {}{} |
+ {}static {}{}: {}{} |
{} |
",
VisSpace(myitem.visibility),
+ MutableSpace(s.mutability),
*myitem.name.get_ref(),
s.type_,
Initializer(s.expr.as_slice(), Item { cx: cx, item: myitem }),
From 1bc29924dc8f88c2c118b688f25ffa7c6a212276 Mon Sep 17 00:00:00 2001
From: fort
Date: Thu, 5 Jun 2014 18:13:30 -0700
Subject: [PATCH 07/16] Remove reference to ~str in documentation
---
src/libstd/macros.rs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs
index 0b9fc250636f..b555c966d2d0 100644
--- a/src/libstd/macros.rs
+++ b/src/libstd/macros.rs
@@ -212,7 +212,7 @@ macro_rules! unimplemented(
() => (fail!("not yet implemented"))
)
-/// Use the syntax described in `std::fmt` to create a value of type `~str`.
+/// Use the syntax described in `std::fmt` to create a value of type `String`.
/// See `std::fmt` for more information.
///
/// # Example
From 1bde6e3fcb32ca00cf8a8dfa0977e47f7f4a77bf Mon Sep 17 00:00:00 2001
From: Aaron Turon
Date: Thu, 5 Jun 2014 23:18:51 -0700
Subject: [PATCH 08/16] Rename Iterator::len to count
This commit carries out the request from issue #14678:
> The method `Iterator::len()` is surprising, as all the other uses of
> `len()` do not consume the value. `len()` would make more sense to be
> called `count()`, but that would collide with the current
> `Iterator::count(|T| -> bool) -> unit` method. That method, however, is
> a bit redundant, and can be easily replaced with
> `iter.filter(|x| x < 5).count()`.
> After this change, we could then define the `len()` method
> on `iter::ExactSize`.
Closes #14678.
[breaking-change]
---
src/compiletest/runtest.rs | 2 +-
src/libcollections/bitv.rs | 8 ++---
src/libcollections/dlist.rs | 8 ++---
src/libcollections/slice.rs | 2 +-
src/libcollections/smallintmap.rs | 2 +-
src/libcollections/str.rs | 34 +++++++++---------
src/libcollections/vec.rs | 14 ++++----
src/libcore/iter.rs | 48 ++++++++++++-------------
src/libcore/slice.rs | 3 +-
src/libcore/str.rs | 3 +-
src/librustc/metadata/encoder.rs | 2 +-
src/librustc/middle/entry.rs | 2 +-
src/librustc/middle/typeck/astconv.rs | 6 ++--
src/librustc/middle/typeck/check/mod.rs | 4 +--
src/librustc/util/ppaux.rs | 2 +-
src/librustdoc/html/render.rs | 2 +-
src/librustdoc/html/toc.rs | 2 +-
src/libstd/num/strconv.rs | 1 -
src/libstd/rand/mod.rs | 12 +++----
src/libstd/rt/backtrace.rs | 2 +-
src/test/run-pass/issue-13204.rs | 2 +-
21 files changed, 78 insertions(+), 83 deletions(-)
diff --git a/src/compiletest/runtest.rs b/src/compiletest/runtest.rs
index 10428244b711..8da984a414bd 100644
--- a/src/compiletest/runtest.rs
+++ b/src/compiletest/runtest.rs
@@ -1545,7 +1545,7 @@ fn disassemble_extract(config: &Config, _props: &TestProps,
fn count_extracted_lines(p: &Path) -> uint {
let x = File::open(&p.with_extension("ll")).read_to_end().unwrap();
let x = str::from_utf8(x.as_slice()).unwrap();
- x.lines().len()
+ x.lines().count()
}
diff --git a/src/libcollections/bitv.rs b/src/libcollections/bitv.rs
index 11c777034fe6..58f081b25e3e 100644
--- a/src/libcollections/bitv.rs
+++ b/src/libcollections/bitv.rs
@@ -241,17 +241,17 @@ enum Op {Union, Intersect, Assign, Difference}
/// bv.set(5, true);
/// bv.set(7, true);
/// println!("{}", bv.to_str());
-/// println!("total bits set to true: {}", bv.iter().count(|x| x));
+/// println!("total bits set to true: {}", bv.iter().filter(|x| *x).count());
///
/// // flip all values in bitvector, producing non-primes less than 10
/// bv.negate();
/// println!("{}", bv.to_str());
-/// println!("total bits set to true: {}", bv.iter().count(|x| x));
+/// println!("total bits set to true: {}", bv.iter().filter(|x| *x).count());
///
/// // reset bitvector to empty
/// bv.clear();
/// println!("{}", bv.to_str());
-/// println!("total bits set to true: {}", bv.iter().count(|x| x));
+/// println!("total bits set to true: {}", bv.iter().filter(|x| *x).count());
/// ```
#[deriving(Clone)]
pub struct Bitv {
@@ -461,7 +461,7 @@ impl Bitv {
/// bv.set(5, true);
/// bv.set(8, true);
/// // Count bits set to 1; result should be 5
- /// println!("{}", bv.iter().count(|x| x));
+ /// println!("{}", bv.iter().filter(|x| *x).count());
/// ```
#[inline]
pub fn iter<'a>(&'a self) -> Bits<'a> {
diff --git a/src/libcollections/dlist.rs b/src/libcollections/dlist.rs
index 8e3a49eecf33..94c617b58e8d 100644
--- a/src/libcollections/dlist.rs
+++ b/src/libcollections/dlist.rs
@@ -1131,7 +1131,7 @@ mod tests {
let v = &[0, ..128];
let m: DList = v.iter().map(|&x|x).collect();
b.iter(|| {
- assert!(m.iter().len() == 128);
+ assert!(m.iter().count() == 128);
})
}
#[bench]
@@ -1139,7 +1139,7 @@ mod tests {
let v = &[0, ..128];
let mut m: DList = v.iter().map(|&x|x).collect();
b.iter(|| {
- assert!(m.mut_iter().len() == 128);
+ assert!(m.mut_iter().count() == 128);
})
}
#[bench]
@@ -1147,7 +1147,7 @@ mod tests {
let v = &[0, ..128];
let m: DList = v.iter().map(|&x|x).collect();
b.iter(|| {
- assert!(m.iter().rev().len() == 128);
+ assert!(m.iter().rev().count() == 128);
})
}
#[bench]
@@ -1155,7 +1155,7 @@ mod tests {
let v = &[0, ..128];
let mut m: DList = v.iter().map(|&x|x).collect();
b.iter(|| {
- assert!(m.mut_iter().rev().len() == 128);
+ assert!(m.mut_iter().rev().count() == 128);
})
}
}
diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs
index 0b339a972629..e631b8b77cf9 100644
--- a/src/libcollections/slice.rs
+++ b/src/libcollections/slice.rs
@@ -2155,7 +2155,7 @@ mod tests {
#[test]
fn test_mut_splitator() {
let mut xs = [0,1,0,2,3,0,0,4,5,0];
- assert_eq!(xs.mut_split(|x| *x == 0).len(), 6);
+ assert_eq!(xs.mut_split(|x| *x == 0).count(), 6);
for slice in xs.mut_split(|x| *x == 0) {
slice.reverse();
}
diff --git a/src/libcollections/smallintmap.rs b/src/libcollections/smallintmap.rs
index 829986e64ee6..f3118181bdcd 100644
--- a/src/libcollections/smallintmap.rs
+++ b/src/libcollections/smallintmap.rs
@@ -31,7 +31,7 @@ pub struct SmallIntMap {
impl Container for SmallIntMap {
/// Return the number of elements in the map
fn len(&self) -> uint {
- self.v.iter().count(|elt| elt.is_some())
+ self.v.iter().filter(|elt| elt.is_some()).count()
}
/// Return true if there are no elements in the map
diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs
index ab1b1d1bd816..5fd133b450f7 100644
--- a/src/libcollections/str.rs
+++ b/src/libcollections/str.rs
@@ -2181,7 +2181,7 @@ mod bench {
let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb";
let len = s.char_len();
- b.iter(|| assert_eq!(s.chars().len(), len));
+ b.iter(|| assert_eq!(s.chars().count(), len));
}
#[bench]
@@ -2194,7 +2194,7 @@ mod bench {
Mary had a little lamb, Little lamb";
let len = s.char_len();
- b.iter(|| assert_eq!(s.chars().len(), len));
+ b.iter(|| assert_eq!(s.chars().count(), len));
}
#[bench]
@@ -2202,7 +2202,7 @@ mod bench {
let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb";
let len = s.char_len();
- b.iter(|| assert_eq!(s.chars().rev().len(), len));
+ b.iter(|| assert_eq!(s.chars().rev().count(), len));
}
#[bench]
@@ -2210,7 +2210,7 @@ mod bench {
let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb";
let len = s.char_len();
- b.iter(|| assert_eq!(s.char_indices().len(), len));
+ b.iter(|| assert_eq!(s.char_indices().count(), len));
}
#[bench]
@@ -2218,14 +2218,14 @@ mod bench {
let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb";
let len = s.char_len();
- b.iter(|| assert_eq!(s.char_indices().rev().len(), len));
+ b.iter(|| assert_eq!(s.char_indices().rev().count(), len));
}
#[bench]
fn split_unicode_ascii(b: &mut Bencher) {
let s = "ประเทศไทย中华Việt Namประเทศไทย中华Việt Nam";
- b.iter(|| assert_eq!(s.split('V').len(), 3));
+ b.iter(|| assert_eq!(s.split('V').count(), 3));
}
#[bench]
@@ -2240,16 +2240,16 @@ mod bench {
}
let s = "ประเทศไทย中华Việt Namประเทศไทย中华Việt Nam";
- b.iter(|| assert_eq!(s.split(NotAscii('V')).len(), 3));
+ b.iter(|| assert_eq!(s.split(NotAscii('V')).count(), 3));
}
#[bench]
fn split_ascii(b: &mut Bencher) {
let s = "Mary had a little lamb, Little lamb, little-lamb.";
- let len = s.split(' ').len();
+ let len = s.split(' ').count();
- b.iter(|| assert_eq!(s.split(' ').len(), len));
+ b.iter(|| assert_eq!(s.split(' ').count(), len));
}
#[bench]
@@ -2264,34 +2264,34 @@ mod bench {
fn only_ascii(&self) -> bool { false }
}
let s = "Mary had a little lamb, Little lamb, little-lamb.";
- let len = s.split(' ').len();
+ let len = s.split(' ').count();
- b.iter(|| assert_eq!(s.split(NotAscii(' ')).len(), len));
+ b.iter(|| assert_eq!(s.split(NotAscii(' ')).count(), len));
}
#[bench]
fn split_extern_fn(b: &mut Bencher) {
let s = "Mary had a little lamb, Little lamb, little-lamb.";
- let len = s.split(' ').len();
+ let len = s.split(' ').count();
fn pred(c: char) -> bool { c == ' ' }
- b.iter(|| assert_eq!(s.split(pred).len(), len));
+ b.iter(|| assert_eq!(s.split(pred).count(), len));
}
#[bench]
fn split_closure(b: &mut Bencher) {
let s = "Mary had a little lamb, Little lamb, little-lamb.";
- let len = s.split(' ').len();
+ let len = s.split(' ').count();
- b.iter(|| assert_eq!(s.split(|c: char| c == ' ').len(), len));
+ b.iter(|| assert_eq!(s.split(|c: char| c == ' ').count(), len));
}
#[bench]
fn split_slice(b: &mut Bencher) {
let s = "Mary had a little lamb, Little lamb, little-lamb.";
- let len = s.split(' ').len();
+ let len = s.split(' ').count();
- b.iter(|| assert_eq!(s.split(&[' ']).len(), len));
+ b.iter(|| assert_eq!(s.split(&[' ']).count(), len));
}
#[bench]
diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs
index aa80a131811c..6ca21262f51c 100644
--- a/src/libcollections/vec.rs
+++ b/src/libcollections/vec.rs
@@ -1772,23 +1772,23 @@ mod tests {
assert_eq!(v.pop(), Some(()));
assert_eq!(v.pop(), None);
- assert_eq!(v.iter().len(), 0);
+ assert_eq!(v.iter().count(), 0);
v.push(());
- assert_eq!(v.iter().len(), 1);
+ assert_eq!(v.iter().count(), 1);
v.push(());
- assert_eq!(v.iter().len(), 2);
+ assert_eq!(v.iter().count(), 2);
for &() in v.iter() {}
- assert_eq!(v.mut_iter().len(), 2);
+ assert_eq!(v.mut_iter().count(), 2);
v.push(());
- assert_eq!(v.mut_iter().len(), 3);
+ assert_eq!(v.mut_iter().count(), 3);
v.push(());
- assert_eq!(v.mut_iter().len(), 4);
+ assert_eq!(v.mut_iter().count(), 4);
for &() in v.mut_iter() {}
unsafe { v.set_len(0); }
- assert_eq!(v.mut_iter().len(), 0);
+ assert_eq!(v.mut_iter().count(), 0);
}
#[test]
diff --git a/src/libcore/iter.rs b/src/libcore/iter.rs
index 875c852d8ae6..64c53b658eff 100644
--- a/src/libcore/iter.rs
+++ b/src/libcore/iter.rs
@@ -529,11 +529,11 @@ pub trait Iterator {
/// ```rust
/// let a = [1, 2, 3, 4, 5];
/// let mut it = a.iter();
- /// assert!(it.len() == 5);
- /// assert!(it.len() == 0);
+ /// assert!(it.count() == 5);
+ /// assert!(it.count() == 0);
/// ```
#[inline]
- fn len(&mut self) -> uint {
+ fn count(&mut self) -> uint {
self.fold(0, |cnt, _x| cnt + 1)
}
@@ -591,16 +591,6 @@ pub trait Iterator {
None
}
- /// Count the number of elements satisfying the specified predicate
- #[inline]
- fn count(&mut self, predicate: |A| -> bool) -> uint {
- let mut i = 0;
- for x in *self {
- if predicate(x) { i += 1 }
- }
- i
- }
-
/// Return the element that gives the maximum value from the
/// specified function.
///
@@ -738,6 +728,14 @@ pub trait ExactSize : DoubleEndedIterator {
}
None
}
+
+ #[inline]
+ /// Return the exact length of the iterator.
+ fn len(&self) -> uint {
+ let (lower, upper) = self.size_hint();
+ assert!(upper == Some(lower));
+ lower
+ }
}
// All adaptors that preserve the size of the wrapped iterator are fine
@@ -2594,9 +2592,9 @@ mod tests {
#[test]
fn test_iterator_len() {
let v = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
- assert_eq!(v.slice(0, 4).iter().len(), 4);
- assert_eq!(v.slice(0, 10).iter().len(), 10);
- assert_eq!(v.slice(0, 0).iter().len(), 0);
+ assert_eq!(v.slice(0, 4).iter().count(), 4);
+ assert_eq!(v.slice(0, 10).iter().count(), 10);
+ assert_eq!(v.slice(0, 0).iter().count(), 0);
}
#[test]
@@ -2712,9 +2710,9 @@ mod tests {
#[test]
fn test_count() {
let xs = &[1, 2, 2, 1, 5, 9, 0, 2];
- assert_eq!(xs.iter().count(|x| *x == 2), 3);
- assert_eq!(xs.iter().count(|x| *x == 5), 1);
- assert_eq!(xs.iter().count(|x| *x == 95), 0);
+ assert_eq!(xs.iter().filter(|x| **x == 2).count(), 3);
+ assert_eq!(xs.iter().filter(|x| **x == 5).count(), 1);
+ assert_eq!(xs.iter().filter(|x| **x == 95).count(), 0);
}
#[test]
@@ -3044,10 +3042,10 @@ mod tests {
assert!(range(-10i, -1).collect::>() ==
vec![-10, -9, -8, -7, -6, -5, -4, -3, -2]);
assert!(range(0i, 5).rev().collect::>() == vec![4, 3, 2, 1, 0]);
- assert_eq!(range(200, -5).len(), 0);
- assert_eq!(range(200, -5).rev().len(), 0);
- assert_eq!(range(200, 200).len(), 0);
- assert_eq!(range(200, 200).rev().len(), 0);
+ assert_eq!(range(200, -5).count(), 0);
+ assert_eq!(range(200, -5).rev().count(), 0);
+ assert_eq!(range(200, 200).count(), 0);
+ assert_eq!(range(200, 200).rev().count(), 0);
assert_eq!(range(0i, 100).size_hint(), (100, Some(100)));
// this test is only meaningful when sizeof uint < sizeof u64
@@ -3062,8 +3060,8 @@ mod tests {
vec![0i, 1, 2, 3, 4, 5]);
assert!(range_inclusive(0i, 5).rev().collect::>() ==
vec![5i, 4, 3, 2, 1, 0]);
- assert_eq!(range_inclusive(200, -5).len(), 0);
- assert_eq!(range_inclusive(200, -5).rev().len(), 0);
+ assert_eq!(range_inclusive(200, -5).count(), 0);
+ assert_eq!(range_inclusive(200, -5).rev().count(), 0);
assert!(range_inclusive(200, 200).collect::>() == vec![200]);
assert!(range_inclusive(200, 200).rev().collect::>() == vec![200]);
}
diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs
index 0257911e8c08..4dea1fd75a4b 100644
--- a/src/libcore/slice.rs
+++ b/src/libcore/slice.rs
@@ -252,7 +252,7 @@ pub mod traits {
use super::*;
use cmp::{PartialEq, PartialOrd, Eq, Ord, Ordering, Equiv};
- use iter::{order, Iterator};
+ use iter::order;
use container::Container;
impl<'a,T:PartialEq> PartialEq for &'a [T] {
@@ -1141,7 +1141,6 @@ impl<'a, T:Clone> MutableCloneableVector for &'a mut [T] {
/// Unsafe operations
pub mod raw {
use mem::transmute;
- use iter::Iterator;
use ptr::RawPtr;
use raw::Slice;
use option::{None, Option, Some};
diff --git a/src/libcore/str.rs b/src/libcore/str.rs
index c08f30152d59..936b698d4b10 100644
--- a/src/libcore/str.rs
+++ b/src/libcore/str.rs
@@ -867,7 +867,6 @@ static TAG_CONT_U8: u8 = 128u8;
pub mod raw {
use mem;
use container::Container;
- use iter::Iterator;
use ptr::RawPtr;
use raw::Slice;
use slice::{ImmutableVector};
@@ -1725,7 +1724,7 @@ impl<'a> StrSlice<'a> for &'a str {
fn is_alphanumeric(&self) -> bool { self.chars().all(char::is_alphanumeric) }
#[inline]
- fn char_len(&self) -> uint { self.chars().len() }
+ fn char_len(&self) -> uint { self.chars().count() }
#[inline]
fn slice(&self, begin: uint, end: uint) -> &'a str {
diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs
index e2d0a858d42b..cd2f3360f830 100644
--- a/src/librustc/metadata/encoder.rs
+++ b/src/librustc/metadata/encoder.rs
@@ -351,7 +351,7 @@ fn encode_enum_variant_info(ecx: &EncodeContext,
fn encode_path + Clone>(ebml_w: &mut Encoder,
mut path: PI) {
ebml_w.start_tag(tag_path);
- ebml_w.wr_tagged_u32(tag_path_len, path.clone().len() as u32);
+ ebml_w.wr_tagged_u32(tag_path_len, path.clone().count() as u32);
for pe in path {
let tag = match pe {
ast_map::PathMod(_) => tag_path_elem_mod,
diff --git a/src/librustc/middle/entry.rs b/src/librustc/middle/entry.rs
index 1b7ed90237fd..9a5f226bb73c 100644
--- a/src/librustc/middle/entry.rs
+++ b/src/librustc/middle/entry.rs
@@ -82,7 +82,7 @@ fn find_item(item: &Item, ctxt: &mut EntryContext) {
ItemFn(..) => {
if item.ident.name == ctxt.main_name {
ctxt.ast_map.with_path(item.id, |mut path| {
- if path.len() == 1 {
+ if path.count() == 1 {
// This is a top-level function so can be 'main'
if ctxt.main_fn.is_none() {
ctxt.main_fn = Some((item.id, item.span));
diff --git a/src/librustc/middle/typeck/astconv.rs b/src/librustc/middle/typeck/astconv.rs
index f8821a86e717..bdb23aea0670 100644
--- a/src/librustc/middle/typeck/astconv.rs
+++ b/src/librustc/middle/typeck/astconv.rs
@@ -191,11 +191,11 @@ fn ast_path_substs(
};
// Convert the type parameters supplied by the user.
- let supplied_ty_param_count = path.segments.iter().flat_map(|s| s.types.iter()).len();
+ let supplied_ty_param_count = path.segments.iter().flat_map(|s| s.types.iter()).count();
let formal_ty_param_count = decl_generics.type_param_defs().len();
let required_ty_param_count = decl_generics.type_param_defs().iter()
.take_while(|x| x.default.is_none())
- .len();
+ .count();
if supplied_ty_param_count < required_ty_param_count {
let expected = if required_ty_param_count < formal_ty_param_count {
"expected at least"
@@ -407,7 +407,7 @@ pub fn ast_ty_to_builtin_ty 1 {
+ .count() > 1 {
this.tcx()
.sess
.span_err(path.span,
diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs
index a09c92d4db01..d25fc9cc5bcd 100644
--- a/src/librustc/middle/typeck/check/mod.rs
+++ b/src/librustc/middle/typeck/check/mod.rs
@@ -1615,7 +1615,7 @@ fn check_type_parameter_positions_in_path(function_context: &FnCtxt,
let formal_ty_param_count = generics.type_param_defs().len();
let required_ty_param_count = generics.type_param_defs().iter()
.take_while(|x| x.default.is_none())
- .len();
+ .count();
let supplied_ty_param_count = trait_segment.types.len();
if supplied_ty_param_count < required_ty_param_count {
let msg = if required_ty_param_count < generics.type_param_defs().len() {
@@ -3876,7 +3876,7 @@ pub fn instantiate_path(fcx: &FnCtxt,
let ty_param_count = tpt.generics.type_param_defs().len();
let ty_param_req = tpt.generics.type_param_defs().iter()
.take_while(|x| x.default.is_none())
- .len();
+ .count();
let mut ty_substs_len = 0;
for segment in pth.segments.iter() {
ty_substs_len += segment.types.len()
diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs
index a9ac1e76f118..eb84ed32335b 100644
--- a/src/librustc/util/ppaux.rs
+++ b/src/librustc/util/ppaux.rs
@@ -456,7 +456,7 @@ pub fn parameterized(cx: &ctxt,
Some(default) => default.subst(cx, &substs) == actual,
None => false
}
- }).len()
+ }).count()
} else {
0
};
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index 086232104e36..20d4d677bc08 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -2043,7 +2043,7 @@ fn build_sidebar(m: &clean::Module) -> HashMap> {
impl<'a> fmt::Show for Source<'a> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
let Source(s) = *self;
- let lines = s.lines().len();
+ let lines = s.lines().count();
let mut cols = 0;
let mut tmp = lines;
while tmp > 0 {
diff --git a/src/librustdoc/html/toc.rs b/src/librustdoc/html/toc.rs
index 2356d4c754fa..5bc6d8031ac2 100644
--- a/src/librustdoc/html/toc.rs
+++ b/src/librustdoc/html/toc.rs
@@ -32,7 +32,7 @@ pub struct Toc {
impl Toc {
fn count_entries_with_level(&self, level: u32) -> uint {
- self.entries.iter().count(|e| e.level == level)
+ self.entries.iter().filter(|e| e.level == level).count()
}
}
diff --git a/src/libstd/num/strconv.rs b/src/libstd/num/strconv.rs
index 54ca57978049..133a8db90fac 100644
--- a/src/libstd/num/strconv.rs
+++ b/src/libstd/num/strconv.rs
@@ -13,7 +13,6 @@
use char;
use clone::Clone;
use container::Container;
-use iter::Iterator;
use num::{NumCast, Zero, One, cast, Int};
use num::{Float, FPNaN, FPInfinite, ToPrimitive};
use num;
diff --git a/src/libstd/rand/mod.rs b/src/libstd/rand/mod.rs
index 61a2ffd383d0..ee1935628871 100644
--- a/src/libstd/rand/mod.rs
+++ b/src/libstd/rand/mod.rs
@@ -353,17 +353,17 @@ mod test {
#[test]
fn test_gen_ascii_str() {
let mut r = task_rng();
- assert_eq!(r.gen_ascii_chars().take(0).len(), 0u);
- assert_eq!(r.gen_ascii_chars().take(10).len(), 10u);
- assert_eq!(r.gen_ascii_chars().take(16).len(), 16u);
+ assert_eq!(r.gen_ascii_chars().take(0).count(), 0u);
+ assert_eq!(r.gen_ascii_chars().take(10).count(), 10u);
+ assert_eq!(r.gen_ascii_chars().take(16).count(), 16u);
}
#[test]
fn test_gen_vec() {
let mut r = task_rng();
- assert_eq!(r.gen_iter::().take(0).len(), 0u);
- assert_eq!(r.gen_iter::().take(10).len(), 10u);
- assert_eq!(r.gen_iter::().take(16).len(), 16u);
+ assert_eq!(r.gen_iter::().take(0).count(), 0u);
+ assert_eq!(r.gen_iter::().take(10).count(), 10u);
+ assert_eq!(r.gen_iter::().take(16).count(), 16u);
}
#[test]
diff --git a/src/libstd/rt/backtrace.rs b/src/libstd/rt/backtrace.rs
index ac421bf78be7..fe6d84d4d2e2 100644
--- a/src/libstd/rt/backtrace.rs
+++ b/src/libstd/rt/backtrace.rs
@@ -84,7 +84,7 @@ fn demangle(writer: &mut Writer, s: &str) -> IoResult<()> {
if i == 0 {
valid = chars.next().is_none();
break
- } else if chars.by_ref().take(i - 1).len() != i - 1 {
+ } else if chars.by_ref().take(i - 1).count() != i - 1 {
valid = false;
}
}
diff --git a/src/test/run-pass/issue-13204.rs b/src/test/run-pass/issue-13204.rs
index 5fb9119849ca..f9b542dea56f 100644
--- a/src/test/run-pass/issue-13204.rs
+++ b/src/test/run-pass/issue-13204.rs
@@ -14,7 +14,7 @@
pub trait Foo {
fn bar<'a, I: Iterator<&'a ()>>(&self, it: I) -> uint {
let mut xs = it.filter(|_| true);
- xs.len()
+ xs.count()
}
}
From b662aa5ec0eb1971111bf10f9c3ef2a8f226bb0a Mon Sep 17 00:00:00 2001
From: Steven Fackler
Date: Thu, 5 Jun 2014 23:22:01 -0700
Subject: [PATCH 09/16] Implement Eq for HashSet and HashMap
Also fix documentation references to PartialEq.
---
src/libstd/collections/hashmap.rs | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/src/libstd/collections/hashmap.rs b/src/libstd/collections/hashmap.rs
index 5dba7a533a1d..571c57947044 100644
--- a/src/libstd/collections/hashmap.rs
+++ b/src/libstd/collections/hashmap.rs
@@ -684,8 +684,8 @@ impl DefaultResizePolicy {
/// denial-of-service attacks (Hash DoS). This behaviour can be
/// overridden with one of the constructors.
///
-/// It is required that the keys implement the `PartialEq` and `Hash` traits, although
-/// this can frequently be achieved by using `#[deriving(PartialEq, Hash)]`.
+/// It is required that the keys implement the `Eq` and `Hash` traits, although
+/// this can frequently be achieved by using `#[deriving(Eq, Hash)]`.
///
/// Relevant papers/articles:
///
@@ -1422,6 +1422,8 @@ impl, V: PartialEq, S, H: Hasher> PartialEq for HashMap, V: Eq, S, H: Hasher> Eq for HashMap {}
+
impl + Show, V: Show, S, H: Hasher> Show for HashMap {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
try!(write!(f, r"\{"));
@@ -1486,7 +1488,7 @@ pub type SetMoveItems =
/// An implementation of a hash set using the underlying representation of a
/// HashMap where the value is (). As with the `HashMap` type, a `HashSet`
-/// requires that the elements implement the `PartialEq` and `Hash` traits.
+/// requires that the elements implement the `Eq` and `Hash` traits.
#[deriving(Clone)]
pub struct HashSet {
map: HashMap
@@ -1500,6 +1502,8 @@ impl, S, H: Hasher> PartialEq for HashSet {
}
}
+impl, S, H: Hasher> Eq for HashSet {}
+
impl, S, H: Hasher> Container for HashSet {
fn len(&self) -> uint { self.map.len() }
}
From 1f4d8f924e78408bc4b10a29da9c42ce29bd725c Mon Sep 17 00:00:00 2001
From: Huon Wilson
Date: Sat, 7 Jun 2014 00:49:19 +1000
Subject: [PATCH 10/16] url: encode small bytes correctly.
Previously, bytes less than 16 would be encoded as %X, rather than %XX,
since the output width was left to be automatic.
---
src/liburl/lib.rs | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/src/liburl/lib.rs b/src/liburl/lib.rs
index 12db15df3110..65b5a8428bdd 100644
--- a/src/liburl/lib.rs
+++ b/src/liburl/lib.rs
@@ -161,10 +161,10 @@ fn encode_inner(s: &str, full_url: bool) -> String {
out.push_char(ch);
}
- _ => out.push_str(format!("%{:X}", ch as uint).as_slice())
+ _ => out.push_str(format!("%{:02X}", ch as uint).as_slice())
}
} else {
- out.push_str(format!("%{:X}", ch as uint).as_slice());
+ out.push_str(format!("%{:02X}", ch as uint).as_slice());
}
}
}
@@ -1178,6 +1178,8 @@ mod tests {
assert_eq!(encode("@"), "@".to_string());
assert_eq!(encode("["), "[".to_string());
assert_eq!(encode("]"), "]".to_string());
+ assert_eq!(encode("\0"), "%00".to_string());
+ assert_eq!(encode("\n"), "%0A".to_string());
}
#[test]
@@ -1207,6 +1209,8 @@ mod tests {
assert_eq!(encode_component("@"), "%40".to_string());
assert_eq!(encode_component("["), "%5B".to_string());
assert_eq!(encode_component("]"), "%5D".to_string());
+ assert_eq!(encode_component("\0"), "%00".to_string());
+ assert_eq!(encode_component("\n"), "%0A".to_string());
}
#[test]
From cb12e7ab743e4a0118a3de53a437a70cf332e5b1 Mon Sep 17 00:00:00 2001
From: Alex Crichton
Date: Fri, 6 Jun 2014 09:22:19 -0700
Subject: [PATCH 11/16] mk: Run doc tests with --cfg dox
There were a few examples in the macros::builtin module that weren't being run
because they were being #[cfg]'d out.
Closes #14697
---
mk/tests.mk | 2 +-
src/libstd/macros.rs | 6 +++++-
2 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/mk/tests.mk b/mk/tests.mk
index c67fa0042f81..dacea3a4bfc4 100644
--- a/mk/tests.mk
+++ b/mk/tests.mk
@@ -818,7 +818,7 @@ endif
ifeq ($(2),$$(CFG_BUILD))
$$(call TEST_OK_FILE,$(1),$(2),$(3),doc-crate-$(4)): $$(CRATEDOCTESTDEP_$(1)_$(2)_$(3)_$(4))
@$$(call E, run doc-crate-$(4) [$(2)])
- $$(Q)$$(RUSTDOC_$(1)_T_$(2)_H_$(3)) --test \
+ $$(Q)$$(RUSTDOC_$(1)_T_$(2)_H_$(3)) --test --cfg dox \
$$(CRATEFILE_$(4)) --test-args "$$(TESTARGS)" && touch $$@
else
$$(call TEST_OK_FILE,$(1),$(2),$(3),doc-crate-$(4)):
diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs
index b555c966d2d0..805da8021ed2 100644
--- a/src/libstd/macros.rs
+++ b/src/libstd/macros.rs
@@ -465,7 +465,7 @@ pub mod builtin {
/// ```
/// let rust = bytes!("r", 'u', "st", 255);
/// assert_eq!(rust[1], 'u' as u8);
- /// assert_eq!(rust[5], 255);
+ /// assert_eq!(rust[4], 255);
/// ```
#[macro_export]
macro_rules! bytes( ($($e:expr),*) => ({ /* compiler built-in */ }) )
@@ -482,10 +482,14 @@ pub mod builtin {
/// # Example
///
/// ```
+ /// #![feature(concat_idents)]
+ ///
+ /// # fn main() {
/// fn foobar() -> int { 23 }
///
/// let f = concat_idents!(foo, bar);
/// println!("{}", f());
+ /// # }
/// ```
#[macro_export]
macro_rules! concat_idents( ($($e:ident),*) => ({ /* compiler built-in */ }) )
From d4dec4701a5e5e6fb4f66c838b9646bc1c1f711b Mon Sep 17 00:00:00 2001
From: Alex Crichton
Date: Fri, 6 Jun 2014 17:48:46 -0700
Subject: [PATCH 12/16] rustc: Preserve reachable extern fns with LTO
All rust functions are internal implementation details with respect to the ABI
exposed by crates, but extern fns are public components of the ABI and shouldn't
be stripped. This commit serializes reachable extern fns to metadata, so when
LTO is performed all of their symbols are not stripped.
Closes #14500
---
src/librustc/metadata/common.rs | 3 +++
src/librustc/metadata/csearch.rs | 7 +++++++
src/librustc/metadata/decoder.rs | 14 ++++++++++++++
src/librustc/metadata/encoder.rs | 25 +++++++++++++++++++++++++
src/librustc/middle/trans/base.rs | 11 +++++++++++
src/test/run-make/issue-14500/Makefile | 14 ++++++++++++++
src/test/run-make/issue-14500/bar.rs | 11 +++++++++++
src/test/run-make/issue-14500/foo.c | 16 ++++++++++++++++
src/test/run-make/issue-14500/foo.rs | 12 ++++++++++++
src/test/run-make/lto-smoke-c/Makefile | 15 +--------------
src/test/run-make/tools.mk | 14 ++++++++++++++
11 files changed, 128 insertions(+), 14 deletions(-)
create mode 100644 src/test/run-make/issue-14500/Makefile
create mode 100644 src/test/run-make/issue-14500/bar.rs
create mode 100644 src/test/run-make/issue-14500/foo.c
create mode 100644 src/test/run-make/issue-14500/foo.rs
diff --git a/src/librustc/metadata/common.rs b/src/librustc/metadata/common.rs
index 8aeef3dca986..6287683c1a14 100644
--- a/src/librustc/metadata/common.rs
+++ b/src/librustc/metadata/common.rs
@@ -209,6 +209,9 @@ pub static tag_dylib_dependency_formats: uint = 0x67;
pub static tag_method_argument_names: uint = 0x8e;
pub static tag_method_argument_name: uint = 0x8f;
+pub static tag_reachable_extern_fns: uint = 0x90;
+pub static tag_reachable_extern_fn_id: uint = 0x91;
+
#[deriving(Clone, Show)]
pub struct LinkMeta {
pub crateid: CrateId,
diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs
index 74a804763e83..c7ad74dce571 100644
--- a/src/librustc/metadata/csearch.rs
+++ b/src/librustc/metadata/csearch.rs
@@ -314,3 +314,10 @@ pub fn get_method_arg_names(cstore: &cstore::CStore, did: ast::DefId)
let cdata = cstore.get_crate_data(did.krate);
decoder::get_method_arg_names(&*cdata, did.node)
}
+
+pub fn get_reachable_extern_fns(cstore: &cstore::CStore, cnum: ast::CrateNum)
+ -> Vec
+{
+ let cdata = cstore.get_crate_data(cnum);
+ decoder::get_reachable_extern_fns(&*cdata)
+}
diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs
index 6469462734e5..c67b5bf1a600 100644
--- a/src/librustc/metadata/decoder.rs
+++ b/src/librustc/metadata/decoder.rs
@@ -1325,3 +1325,17 @@ pub fn get_method_arg_names(cdata: Cmd, id: ast::NodeId) -> Vec {
}
return ret;
}
+
+pub fn get_reachable_extern_fns(cdata: Cmd) -> Vec {
+ let mut ret = Vec::new();
+ let items = reader::get_doc(ebml::Doc::new(cdata.data()),
+ tag_reachable_extern_fns);
+ reader::tagged_docs(items, tag_reachable_extern_fn_id, |doc| {
+ ret.push(ast::DefId {
+ krate: cdata.cnum,
+ node: reader::doc_as_u32(doc),
+ });
+ true
+ });
+ return ret;
+}
diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs
index cd2f3360f830..37cb75e4697b 100644
--- a/src/librustc/metadata/encoder.rs
+++ b/src/librustc/metadata/encoder.rs
@@ -75,6 +75,7 @@ pub struct EncodeParams<'a> {
pub link_meta: &'a LinkMeta,
pub cstore: &'a cstore::CStore,
pub encode_inlined_item: EncodeInlinedItem<'a>,
+ pub reachable: &'a NodeSet,
}
pub struct EncodeContext<'a> {
@@ -87,6 +88,7 @@ pub struct EncodeContext<'a> {
pub cstore: &'a cstore::CStore,
pub encode_inlined_item: RefCell>,
pub type_abbrevs: tyencode::abbrev_map,
+ pub reachable: &'a NodeSet,
}
fn encode_name(ebml_w: &mut Encoder, name: Name) {
@@ -1702,6 +1704,26 @@ fn encode_misc_info(ecx: &EncodeContext,
ebml_w.end_tag();
}
+fn encode_reachable_extern_fns(ecx: &EncodeContext, ebml_w: &mut Encoder) {
+ ebml_w.start_tag(tag_reachable_extern_fns);
+
+ for id in ecx.reachable.iter() {
+ match ecx.tcx.map.find(*id) {
+ Some(ast_map::NodeItem(i)) => {
+ match i.node {
+ ast::ItemFn(_, _, abi, _, _) if abi != abi::Rust => {
+ ebml_w.wr_tagged_u32(tag_reachable_extern_fn_id, *id);
+ }
+ _ => {}
+ }
+ }
+ _ => {}
+ }
+ }
+
+ ebml_w.end_tag();
+}
+
fn encode_crate_dep(ebml_w: &mut Encoder,
dep: decoder::CrateDep) {
ebml_w.start_tag(tag_crate_dep);
@@ -1801,6 +1823,7 @@ fn encode_metadata_inner(wr: &mut MemWriter, parms: EncodeParams, krate: &Crate)
encode_inlined_item,
link_meta,
non_inlineable_statics,
+ reachable,
..
} = parms;
let ecx = EncodeContext {
@@ -1813,6 +1836,7 @@ fn encode_metadata_inner(wr: &mut MemWriter, parms: EncodeParams, krate: &Crate)
cstore: cstore,
encode_inlined_item: RefCell::new(encode_inlined_item),
type_abbrevs: RefCell::new(HashMap::new()),
+ reachable: reachable,
};
let mut ebml_w = writer::Encoder::new(wr);
@@ -1864,6 +1888,7 @@ fn encode_metadata_inner(wr: &mut MemWriter, parms: EncodeParams, krate: &Crate)
// Encode miscellaneous info.
i = ebml_w.writer.tell().unwrap();
encode_misc_info(&ecx, krate, &mut ebml_w);
+ encode_reachable_extern_fns(&ecx, &mut ebml_w);
stats.misc_bytes = ebml_w.writer.tell().unwrap() - i;
// Encode and index the items.
diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs
index 9be07eaaca93..09f5d2a35076 100644
--- a/src/librustc/middle/trans/base.rs
+++ b/src/librustc/middle/trans/base.rs
@@ -2238,6 +2238,7 @@ pub fn crate_ctxt_to_encode_parms<'r>(cx: &'r CrateContext, ie: encoder::EncodeI
link_meta: &cx.link_meta,
cstore: &cx.sess().cstore,
encode_inlined_item: ie,
+ reachable: &cx.reachable,
}
}
@@ -2374,6 +2375,16 @@ pub fn trans_crate(krate: ast::Crate,
ccx.item_symbols.borrow().find(id).map(|s| s.to_string())
}).collect();
+ // For the purposes of LTO, we add to the reachable set all of the upstream
+ // reachable extern fns. These functions are all part of the public ABI of
+ // the final product, so LTO needs to preserve them.
+ ccx.sess().cstore.iter_crate_data(|cnum, _| {
+ let syms = csearch::get_reachable_extern_fns(&ccx.sess().cstore, cnum);
+ reachable.extend(syms.move_iter().map(|did| {
+ csearch::get_symbol(&ccx.sess().cstore, did)
+ }));
+ });
+
// Make sure that some other crucial symbols are not eliminated from the
// module. This includes the main function, the crate map (used for debug
// log settings and I/O), and finally the curious rust_stack_exhausted
diff --git a/src/test/run-make/issue-14500/Makefile b/src/test/run-make/issue-14500/Makefile
new file mode 100644
index 000000000000..c1087b0f55ec
--- /dev/null
+++ b/src/test/run-make/issue-14500/Makefile
@@ -0,0 +1,14 @@
+-include ../tools.mk
+
+# Test to make sure that reachable extern fns are always available in final
+# productcs, including when LTO is used. In this test, the `foo` crate has a
+# reahable symbol, and is a dependency of the `bar` crate. When the `bar` crate
+# is compiled with LTO, it shouldn't strip the symbol from `foo`, and that's the
+# only way that `foo.c` will successfully compile.
+
+all:
+ $(RUSTC) foo.rs --crate-type=rlib
+ $(RUSTC) bar.rs --crate-type=staticlib -Zlto -L. -o $(TMPDIR)/libbar.a
+ $(CC) foo.c -lbar -o $(call RUN_BINFILE,foo) $(EXTRACFLAGS)
+ $(call RUN,foo)
+
diff --git a/src/test/run-make/issue-14500/bar.rs b/src/test/run-make/issue-14500/bar.rs
new file mode 100644
index 000000000000..4b4916fe96d6
--- /dev/null
+++ b/src/test/run-make/issue-14500/bar.rs
@@ -0,0 +1,11 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 or the MIT license
+// , at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+extern crate foo;
diff --git a/src/test/run-make/issue-14500/foo.c b/src/test/run-make/issue-14500/foo.c
new file mode 100644
index 000000000000..25098ac479d0
--- /dev/null
+++ b/src/test/run-make/issue-14500/foo.c
@@ -0,0 +1,16 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 or the MIT license
+// , at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+extern void foo();
+
+int main() {
+ foo();
+ return 0;
+}
diff --git a/src/test/run-make/issue-14500/foo.rs b/src/test/run-make/issue-14500/foo.rs
new file mode 100644
index 000000000000..ceca907403f9
--- /dev/null
+++ b/src/test/run-make/issue-14500/foo.rs
@@ -0,0 +1,12 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 or the MIT license
+// , at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#[no_mangle]
+pub extern fn foo() {}
diff --git a/src/test/run-make/lto-smoke-c/Makefile b/src/test/run-make/lto-smoke-c/Makefile
index 49a04ce42a0a..9b44c3e582a7 100644
--- a/src/test/run-make/lto-smoke-c/Makefile
+++ b/src/test/run-make/lto-smoke-c/Makefile
@@ -1,23 +1,10 @@
-include ../tools.mk
-ifdef IS_WINDOWS
- EXTRAFLAGS :=
-else
-ifeq ($(shell uname),Darwin)
-else
-ifeq ($(shell uname),FreeBSD)
- EXTRAFLAGS := -lm -lpthread -lgcc_s
-else
- EXTRAFLAGS := -lm -lrt -ldl -lpthread
-endif
-endif
-endif
-
# Apparently older versions of GCC segfault if -g is passed...
CC := $(CC:-g=)
all:
$(RUSTC) foo.rs -Z lto
ln -s $(call STATICLIB,foo-*) $(call STATICLIB,foo)
- $(CC) bar.c -lfoo -o $(call RUN_BINFILE,bar) $(EXTRAFLAGS) -lstdc++
+ $(CC) bar.c -lfoo -o $(call RUN_BINFILE,bar) $(EXTRACFLAGS) -lstdc++
$(call RUN,bar)
diff --git a/src/test/run-make/tools.mk b/src/test/run-make/tools.mk
index dedd739052ca..c9c4c455e4f8 100644
--- a/src/test/run-make/tools.mk
+++ b/src/test/run-make/tools.mk
@@ -53,6 +53,20 @@ RPATH_LINK_SEARCH = -Wl,-rpath-link=$(1)
endif
endif
+# Extra flags needed to compile a working executable with the standard library
+ifdef IS_WINDOWS
+ EXTRACFLAGS :=
+else
+ifeq ($(shell uname),Darwin)
+else
+ifeq ($(shell uname),FreeBSD)
+ EXTRACFLAGS := -lm -lpthread -lgcc_s
+else
+ EXTRACFLAGS := -lm -lrt -ldl -lpthread
+endif
+endif
+endif
+
REMOVE_DYLIBS = rm $(TMPDIR)/$(call DYLIB_GLOB,$(1))
REMOVE_RLIBS = rm $(TMPDIR)/$(call RLIB_GLOB,$(1))
From 59157631061744947df9a7751ac55fe2304e67ad Mon Sep 17 00:00:00 2001
From: Axel Viala
Date: Sat, 7 Jun 2014 00:43:45 +0200
Subject: [PATCH 13/16] Removing unused wrapper to libc::close.
---
src/libstd/os.rs | 6 ------
1 file changed, 6 deletions(-)
diff --git a/src/libstd/os.rs b/src/libstd/os.rs
index 1f75754f4d53..381ebc082006 100644
--- a/src/libstd/os.rs
+++ b/src/libstd/os.rs
@@ -56,12 +56,6 @@ use libc::c_char;
#[cfg(windows)]
use str::OwnedStr;
-/// Delegates to the libc close() function, returning the same return value.
-pub fn close(fd: int) -> int {
- unsafe {
- libc::close(fd as c_int) as int
- }
-}
pub static TMPBUF_SZ : uint = 1000u;
static BUF_BYTES : uint = 2048u;
From cc63d4c61bb83fcbcef5ccfffcd9b26b1bf2d20a Mon Sep 17 00:00:00 2001
From: Alex Crichton
Date: Thu, 5 Jun 2014 23:01:01 -0700
Subject: [PATCH 14/16] doc: Turn off special features for rustdoc tests
These were only used for the markdown tests, and there's no reason they should
be distinct from the other tests.
---
src/doc/guide-macros.md | 35 ++++++++++++++++++++++++++---------
src/doc/guide-unsafe.md | 1 +
src/doc/rust.md | 3 +++
src/doc/tutorial.md | 3 +++
src/librustdoc/markdown.rs | 2 +-
src/librustdoc/test.rs | 23 +++++------------------
6 files changed, 39 insertions(+), 28 deletions(-)
diff --git a/src/doc/guide-macros.md b/src/doc/guide-macros.md
index b86a6aa1b619..45745c7b7bc7 100644
--- a/src/doc/guide-macros.md
+++ b/src/doc/guide-macros.md
@@ -11,7 +11,7 @@ which both pattern-match on their input and both return early in one case,
doing nothing otherwise:
~~~~
-# enum T { SpecialA(uint), SpecialB(uint) };
+# enum T { SpecialA(uint), SpecialB(uint) }
# fn f() -> uint {
# let input_1 = SpecialA(0);
# let input_2 = SpecialA(0);
@@ -37,7 +37,8 @@ lightweight custom syntax extensions, themselves defined using the
the pattern in the above code:
~~~~
-# enum T { SpecialA(uint), SpecialB(uint) };
+# #![feature(macro_rules)]
+# enum T { SpecialA(uint), SpecialB(uint) }
# fn f() -> uint {
# let input_1 = SpecialA(0);
# let input_2 = SpecialA(0);
@@ -55,6 +56,7 @@ early_return!(input_1 SpecialA);
early_return!(input_2 SpecialB);
# return 0;
# }
+# fn main() {}
~~~~
Macros are defined in pattern-matching style: in the above example, the text
@@ -155,7 +157,8 @@ separator token (a comma-separated list could be written `$(...),*`), and `+`
instead of `*` to mean "at least one".
~~~~
-# enum T { SpecialA(uint),SpecialB(uint),SpecialC(uint),SpecialD(uint)};
+# #![feature(macro_rules)]
+# enum T { SpecialA(uint),SpecialB(uint),SpecialC(uint),SpecialD(uint)}
# fn f() -> uint {
# let input_1 = SpecialA(0);
# let input_2 = SpecialA(0);
@@ -175,6 +178,7 @@ early_return!(input_1, [SpecialA|SpecialC|SpecialD]);
early_return!(input_2, [SpecialB]);
# return 0;
# }
+# fn main() {}
~~~~
### Transcription
@@ -215,9 +219,10 @@ solves the problem.
Now consider code like the following:
~~~~
-# enum T1 { Good1(T2, uint), Bad1};
+# #![feature(macro_rules)]
+# enum T1 { Good1(T2, uint), Bad1}
# struct T2 { body: T3 }
-# enum T3 { Good2(uint), Bad2};
+# enum T3 { Good2(uint), Bad2}
# fn f(x: T1) -> uint {
match x {
Good1(g1, val) => {
@@ -232,6 +237,7 @@ match x {
_ => return 0 // default value
}
# }
+# fn main() {}
~~~~
All the complicated stuff is deeply indented, and the error-handling code is
@@ -240,6 +246,7 @@ a match, but with a syntax that suits the problem better. The following macro
can solve the problem:
~~~~
+# #![feature(macro_rules)]
macro_rules! biased_match (
// special case: `let (x) = ...` is illegal, so use `let x = ...` instead
( ($e:expr) ~ ($p:pat) else $err:stmt ;
@@ -261,9 +268,9 @@ macro_rules! biased_match (
)
)
-# enum T1 { Good1(T2, uint), Bad1};
+# enum T1 { Good1(T2, uint), Bad1}
# struct T2 { body: T3 }
-# enum T3 { Good2(uint), Bad2};
+# enum T3 { Good2(uint), Bad2}
# fn f(x: T1) -> uint {
biased_match!((x) ~ (Good1(g1, val)) else { return 0 };
binds g1, val )
@@ -273,6 +280,7 @@ biased_match!((g1.body) ~ (Good2(result) )
// complicated stuff goes here
return result + val;
# }
+# fn main() {}
~~~~
This solves the indentation problem. But if we have a lot of chained matches
@@ -280,6 +288,8 @@ like this, we might prefer to write a single macro invocation. The input
pattern we want is clear:
~~~~
+# #![feature(macro_rules)]
+# fn main() {}
# macro_rules! b(
( $( ($e:expr) ~ ($p:pat) else $err:stmt ; )*
binds $( $bind_res:ident ),*
@@ -301,14 +311,18 @@ process the semicolon-terminated lines, one-by-one. So, we want the following
input patterns:
~~~~
+# #![feature(macro_rules)]
# macro_rules! b(
( binds $( $bind_res:ident ),* )
# => (0))
+# fn main() {}
~~~~
...and:
~~~~
+# #![feature(macro_rules)]
+# fn main() {}
# macro_rules! b(
( ($e :expr) ~ ($p :pat) else $err :stmt ;
$( ($e_rest:expr) ~ ($p_rest:pat) else $err_rest:stmt ; )*
@@ -322,6 +336,8 @@ The resulting macro looks like this. Note that the separation into
piece of syntax (the `let`) which we only want to transcribe once.
~~~~
+# #![feature(macro_rules)]
+# fn main() {
macro_rules! biased_match_rec (
// Handle the first layer
@@ -365,9 +381,9 @@ macro_rules! biased_match (
)
-# enum T1 { Good1(T2, uint), Bad1};
+# enum T1 { Good1(T2, uint), Bad1}
# struct T2 { body: T3 }
-# enum T3 { Good2(uint), Bad2};
+# enum T3 { Good2(uint), Bad2}
# fn f(x: T1) -> uint {
biased_match!(
(x) ~ (Good1(g1, val)) else { return 0 };
@@ -376,6 +392,7 @@ biased_match!(
// complicated stuff goes here
return result + val;
# }
+# }
~~~~
This technique applies to many cases where transcribing a result all at once is not possible.
diff --git a/src/doc/guide-unsafe.md b/src/doc/guide-unsafe.md
index e0a48682963b..1431c8a5c9ae 100644
--- a/src/doc/guide-unsafe.md
+++ b/src/doc/guide-unsafe.md
@@ -523,6 +523,7 @@ vectors provided from C, using idiomatic Rust practices.
```
#![no_std]
+#![feature(globs)]
# extern crate libc;
extern crate core;
diff --git a/src/doc/rust.md b/src/doc/rust.md
index 06c9da2fe0e5..619e24af3606 100644
--- a/src/doc/rust.md
+++ b/src/doc/rust.md
@@ -1260,6 +1260,8 @@ a = Cat;
Enumeration constructors can have either named or unnamed fields:
~~~~
+# #![feature(struct_variant)]
+# fn main() {
enum Animal {
Dog (String, f64),
Cat { name: String, weight: f64 }
@@ -1267,6 +1269,7 @@ enum Animal {
let mut a: Animal = Dog("Cocoa".to_string(), 37.2);
a = Cat { name: "Spotty".to_string(), weight: 2.7 };
+# }
~~~~
In this example, `Cat` is a _struct-like enum variant_,
diff --git a/src/doc/tutorial.md b/src/doc/tutorial.md
index 917704a2faac..3b4164ffbc61 100644
--- a/src/doc/tutorial.md
+++ b/src/doc/tutorial.md
@@ -774,6 +774,7 @@ fn point_from_direction(dir: Direction) -> Point {
Enum variants may also be structs. For example:
~~~~
+# #![feature(struct_variant)]
use std::f64;
# struct Point { x: f64, y: f64 }
# fn square(x: f64) -> f64 { x * x }
@@ -789,6 +790,7 @@ fn area(sh: Shape) -> f64 {
}
}
}
+# fn main() {}
~~~~
> *Note:* This feature of the compiler is currently gated behind the
@@ -3046,6 +3048,7 @@ use farm::{chicken, cow};
2. Import everything in a module with a wildcard:
~~~
+# #![feature(globs)]
use farm::*;
# mod farm {
# pub fn cow() { println!("Bat-chicken? What a stupid name!") }
diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs
index 961c92940be8..500d17c9f9a5 100644
--- a/src/librustdoc/markdown.rs
+++ b/src/librustdoc/markdown.rs
@@ -173,7 +173,7 @@ pub fn render(input: &str, mut output: Path, matches: &getopts::Matches) -> int
pub fn test(input: &str, libs: HashSet, mut test_args: Vec) -> int {
let input_str = load_or_return!(input, 1, 2);
- let mut collector = Collector::new(input.to_string(), libs, true, true);
+ let mut collector = Collector::new(input.to_string(), libs, true);
find_testable_code(input_str.as_slice(), &mut collector);
test_args.unshift("rustdoctest".to_string());
testing::test_main(test_args.as_slice(), collector.tests);
diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs
index ed53b2ac314a..1434c3eb07d5 100644
--- a/src/librustdoc/test.rs
+++ b/src/librustdoc/test.rs
@@ -91,7 +91,6 @@ pub fn run(input: &str,
let mut collector = Collector::new(krate.name.to_string(),
libs,
- false,
false);
collector.fold_crate(krate);
@@ -103,8 +102,8 @@ pub fn run(input: &str,
}
fn runtest(test: &str, cratename: &str, libs: HashSet, should_fail: bool,
- no_run: bool, loose_feature_gating: bool) {
- let test = maketest(test, cratename, loose_feature_gating);
+ no_run: bool) {
+ let test = maketest(test, cratename);
let input = driver::StrInput(test.to_string());
let sessopts = config::Options {
@@ -201,18 +200,12 @@ fn runtest(test: &str, cratename: &str, libs: HashSet, should_fail: bool,
}
}
-fn maketest(s: &str, cratename: &str, loose_feature_gating: bool) -> String {
+pub fn maketest(s: &str, cratename: &str) -> String {
let mut prog = String::from_str(r"
#![deny(warnings)]
#![allow(unused_variable, dead_assignment, unused_mut, attribute_usage, dead_code)]
");
- if loose_feature_gating {
- // FIXME #12773: avoid inserting these when the tutorial & manual
- // etc. have been updated to not use them so prolifically.
- prog.push_str("#![feature(macro_rules, globs, struct_variant, managed_boxes) ]\n");
- }
-
if !s.contains("extern crate") {
if s.contains(cratename) {
prog.push_str(format!("extern crate {};\n",
@@ -238,13 +231,11 @@ pub struct Collector {
use_headers: bool,
current_header: Option,
cratename: String,
-
- loose_feature_gating: bool
}
impl Collector {
pub fn new(cratename: String, libs: HashSet,
- use_headers: bool, loose_feature_gating: bool) -> Collector {
+ use_headers: bool) -> Collector {
Collector {
tests: Vec::new(),
names: Vec::new(),
@@ -253,8 +244,6 @@ impl Collector {
use_headers: use_headers,
current_header: None,
cratename: cratename,
-
- loose_feature_gating: loose_feature_gating
}
}
@@ -268,7 +257,6 @@ impl Collector {
self.cnt += 1;
let libs = self.libs.clone();
let cratename = self.cratename.to_string();
- let loose_feature_gating = self.loose_feature_gating;
debug!("Creating test {}: {}", name, test);
self.tests.push(testing::TestDescAndFn {
desc: testing::TestDesc {
@@ -281,8 +269,7 @@ impl Collector {
cratename.as_slice(),
libs,
should_fail,
- no_run,
- loose_feature_gating);
+ no_run);
}),
});
}
From e5bbbca33e11d9e22dbbe32c975f908710d4155c Mon Sep 17 00:00:00 2001
From: Alex Crichton
Date: Fri, 6 Jun 2014 09:12:18 -0700
Subject: [PATCH 15/16] rustdoc: Submit examples to play.rust-lang.org
This grows a new option inside of rustdoc to add the ability to submit examples
to an external website. If the `--markdown-playground-url` command line option
or crate doc attribute `html_playground_url` is present, then examples will have
a button on hover to submit the code to the playground specified.
This commit enables submission of example code to play.rust-lang.org. The code
submitted is that which is tested by rustdoc, not necessarily the exact code
shown in the example.
Closes #14654
---
mk/docs.mk | 4 ++-
src/doc/footer.inc | 2 ++
src/doc/rust.css | 13 ++++++++++
src/libcollections/lib.rs | 3 ++-
src/libcore/lib.rs | 3 ++-
src/libgetopts/lib.rs | 3 ++-
src/libglob/lib.rs | 4 +--
src/libgreen/lib.rs | 3 ++-
src/liblog/lib.rs | 3 ++-
src/libnum/lib.rs | 3 ++-
src/librand/lib.rs | 3 ++-
src/libregex/lib.rs | 3 ++-
src/librustdoc/html/highlight.rs | 13 +++++++---
src/librustdoc/html/layout.rs | 13 ++++++++--
src/librustdoc/html/markdown.rs | 35 ++++++++++++++++++++++-----
src/librustdoc/html/render.rs | 15 ++++++++++--
src/librustdoc/html/static/main.css | 13 +++++++++-
src/librustdoc/html/static/main.js | 2 +-
src/librustdoc/html/static/playpen.js | 29 ++++++++++++++++++++++
src/librustdoc/lib.rs | 4 ++-
src/librustdoc/markdown.rs | 13 +++++++++-
src/librustdoc/test.rs | 24 ++++++++++++------
src/libserialize/lib.rs | 3 ++-
src/libstd/lib.rs | 3 ++-
src/libsync/lib.rs | 3 ++-
src/libterm/lib.rs | 3 ++-
src/libtime/lib.rs | 3 ++-
src/liburl/lib.rs | 3 ++-
src/libuuid/lib.rs | 3 ++-
29 files changed, 186 insertions(+), 43 deletions(-)
create mode 100644 src/librustdoc/html/static/playpen.js
diff --git a/mk/docs.mk b/mk/docs.mk
index 90f85079464b..dab40cb16543 100644
--- a/mk/docs.mk
+++ b/mk/docs.mk
@@ -43,7 +43,9 @@ L10N_LANGS := ja
# The options are passed to the documentation generators.
RUSTDOC_HTML_OPTS_NO_CSS = --markdown-before-content=doc/version_info.html \
- --markdown-in-header=doc/favicon.inc --markdown-after-content=doc/footer.inc
+ --markdown-in-header=doc/favicon.inc \
+ --markdown-after-content=doc/footer.inc \
+ --markdown-playground-url='http://play.rust-lang.org/'
RUSTDOC_HTML_OPTS = $(RUSTDOC_HTML_OPTS_NO_CSS) --markdown-css rust.css
diff --git a/src/doc/footer.inc b/src/doc/footer.inc
index a103a4908f6b..4e7d60586f23 100644
--- a/src/doc/footer.inc
+++ b/src/doc/footer.inc
@@ -5,3 +5,5 @@ or the MIT license, at your opt
This file may not be copied, modified, or distributed except according to those terms.
+
+
diff --git a/src/doc/rust.css b/src/doc/rust.css
index d60dd54a67d1..3957231a195a 100644
--- a/src/doc/rust.css
+++ b/src/doc/rust.css
@@ -313,6 +313,19 @@ table th {
padding: 5px;
}
+/* Code snippets */
+
+.rusttest { display: none; }
+pre.rust { position: relative; }
+pre.rust a { transform: scaleX(-1); }
+.test-arrow {
+ display: inline-block;
+ position: absolute;
+ top: 0;
+ right: 10px;
+ font-size: 150%;
+}
+
@media (min-width: 1170px) {
pre {
font-size: 15px;
diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs
index 2004285ecb91..a65c06107ce3 100644
--- a/src/libcollections/lib.rs
+++ b/src/libcollections/lib.rs
@@ -17,7 +17,8 @@
#![license = "MIT/ASL2"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
- html_root_url = "http://doc.rust-lang.org/")]
+ html_root_url = "http://doc.rust-lang.org/",
+ html_playground_url = "http://play.rust-lang.org/")]
#![feature(macro_rules, managed_boxes, default_type_params, phase, globs)]
#![no_std]
diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs
index 6aa07415e9cc..2ccf431fc22e 100644
--- a/src/libcore/lib.rs
+++ b/src/libcore/lib.rs
@@ -50,7 +50,8 @@
#![crate_type = "rlib"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
- html_root_url = "http://doc.rust-lang.org/")]
+ html_root_url = "http://doc.rust-lang.org/",
+ html_playground_url = "http://play.rust-lang.org/")]
#![no_std]
#![feature(globs, macro_rules, managed_boxes, phase, simd)]
diff --git a/src/libgetopts/lib.rs b/src/libgetopts/lib.rs
index ddfe8380e09d..10584223486c 100644
--- a/src/libgetopts/lib.rs
+++ b/src/libgetopts/lib.rs
@@ -84,7 +84,8 @@
#![license = "MIT/ASL2"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
- html_root_url = "http://doc.rust-lang.org/")]
+ html_root_url = "http://doc.rust-lang.org/",
+ html_playground_url = "http://play.rust-lang.org/")]
#![feature(globs, phase)]
#![deny(missing_doc)]
#![deny(deprecated_owned_vector)]
diff --git a/src/libglob/lib.rs b/src/libglob/lib.rs
index 86753fbb811c..f3e1da77ce5c 100644
--- a/src/libglob/lib.rs
+++ b/src/libglob/lib.rs
@@ -29,8 +29,8 @@
#![license = "MIT/ASL2"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
- html_root_url = "http://doc.rust-lang.org/")]
-
+ html_root_url = "http://doc.rust-lang.org/",
+ html_playground_url = "http://play.rust-lang.org/")]
#![deny(deprecated_owned_vector)]
use std::cell::Cell;
diff --git a/src/libgreen/lib.rs b/src/libgreen/lib.rs
index 31fd8950c804..c75d69480ce0 100644
--- a/src/libgreen/lib.rs
+++ b/src/libgreen/lib.rs
@@ -203,7 +203,8 @@
#![crate_type = "dylib"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
- html_root_url = "http://doc.rust-lang.org/")]
+ html_root_url = "http://doc.rust-lang.org/",
+ html_playground_url = "http://play.rust-lang.org/")]
// NB this does *not* include globs, please keep it that way.
#![feature(macro_rules, phase)]
diff --git a/src/liblog/lib.rs b/src/liblog/lib.rs
index ff5805599690..daacf8b3c476 100644
--- a/src/liblog/lib.rs
+++ b/src/liblog/lib.rs
@@ -111,7 +111,8 @@ if logging is disabled, none of the components of the log will be executed.
#![crate_type = "dylib"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
- html_root_url = "http://doc.rust-lang.org/")]
+ html_root_url = "http://doc.rust-lang.org/",
+ html_playground_url = "http://play.rust-lang.org/")]
#![feature(macro_rules)]
#![deny(missing_doc, deprecated_owned_vector)]
diff --git a/src/libnum/lib.rs b/src/libnum/lib.rs
index 29cf769ffc9d..fae21e80f307 100644
--- a/src/libnum/lib.rs
+++ b/src/libnum/lib.rs
@@ -50,7 +50,8 @@
#![license = "MIT/ASL2"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
- html_root_url = "http://doc.rust-lang.org/")]
+ html_root_url = "http://doc.rust-lang.org/",
+ html_playground_url = "http://play.rust-lang.org/")]
#![deny(deprecated_owned_vector)]
diff --git a/src/librand/lib.rs b/src/librand/lib.rs
index 3ed086e9b13c..7a12dcf9f7f3 100644
--- a/src/librand/lib.rs
+++ b/src/librand/lib.rs
@@ -21,7 +21,8 @@
#![crate_type = "rlib"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
- html_root_url = "http://doc.rust-lang.org/")]
+ html_root_url = "http://doc.rust-lang.org/",
+ html_playground_url = "http://play.rust-lang.org/")]
#![feature(macro_rules, phase, globs)]
#![no_std]
diff --git a/src/libregex/lib.rs b/src/libregex/lib.rs
index a48760913c16..44c206162ab2 100644
--- a/src/libregex/lib.rs
+++ b/src/libregex/lib.rs
@@ -360,7 +360,8 @@
#![license = "MIT/ASL2"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
- html_root_url = "http://doc.rust-lang.org/")]
+ html_root_url = "http://doc.rust-lang.org/",
+ html_playground_url = "http://play.rust-lang.org/")]
#![feature(macro_rules, phase)]
#![deny(missing_doc, deprecated_owned_vector)]
diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs
index f544e1e0973f..3c9358b03a98 100644
--- a/src/librustdoc/html/highlight.rs
+++ b/src/librustdoc/html/highlight.rs
@@ -25,7 +25,7 @@ use html::escape::Escape;
use t = syntax::parse::token;
/// Highlights some source code, returning the HTML output.
-pub fn highlight(src: &str, class: Option<&str>) -> String {
+pub fn highlight(src: &str, class: Option<&str>, id: Option<&str>) -> String {
debug!("highlighting: ================\n{}\n==============", src);
let sess = parse::new_parse_sess();
let fm = parse::string_to_filemap(&sess,
@@ -36,6 +36,7 @@ pub fn highlight(src: &str, class: Option<&str>) -> String {
doit(&sess,
lexer::StringReader::new(&sess.span_diagnostic, fm),
class,
+ id,
&mut out).unwrap();
str::from_utf8_lossy(out.unwrap().as_slice()).to_string()
}
@@ -47,11 +48,17 @@ pub fn highlight(src: &str, class: Option<&str>) -> String {
/// it's used. All source code emission is done as slices from the source map,
/// not from the tokens themselves, in order to stay true to the original
/// source.
-fn doit(sess: &parse::ParseSess, mut lexer: lexer::StringReader, class: Option<&str>,
+fn doit(sess: &parse::ParseSess, mut lexer: lexer::StringReader,
+ class: Option<&str>, id: Option<&str>,
out: &mut Writer) -> io::IoResult<()> {
use syntax::parse::lexer::Reader;
- try!(write!(out, "\n", class.unwrap_or("")));
+ try!(write!(out, " try!(write!(out, "id='{}' ", id)),
+ None => {}
+ }
+ try!(write!(out, "class='rust {}'>\n", class.unwrap_or("")));
let mut last = BytePos(0);
let mut is_attribute = false;
let mut is_macro = false;
diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs
index 80653878247f..e2fa57148c2c 100644
--- a/src/librustdoc/html/layout.rs
+++ b/src/librustdoc/html/layout.rs
@@ -16,6 +16,7 @@ pub struct Layout {
pub logo: String,
pub favicon: String,
pub krate: String,
+ pub playground_url: String,
}
pub struct Page<'a> {
@@ -108,11 +109,13 @@ r##"
+ {play_js}