From 1f4c63049ed2e323ba2961c19dc067f86dd61861 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 18 Mar 2014 11:53:32 -0500 Subject: [PATCH 01/22] Make method Vec::remove() public --- src/libstd/vec_ng.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/vec_ng.rs b/src/libstd/vec_ng.rs index d36617e192467..c51ab48207fd8 100644 --- a/src/libstd/vec_ng.rs +++ b/src/libstd/vec_ng.rs @@ -427,7 +427,7 @@ impl Vec { } } - fn remove(&mut self, index: uint) -> Option { + pub fn remove(&mut self, index: uint) -> Option { let len = self.len(); if index < len { unsafe { // infallible From 1607871dc2a5240177865210822238f66c1dfb2e Mon Sep 17 00:00:00 2001 From: Corey Richardson Date: Tue, 18 Mar 2014 10:42:23 -0400 Subject: [PATCH 02/22] rustc: disallow duplicate methods in trait impls Closes #8153 --- src/librustc/middle/typeck/collect.rs | 7 +++++++ src/test/compile-fail/issue-8153.rs | 26 ++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 src/test/compile-fail/issue-8153.rs diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs index fc6b4c91b4e89..f65c168f38295 100644 --- a/src/librustc/middle/typeck/collect.rs +++ b/src/librustc/middle/typeck/collect.rs @@ -48,6 +48,8 @@ use util::ppaux::Repr; use std::rc::Rc; use std::vec_ng::Vec; use std::vec_ng; +use collections::HashSet; + use syntax::abi::AbiSet; use syntax::ast::{RegionTyParamBound, TraitTyParamBound}; use syntax::ast; @@ -478,7 +480,12 @@ fn convert_methods(ccx: &CrateCtxt, rcvr_visibility: ast::Visibility) { let tcx = ccx.tcx; + let mut seen_methods = HashSet::new(); for m in ms.iter() { + if !seen_methods.insert(m.ident.repr(ccx.tcx)) { + tcx.sess.span_err(m.span, "duplicate method in trait impl"); + } + let num_rcvr_ty_params = rcvr_ty_generics.type_param_defs().len(); let m_ty_generics = ty_generics_for_fn_or_method(ccx, &m.generics, num_rcvr_ty_params); diff --git a/src/test/compile-fail/issue-8153.rs b/src/test/compile-fail/issue-8153.rs new file mode 100644 index 0000000000000..2af531135eca3 --- /dev/null +++ b/src/test/compile-fail/issue-8153.rs @@ -0,0 +1,26 @@ +// Copyright 2013 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. + +// Test that duplicate methods in impls are not allowed + +struct Foo; + +trait Bar { + fn bar(&self) -> int; +} + +impl Bar for Foo { + fn bar(&self) -> int {1} + fn bar(&self) -> int {2} //~ ERROR duplicate method +} + +fn main() { + println!("{}", Foo.bar()); +} From f9e0baa19a33c2b98f502d9604dabacd8f634965 Mon Sep 17 00:00:00 2001 From: Corey Richardson Date: Tue, 18 Mar 2014 12:04:23 -0400 Subject: [PATCH 03/22] remove duplicate methods in impls --- src/libserialize/json.rs | 2 +- src/libstd/str.rs | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/libserialize/json.rs b/src/libserialize/json.rs index 6ce555ba9f74a..33868641e5ff0 100644 --- a/src/libserialize/json.rs +++ b/src/libserialize/json.rs @@ -1312,7 +1312,7 @@ impl ::Decoder for Decoder { value => self.expected("number", &value) } } - fn read_f32(&mut self) -> f32 { self.read_f64() as f32 } + fn read_f32(&mut self) -> f32 { self.read_f64() as f32 } fn read_char(&mut self) -> char { diff --git a/src/libstd/str.rs b/src/libstd/str.rs index 3704e6e37eb55..ccd08e8a716c0 100644 --- a/src/libstd/str.rs +++ b/src/libstd/str.rs @@ -2664,9 +2664,6 @@ impl<'a> StrSlice<'a> for &'a str { return multibyte_char_range_at(*self, i); } - #[inline] - fn char_at(&self, i: uint) -> char { self.char_range_at(i).ch } - #[inline] fn char_range_at_reverse(&self, start: uint) -> CharRange { let mut prev = start; From 873f7408bdffdb05b23f77aa343abd05f2e3126c Mon Sep 17 00:00:00 2001 From: Corey Richardson Date: Tue, 18 Mar 2014 09:20:30 -0400 Subject: [PATCH 04/22] rustc: test: don't silently ignore bad benches This is adequate because when a function has a type that isn't caught here, that is, it has a single argument, but it *isn't* `&mut BenchHarness`, it errors later on with: error: mismatched types: expected `fn(&mut test::BenchHarness)` but found `fn(int)` (expected &-ptr but found int) which I consider acceptable. Closes #12997 --- src/librustc/front/test.rs | 15 ++++++++++----- src/test/compile-fail/issue-12997-1.rs | 19 +++++++++++++++++++ src/test/compile-fail/issue-12997-2.rs | 17 +++++++++++++++++ 3 files changed, 46 insertions(+), 5 deletions(-) create mode 100644 src/test/compile-fail/issue-12997-1.rs create mode 100644 src/test/compile-fail/issue-12997-2.rs diff --git a/src/librustc/front/test.rs b/src/librustc/front/test.rs index cf5373fd17de7..6d8029b1638c4 100644 --- a/src/librustc/front/test.rs +++ b/src/librustc/front/test.rs @@ -95,10 +95,9 @@ impl<'a> fold::Folder for TestHarnessGenerator<'a> { debug!("current path: {}", ast_util::path_name_i(self.cx.path.get().as_slice())); - if is_test_fn(&self.cx, i) || is_bench_fn(i) { + if is_test_fn(&self.cx, i) || is_bench_fn(&self.cx, i) { match i.node { - ast::ItemFn(_, purity, _, _, _) - if purity == ast::UnsafeFn => { + ast::ItemFn(_, ast::UnsafeFn, _, _, _) => { let sess = self.cx.sess; sess.span_fatal(i.span, "unsafe functions cannot be used for \ @@ -109,7 +108,7 @@ impl<'a> fold::Folder for TestHarnessGenerator<'a> { let test = Test { span: i.span, path: self.cx.path.get(), - bench: is_bench_fn(i), + bench: is_bench_fn(&self.cx, i), ignore: is_ignored(&self.cx, i), should_fail: should_fail(i) }; @@ -233,7 +232,7 @@ fn is_test_fn(cx: &TestCtxt, i: @ast::Item) -> bool { return has_test_attr && has_test_signature(i); } -fn is_bench_fn(i: @ast::Item) -> bool { +fn is_bench_fn(cx: &TestCtxt, i: @ast::Item) -> bool { let has_bench_attr = attr::contains_name(i.attrs.as_slice(), "bench"); fn has_test_signature(i: @ast::Item) -> bool { @@ -254,6 +253,12 @@ fn is_bench_fn(i: @ast::Item) -> bool { } } + if has_bench_attr && !has_test_signature(i) { + let sess = cx.sess; + sess.span_err(i.span, "functions used as benches must have signature \ + `fn(&mut BenchHarness) -> ()`"); + } + return has_bench_attr && has_test_signature(i); } diff --git a/src/test/compile-fail/issue-12997-1.rs b/src/test/compile-fail/issue-12997-1.rs new file mode 100644 index 0000000000000..193cbcb25b74d --- /dev/null +++ b/src/test/compile-fail/issue-12997-1.rs @@ -0,0 +1,19 @@ +// 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. + +// compile-flags: --test + +//! Test that makes sure wrongly-typed bench functions aren't ignored + +#[bench] +fn foo() { } //~ ERROR functions used as benches + +#[bench] +fn bar(x: int, y: int) { } //~ ERROR functions used as benches diff --git a/src/test/compile-fail/issue-12997-2.rs b/src/test/compile-fail/issue-12997-2.rs new file mode 100644 index 0000000000000..f520ce0eabba6 --- /dev/null +++ b/src/test/compile-fail/issue-12997-2.rs @@ -0,0 +1,17 @@ +// 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. + +// compile-flags: --test + +//! Test that makes sure wrongly-typed bench functions are rejected + +// error-pattern:expected &-ptr but found int +#[bench] +fn bar(x: int) { } From 92f0bc29355ac990595e1771c4bb9a3b7e358d30 Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Tue, 18 Mar 2014 23:40:07 +1100 Subject: [PATCH 05/22] rustc: buffer the output writer for -Z ast-json[-noexpand]. This takes the time for `rustc libstd/lib.rs -Z ast-json-noexpand > file.json` from 9.0s to 3.5s (~0.5s spent parsing etc.) and `-Z ast-json` from 11s to 5s (~1.5s spent parsing and expanding). --- src/librustc/driver/driver.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs index e7c1e214d070a..5926f535ad898 100644 --- a/src/librustc/driver/driver.rs +++ b/src/librustc/driver/driver.rs @@ -186,7 +186,7 @@ pub fn phase_1_parse_input(sess: &Session, cfg: ast::CrateConfig, input: &Input) }); if sess.opts.debugging_opts & session::AST_JSON_NOEXPAND != 0 { - let mut stdout = io::stdout(); + let mut stdout = io::BufferedWriter::new(io::stdout()); let mut json = json::PrettyEncoder::new(&mut stdout); krate.encode(&mut json); } @@ -261,7 +261,7 @@ pub fn phase_2_configure_and_expand(sess: &Session, front::assign_node_ids_and_map::assign_node_ids_and_map(sess, krate)); if sess.opts.debugging_opts & session::AST_JSON != 0 { - let mut stdout = io::stdout(); + let mut stdout = io::BufferedWriter::new(io::stdout()); let mut json = json::PrettyEncoder::new(&mut stdout); krate.encode(&mut json); } From 87c7c03f4585a35f1bc6d3e607a08e3beea48041 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 17 Mar 2014 22:27:37 -0700 Subject: [PATCH 06/22] syntax: Don't parameterize the the pretty printer The pretty printer constitues an enormous amount of code, there's no reason for it to be generic. This just least to a huge amount of metadata which isn't necessary. Instead, this change migrates the pretty printer to using a trait object instead. Closes #12985 --- src/librustc/driver/driver.rs | 8 +++---- src/librustc/middle/dataflow.rs | 2 +- src/libsyntax/fold.rs | 4 ++-- src/libsyntax/print/pprust.rs | 37 +++++++++++++++++---------------- 4 files changed, 26 insertions(+), 25 deletions(-) diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs index 5926f535ad898..94965e7e0dc3f 100644 --- a/src/librustc/driver/driver.rs +++ b/src/librustc/driver/driver.rs @@ -596,7 +596,7 @@ struct IdentifiedAnnotation; impl pprust::PpAnn for IdentifiedAnnotation { fn pre(&self, - s: &mut pprust::State, + s: &mut pprust::State, node: pprust::AnnNode) -> io::IoResult<()> { match node { pprust::NodeExpr(_) => s.popen(), @@ -604,7 +604,7 @@ impl pprust::PpAnn for IdentifiedAnnotation { } } fn post(&self, - s: &mut pprust::State, + s: &mut pprust::State, node: pprust::AnnNode) -> io::IoResult<()> { match node { pprust::NodeItem(item) => { @@ -634,7 +634,7 @@ struct TypedAnnotation { impl pprust::PpAnn for TypedAnnotation { fn pre(&self, - s: &mut pprust::State, + s: &mut pprust::State, node: pprust::AnnNode) -> io::IoResult<()> { match node { pprust::NodeExpr(_) => s.popen(), @@ -642,7 +642,7 @@ impl pprust::PpAnn for TypedAnnotation { } } fn post(&self, - s: &mut pprust::State, + s: &mut pprust::State, node: pprust::AnnNode) -> io::IoResult<()> { let tcx = &self.analysis.ty_cx; match node { diff --git a/src/librustc/middle/dataflow.rs b/src/librustc/middle/dataflow.rs index 4253f90ef794a..be49784cba189 100644 --- a/src/librustc/middle/dataflow.rs +++ b/src/librustc/middle/dataflow.rs @@ -85,7 +85,7 @@ struct LoopScope<'a> { impl<'a, O:DataFlowOperator> pprust::PpAnn for DataFlowContext<'a, O> { fn pre(&self, - ps: &mut pprust::State>, + ps: &mut pprust::State, node: pprust::AnnNode) -> io::IoResult<()> { let id = match node { pprust::NodeExpr(expr) => expr.id, diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 973682ea74369..d9510ddad4b16 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -880,8 +880,8 @@ mod test { use super::*; // this version doesn't care about getting comments or docstrings in. - fn fake_print_crate(s: &mut pprust::State, - krate: &ast::Crate) -> io::IoResult<()> { + fn fake_print_crate(s: &mut pprust::State, + krate: &ast::Crate) -> io::IoResult<()> { s.print_mod(&krate.module, krate.attrs.as_slice()) } diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index a35bdc307c080..2f96a71cc0fdb 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -43,8 +43,8 @@ pub enum AnnNode<'a> { } pub trait PpAnn { - fn pre(&self, _state: &mut State, _node: AnnNode) -> IoResult<()> { Ok(()) } - fn post(&self, _state: &mut State, _node: AnnNode) -> IoResult<()> { Ok(()) } + fn pre(&self, _state: &mut State, _node: AnnNode) -> IoResult<()> { Ok(()) } + fn post(&self, _state: &mut State, _node: AnnNode) -> IoResult<()> { Ok(()) } } pub struct NoAnn; @@ -56,7 +56,7 @@ pub struct CurrentCommentAndLiteral { cur_lit: uint, } -pub struct State<'a, A> { +pub struct State<'a> { s: pp::Printer, cm: Option<&'a CodeMap>, intr: @token::IdentInterner, @@ -64,15 +64,16 @@ pub struct State<'a, A> { literals: Option >, cur_cmnt_and_lit: CurrentCommentAndLiteral, boxes: RefCell >, - ann: &'a A + ann: &'a PpAnn } -pub fn rust_printer(writer: ~io::Writer) -> State<'static, NoAnn> { +pub fn rust_printer(writer: ~io::Writer) -> State<'static> { static NO_ANN: NoAnn = NoAnn; rust_printer_annotated(writer, &NO_ANN) } -pub fn rust_printer_annotated<'a, A: PpAnn>(writer: ~io::Writer, ann: &'a A) -> State<'a, A> { +pub fn rust_printer_annotated<'a>(writer: ~io::Writer, + ann: &'a PpAnn) -> State<'a> { State { s: pp::mk_printer(writer, default_columns), cm: None, @@ -95,14 +96,14 @@ pub static default_columns: uint = 78u; // Requires you to pass an input filename and reader so that // it can scan the input text for comments and literals to // copy forward. -pub fn print_crate<'a, A: PpAnn>(cm: &'a CodeMap, - span_diagnostic: &diagnostic::SpanHandler, - krate: &ast::Crate, - filename: ~str, - input: &mut io::Reader, - out: ~io::Writer, - ann: &'a A, - is_expanded: bool) -> IoResult<()> { +pub fn print_crate<'a>(cm: &'a CodeMap, + span_diagnostic: &diagnostic::SpanHandler, + krate: &ast::Crate, + filename: ~str, + input: &mut io::Reader, + out: ~io::Writer, + ann: &'a PpAnn, + is_expanded: bool) -> IoResult<()> { let (cmnts, lits) = comments::gather_comments_and_literals( span_diagnostic, filename, @@ -133,7 +134,7 @@ pub fn print_crate<'a, A: PpAnn>(cm: &'a CodeMap, eof(&mut s.s) } -pub fn to_str(f: |&mut State| -> IoResult<()>) -> ~str { +pub fn to_str(f: |&mut State| -> IoResult<()>) -> ~str { let mut s = rust_printer(~MemWriter::new()); f(&mut s).unwrap(); eof(&mut s.s).unwrap(); @@ -237,7 +238,7 @@ pub fn visibility_qualified(vis: ast::Visibility, s: &str) -> ~str { } } -impl<'a, A: PpAnn> State<'a, A> { +impl<'a> State<'a> { pub fn ibox(&mut self, u: uint) -> IoResult<()> { self.boxes.borrow_mut().get().push(pp::Inconsistent); pp::ibox(&mut self.s, u) @@ -365,7 +366,7 @@ impl<'a, A: PpAnn> State<'a, A> { } pub fn commasep(&mut self, b: Breaks, elts: &[T], - op: |&mut State, &T| -> IoResult<()>) + op: |&mut State, &T| -> IoResult<()>) -> IoResult<()> { try!(self.rbox(0u, b)); let mut first = true; @@ -381,7 +382,7 @@ impl<'a, A: PpAnn> State<'a, A> { &mut self, b: Breaks, elts: &[T], - op: |&mut State, &T| -> IoResult<()>, + op: |&mut State, &T| -> IoResult<()>, get_span: |&T| -> codemap::Span) -> IoResult<()> { try!(self.rbox(0u, b)); let len = elts.len(); From 4ab95bcf20e8ecee4bef874bcf552829cfc9567c Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Tue, 18 Mar 2014 12:19:18 +0800 Subject: [PATCH 07/22] `char`: s/character/Unicode scalar value/ Tweak the definition of `char` to use the appropriate Unicode terminology. --- src/doc/rust.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/doc/rust.md b/src/doc/rust.md index 7233288a81328..39b6261553618 100644 --- a/src/doc/rust.md +++ b/src/doc/rust.md @@ -3136,8 +3136,12 @@ machine. The types `char` and `str` hold textual data. -A value of type `char` is a Unicode character, -represented as a 32-bit unsigned word holding a UCS-4 codepoint. +A value of type `char` is a [Unicode scalar value]( +http://www.unicode.org/glossary/#unicode_scalar_value) +(ie. a code point that is not a surrogate), +represented as a 32-bit unsigned word in the 0x0000 to 0xD7FF +or 0xE000 to 0x10FFFF range. +A `[char]` vector is effectively an UCS-4 / UTF-32 string. A value of type `str` is a Unicode string, represented as a vector of 8-bit unsigned bytes holding a sequence of UTF-8 codepoints. From 083d423976359c3a0222907b588df534cfc17a28 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Tue, 18 Mar 2014 14:21:35 +1300 Subject: [PATCH 08/22] Move syntax-extension-hexfloat.rs Move syntax-extension-hexfloat.rs to run-pass-fulldeps so it depends on libhexfloat being compiled before running. --- .../{run-pass => run-pass-fulldeps}/syntax-extension-hexfloat.rs | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/test/{run-pass => run-pass-fulldeps}/syntax-extension-hexfloat.rs (100%) diff --git a/src/test/run-pass/syntax-extension-hexfloat.rs b/src/test/run-pass-fulldeps/syntax-extension-hexfloat.rs similarity index 100% rename from src/test/run-pass/syntax-extension-hexfloat.rs rename to src/test/run-pass-fulldeps/syntax-extension-hexfloat.rs From 3301223c99574d53bbdcd06ac85b3cec255128e0 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Tue, 18 Mar 2014 10:54:35 +1300 Subject: [PATCH 09/22] Fix linkage1 test which fails due to --as-needed It appears that the --as-needed flag to linkers will not pull in a dynamic library unless it satisfies a non weak undefined symbol. The linkage1 test was creating a dynamic library where it was only used for a weak-symbol as part of an executable, so the dynamic library was getting discarded. This commit adds another symbol to the library which satisfies a strong undefined symbol, so the library is pulled in to resolve the weak reference. --- src/test/auxiliary/linkage1.rs | 2 ++ src/test/run-pass/linkage1.rs | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/src/test/auxiliary/linkage1.rs b/src/test/auxiliary/linkage1.rs index 9017ee88363b7..a74c8c47cd9b7 100644 --- a/src/test/auxiliary/linkage1.rs +++ b/src/test/auxiliary/linkage1.rs @@ -10,3 +10,5 @@ #[no_mangle] pub static foo: int = 3; + +pub fn bar() {} diff --git a/src/test/run-pass/linkage1.rs b/src/test/run-pass/linkage1.rs index 8f8b0cfecb28d..c6f672c5d34d0 100644 --- a/src/test/run-pass/linkage1.rs +++ b/src/test/run-pass/linkage1.rs @@ -26,6 +26,13 @@ extern { } fn main() { + // It appears that the --as-needed flag to linkers will not pull in a dynamic + // library unless it satisfies a non weak undefined symbol. The 'other' crate + // is compiled as a dynamic library where it would only be used for a + // weak-symbol as part of an executable, so the dynamic library woudl be + // discarded. By adding and calling `other::bar`, we get around this problem. + other::bar(); + assert!(!foo.is_null()); assert_eq!(unsafe { *foo }, 3); assert!(something_that_should_never_exist.is_null()); From c800c985740a0fcc2e978b346d3f3b9390850b7b Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Sun, 16 Mar 2014 14:39:51 +0100 Subject: [PATCH 10/22] rustc: remove linker_private/linker_private_weak Remove the linker_private and linker_private_weak linkage attributes, they have been superseded by private and private_weak and have been removed in upstream LLVM in commit r203866. --- src/librustc/lib/llvm.rs | 2 -- src/librustc/middle/trans/foreign.rs | 2 -- 2 files changed, 4 deletions(-) diff --git a/src/librustc/lib/llvm.rs b/src/librustc/lib/llvm.rs index 448b9e30dcd3d..8cfe08dc975a1 100644 --- a/src/librustc/lib/llvm.rs +++ b/src/librustc/lib/llvm.rs @@ -59,8 +59,6 @@ pub enum Linkage { ExternalWeakLinkage = 12, GhostLinkage = 13, CommonLinkage = 14, - LinkerPrivateLinkage = 15, - LinkerPrivateWeakLinkage = 16, } #[deriving(Clone)] diff --git a/src/librustc/middle/trans/foreign.rs b/src/librustc/middle/trans/foreign.rs index fdc33666e8abb..7f6781096f584 100644 --- a/src/librustc/middle/trans/foreign.rs +++ b/src/librustc/middle/trans/foreign.rs @@ -121,8 +121,6 @@ pub fn llvm_linkage_by_name(name: &str) -> Option { "extern_weak" => Some(lib::llvm::ExternalWeakLinkage), "external" => Some(lib::llvm::ExternalLinkage), "internal" => Some(lib::llvm::InternalLinkage), - "linker_private" => Some(lib::llvm::LinkerPrivateLinkage), - "linker_private_weak" => Some(lib::llvm::LinkerPrivateWeakLinkage), "linkonce" => Some(lib::llvm::LinkOnceAnyLinkage), "linkonce_odr" => Some(lib::llvm::LinkOnceODRLinkage), "private" => Some(lib::llvm::PrivateLinkage), From 8f7a7970f3f01aa2266c6ce3ee031234b86b1b9b Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Mon, 17 Mar 2014 16:37:23 +0100 Subject: [PATCH 11/22] rustc: remove obsolete linkage types Remove obsolete linkage types from the llvm::Linkage enum. The linkage types are no-ops and weren't used inside rustc anyway. --- src/librustc/lib/llvm.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/librustc/lib/llvm.rs b/src/librustc/lib/llvm.rs index 8cfe08dc975a1..b98f3f6fd5d48 100644 --- a/src/librustc/lib/llvm.rs +++ b/src/librustc/lib/llvm.rs @@ -43,21 +43,21 @@ pub enum Visibility { ProtectedVisibility = 2, } +// This enum omits the obsolete (and no-op) linkage types DLLImportLinkage, +// DLLExportLinkage, GhostLinkage and LinkOnceODRAutoHideLinkage. +// LinkerPrivateLinkage and LinkerPrivateWeakLinkage are not included either; +// they've been removed in upstream LLVM commit r203866. pub enum Linkage { ExternalLinkage = 0, AvailableExternallyLinkage = 1, LinkOnceAnyLinkage = 2, LinkOnceODRLinkage = 3, - LinkOnceODRAutoHideLinkage = 4, WeakAnyLinkage = 5, WeakODRLinkage = 6, AppendingLinkage = 7, InternalLinkage = 8, PrivateLinkage = 9, - DLLImportLinkage = 10, - DLLExportLinkage = 11, ExternalWeakLinkage = 12, - GhostLinkage = 13, CommonLinkage = 14, } From 20e178c5821b32d7a7deab70af90bf50f9d39df3 Mon Sep 17 00:00:00 2001 From: Liigo Zhuang Date: Tue, 18 Mar 2014 08:59:44 +0800 Subject: [PATCH 12/22] libsyntax: librustdoc: ignore utf-8 BOM in .rs files Closes #12974 --- src/librustdoc/html/render.rs | 9 ++++++++- src/libsyntax/codemap.rs | 11 ++++++++++- src/test/run-pass/utf8-bom.rs | 13 +++++++++++++ 3 files changed, 31 insertions(+), 2 deletions(-) create mode 100644 src/test/run-pass/utf8-bom.rs diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 1ebb51cb65e9f..6ad7b7d9da122 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -463,6 +463,13 @@ impl<'a> SourceCollector<'a> { }; let contents = str::from_utf8_owned(contents).unwrap(); + // Remove the utf-8 BOM if any + let contents = if contents.starts_with("\ufeff") { + contents.as_slice().slice_from(3) + } else { + contents.as_slice() + }; + // Create the intermediate directories let mut cur = self.dst.clone(); let mut root_path = ~"../../"; @@ -482,7 +489,7 @@ impl<'a> SourceCollector<'a> { root_path: root_path, }; try!(layout::render(&mut w as &mut Writer, &self.cx.layout, - &page, &(""), &Source(contents.as_slice()))); + &page, &(""), &Source(contents))); try!(w.flush()); return Ok(()); } diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index 4bfd5391a8f10..d93b5803eac30 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -271,13 +271,22 @@ impl CodeMap { } } - pub fn new_filemap(&self, filename: FileName, mut src: ~str) -> Rc { + pub fn new_filemap(&self, filename: FileName, src: ~str) -> Rc { let mut files = self.files.borrow_mut(); let start_pos = match files.get().last() { None => 0, Some(last) => last.deref().start_pos.to_uint() + last.deref().src.len(), }; + // Remove utf-8 BOM if any. + // FIXME #12884: no efficient/safe way to remove from the start of a string + // and reuse the allocation. + let mut src = if src.starts_with("\ufeff") { + src.as_slice().slice_from(3).into_owned() + } else { + src + }; + // Append '\n' in case it's not already there. // This is a workaround to prevent CodeMap.lookup_filemap_idx from accidentally // overflowing into the next filemap in case the last byte of span is also the last diff --git a/src/test/run-pass/utf8-bom.rs b/src/test/run-pass/utf8-bom.rs new file mode 100644 index 0000000000000..ccd40cb88fe08 --- /dev/null +++ b/src/test/run-pass/utf8-bom.rs @@ -0,0 +1,13 @@ +// 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. + +// This file has utf-8 BOM, it should be compiled normally without error. + +pub fn main() {} From 22655120332293901f8d4cb822e10a8aa6ee3697 Mon Sep 17 00:00:00 2001 From: Jeff Olson Date: Mon, 17 Mar 2014 00:26:36 -0700 Subject: [PATCH 13/22] closes #12967 fix [en|de]coding of HashMap where K is a numeric type serialize: ref #12697 minor adj. to last char check + prettyencode test --- src/libserialize/json.rs | 85 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 84 insertions(+), 1 deletion(-) diff --git a/src/libserialize/json.rs b/src/libserialize/json.rs index 33868641e5ff0..9b93a62304c88 100644 --- a/src/libserialize/json.rs +++ b/src/libserialize/json.rs @@ -464,8 +464,20 @@ impl<'a> ::Encoder for Encoder<'a> { } fn emit_map_elt_key(&mut self, idx: uint, f: |&mut Encoder<'a>|) { + use std::str::from_utf8; if idx != 0 { try!(write!(self.wr, ",")) } - f(self) + // ref #12967, make sure to wrap a key in double quotes, + // in the event that its of a type that omits them (eg numbers) + let mut buf = MemWriter::new(); + let mut check_encoder = Encoder::new(&mut buf); + f(&mut check_encoder); + let buf = buf.unwrap(); + let out = from_utf8(buf).unwrap(); + let needs_wrapping = out.char_at(0) != '"' && + out.char_at_reverse(out.len()) != '"'; + if needs_wrapping { try!(write!(self.wr, "\"")); } + f(self); + if needs_wrapping { try!(write!(self.wr, "\"")); } } fn emit_map_elt_val(&mut self, _idx: uint, f: |&mut Encoder<'a>|) { @@ -659,13 +671,25 @@ impl<'a> ::Encoder for PrettyEncoder<'a> { } fn emit_map_elt_key(&mut self, idx: uint, f: |&mut PrettyEncoder<'a>|) { + use std::str::from_utf8; if idx == 0 { try!(write!(self.wr, "\n")); } else { try!(write!(self.wr, ",\n")); } try!(write!(self.wr, "{}", spaces(self.indent))); + // ref #12967, make sure to wrap a key in double quotes, + // in the event that its of a type that omits them (eg numbers) + let mut buf = MemWriter::new(); + let mut check_encoder = PrettyEncoder::new(&mut buf); + f(&mut check_encoder); + let buf = buf.unwrap(); + let out = from_utf8(buf).unwrap(); + let needs_wrapping = out.char_at(0) != '"' && + out.char_at_reverse(out.len()) != '"'; + if needs_wrapping { try!(write!(self.wr, "\"")); } f(self); + if needs_wrapping { try!(write!(self.wr, "\"")); } } fn emit_map_elt_val(&mut self, _idx: uint, f: |&mut PrettyEncoder<'a>|) { @@ -1306,9 +1330,15 @@ impl ::Decoder for Decoder { } fn read_f64(&mut self) -> f64 { + use std::from_str::FromStr; debug!("read_f64"); match self.stack.pop().unwrap() { Number(f) => f, + String(s) => { + // re: #12967.. a type w/ numeric keys (ie HashMap etc) + // is going to have a string here, as per JSON spec.. + FromStr::from_str(s).unwrap() + }, value => self.expected("number", &value) } } @@ -2519,4 +2549,57 @@ mod tests { let expected_null = (); assert!(json_null.is_some() && json_null.unwrap() == expected_null); } + + #[test] + fn test_encode_hashmap_with_numeric_key() { + use std::str::from_utf8; + use std::io::Writer; + use std::io::MemWriter; + use collections::HashMap; + let mut hm: HashMap = HashMap::new(); + hm.insert(1, true); + let mut mem_buf = MemWriter::new(); + { + let mut encoder = Encoder::new(&mut mem_buf as &mut io::Writer); + hm.encode(&mut encoder) + } + let bytes = mem_buf.unwrap(); + let json_str = from_utf8(bytes).unwrap(); + match from_str(json_str) { + Err(_) => fail!("Unable to parse json_str: {:?}", json_str), + _ => {} // it parsed and we are good to go + } + } + #[test] + fn test_prettyencode_hashmap_with_numeric_key() { + use std::str::from_utf8; + use std::io::Writer; + use std::io::MemWriter; + use collections::HashMap; + let mut hm: HashMap = HashMap::new(); + hm.insert(1, true); + let mut mem_buf = MemWriter::new(); + { + let mut encoder = PrettyEncoder::new(&mut mem_buf as &mut io::Writer); + hm.encode(&mut encoder) + } + let bytes = mem_buf.unwrap(); + let json_str = from_utf8(bytes).unwrap(); + match from_str(json_str) { + Err(_) => fail!("Unable to parse json_str: {:?}", json_str), + _ => {} // it parsed and we are good to go + } + } + #[test] + fn test_hashmap_with_numeric_key_can_handle_double_quote_delimited_key() { + use collections::HashMap; + use Decodable; + let json_str = "{\"1\":true}"; + let json_obj = match from_str(json_str) { + Err(_) => fail!("Unable to parse json_str: {:?}", json_str), + Ok(o) => o + }; + let mut decoder = Decoder::new(json_obj); + let hm: HashMap = Decodable::decode(&mut decoder); + } } From e627bce939cfe83b9c8b02c5805388b472d3dfcf Mon Sep 17 00:00:00 2001 From: Eunchong Yu Date: Mon, 17 Mar 2014 15:30:27 +0900 Subject: [PATCH 14/22] Add impl IntoStr for ::std::vec_ng::Vec --- src/libstd/ascii.rs | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/libstd/ascii.rs b/src/libstd/ascii.rs index a21393e268954..3ca08797dd1fe 100644 --- a/src/libstd/ascii.rs +++ b/src/libstd/ascii.rs @@ -20,6 +20,7 @@ use cast; use fmt; use iter::Iterator; use vec::{ImmutableVector, MutableVector, Vector}; +use vec_ng::Vec; use option::{Option, Some, None}; /// Datatype to hold one ascii character. It wraps a `u8`, with the highest bit always zero. @@ -305,6 +306,14 @@ impl IntoStr for ~[Ascii] { } } +impl IntoStr for Vec { + #[inline] + fn into_str(self) -> ~str { + let v: ~[Ascii] = self.move_iter().collect(); + unsafe { cast::transmute(v) } + } +} + /// Trait to convert to an owned byte array by consuming self pub trait IntoBytes { /// Converts to an owned byte array by consuming self @@ -473,6 +482,7 @@ mod tests { use super::*; use str::from_char; use char::from_u32; + use vec_ng::Vec; macro_rules! v2ascii ( ( [$($e:expr),*]) => (&[$(Ascii{chr:$e}),*]); @@ -480,6 +490,10 @@ mod tests { (~[$($e:expr),*]) => (~[$(Ascii{chr:$e}),*]); ) + macro_rules! vec2ascii ( + ($($e:expr),*) => (Vec::from_slice([$(Ascii{chr:$e}),*])); + ) + #[test] fn test_ascii() { assert_eq!(65u8.to_ascii().to_byte(), 65u8); @@ -535,6 +549,17 @@ mod tests { } + #[test] + fn test_ascii_vec_ng() { + assert_eq!(Vec::from_slice("abCDef&?#".to_ascii().to_lower()).into_str(), ~"abcdef&?#"); + assert_eq!(Vec::from_slice("abCDef&?#".to_ascii().to_upper()).into_str(), ~"ABCDEF&?#"); + + assert_eq!(Vec::from_slice("".to_ascii().to_lower()).into_str(), ~""); + assert_eq!(Vec::from_slice("YMCA".to_ascii().to_lower()).into_str(), ~"ymca"); + assert_eq!(Vec::from_slice("abcDEFxyz:.;".to_ascii().to_upper()).into_str(), + ~"ABCDEFXYZ:.;"); + } + #[test] fn test_owned_ascii_vec() { assert_eq!((~"( ;").into_ascii(), v2ascii!(~[40, 32, 59])); @@ -550,6 +575,7 @@ mod tests { #[test] fn test_ascii_into_str() { assert_eq!(v2ascii!(~[40, 32, 59]).into_str(), ~"( ;"); + assert_eq!(vec2ascii!(40, 32, 59).into_str(), ~"( ;"); } #[test] From 175bf9470a2f1b95215b4b5dc1f12d949a0f8ddd Mon Sep 17 00:00:00 2001 From: Alan Andrade Date: Sun, 16 Mar 2014 22:53:54 -0700 Subject: [PATCH 15/22] deny missing docs --- src/libgetopts/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libgetopts/lib.rs b/src/libgetopts/lib.rs index 43b05e7e2e71f..5abe96b1acc46 100644 --- a/src/libgetopts/lib.rs +++ b/src/libgetopts/lib.rs @@ -83,7 +83,7 @@ #[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://static.rust-lang.org/doc/master")]; -#[allow(missing_doc)]; +#[deny(missing_doc)]; #[allow(deprecated_owned_vector)]; #[feature(globs, phase)]; From c297cff7771a84c417913b2023353cf44f9e260c Mon Sep 17 00:00:00 2001 From: Ziad Hatahet Date: Sun, 16 Mar 2014 20:42:25 -0700 Subject: [PATCH 16/22] Documentation and formatting changes for option.rs. --- src/libstd/option.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/libstd/option.rs b/src/libstd/option.rs index e4d843d88824d..9327136c771f0 100644 --- a/src/libstd/option.rs +++ b/src/libstd/option.rs @@ -149,7 +149,7 @@ impl Option { } } - /// Returns the contained value or a default + /// Returns the contained value or a default. #[inline] pub fn unwrap_or(self, def: T) -> T { match self { @@ -158,7 +158,7 @@ impl Option { } } - /// Returns the contained value or computes it from a closure + /// Returns the contained value or computes it from a closure. #[inline] pub fn unwrap_or_else(self, f: || -> T) -> T { match self { @@ -183,7 +183,7 @@ impl Option { match self { None => def, Some(t) => f(t) } } - /// Apply a function to the contained value or do nothing. + /// Applies a function to the contained value or does nothing. /// Returns true if the contained value was mutated. pub fn mutate(&mut self, f: |T| -> T) -> bool { if self.is_some() { @@ -192,7 +192,7 @@ impl Option { } else { false } } - /// Apply a function to the contained value or set it to a default. + /// Applies a function to the contained value or sets it to a default. /// Returns true if the contained value was mutated, or false if set to the default. pub fn mutate_or_set(&mut self, def: T, f: |T| -> T) -> bool { if self.is_some() { @@ -208,19 +208,19 @@ impl Option { // Iterator constructors ///////////////////////////////////////////////////////////////////////// - /// Return an iterator over the possibly contained value + /// Returns an iterator over the possibly contained value. #[inline] pub fn iter<'r>(&'r self) -> Item<&'r T> { Item{opt: self.as_ref()} } - /// Return a mutable iterator over the possibly contained value + /// Returns a mutable iterator over the possibly contained value. #[inline] pub fn mut_iter<'r>(&'r mut self) -> Item<&'r mut T> { Item{opt: self.as_mut()} } - /// Return a consuming iterator over the possibly contained value + /// Returns a consuming iterator over the possibly contained value. #[inline] pub fn move_iter(self) -> Item { Item{opt: self} @@ -264,7 +264,7 @@ impl Option { pub fn or_else(self, f: || -> Option) -> Option { match self { Some(_) => self, - None => f(), + None => f() } } @@ -272,7 +272,7 @@ impl Option { // Misc ///////////////////////////////////////////////////////////////////////// - /// Take the value out of the option, leaving a `None` in its place. + /// Takes the value out of the option, leaving a `None` in its place. #[inline] pub fn take(&mut self) -> Option { mem::replace(self, None) @@ -282,7 +282,7 @@ impl Option { #[inline(always)] pub fn filtered(self, f: |t: &T| -> bool) -> Option { match self { - Some(x) => if f(&x) {Some(x)} else {None}, + Some(x) => if f(&x) { Some(x) } else { None }, None => None } } From 168cd3a2f57ff418ebf87433bff678c85cad6a18 Mon Sep 17 00:00:00 2001 From: Jonathan S Date: Sun, 16 Mar 2014 19:39:38 -0500 Subject: [PATCH 17/22] Relaxed the memory ordering on the implementation of UnsafeArc --- src/libstd/sync/arc.rs | 36 +++++++++++++++++++++++++++++------- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/src/libstd/sync/arc.rs b/src/libstd/sync/arc.rs index 10369a52f0f17..56c71a5e4ff79 100644 --- a/src/libstd/sync/arc.rs +++ b/src/libstd/sync/arc.rs @@ -1,4 +1,4 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -26,7 +26,7 @@ use clone::Clone; use kinds::Send; use ops::Drop; use ptr::RawPtr; -use sync::atomics::{AtomicUint, SeqCst, Relaxed, Acquire}; +use sync::atomics::{fence, AtomicUint, Relaxed, Acquire, Release}; use vec; /// An atomically reference counted pointer. @@ -109,8 +109,16 @@ impl UnsafeArc { impl Clone for UnsafeArc { fn clone(&self) -> UnsafeArc { unsafe { - // This barrier might be unnecessary, but I'm not sure... - let old_count = (*self.data).count.fetch_add(1, Acquire); + // Using a relaxed ordering is alright here, as knowledge of the original reference + // prevents other threads from erroneously deleting the object. + // + // As explained in the [Boost documentation][1], + // Increasing the reference counter can always be done with memory_order_relaxed: New + // references to an object can only be formed from an existing reference, and passing + // an existing reference from one thread to another must already provide any required + // synchronization. + // [1]: (www.boost.org/doc/libs/1_55_0/doc/html/atomic/usage_examples.html) + let old_count = (*self.data).count.fetch_add(1, Relaxed); // FIXME(#12049): this needs some sort of debug assertion if cfg!(test) { assert!(old_count >= 1); } return UnsafeArc { data: self.data }; @@ -127,12 +135,26 @@ impl Drop for UnsafeArc{ if self.data.is_null() { return } - // Must be acquire+release, not just release, to make sure this - // doesn't get reordered to after the unwrapper pointer load. - let old_count = (*self.data).count.fetch_sub(1, SeqCst); + // Because `fetch_sub` is already atomic, we do not need to synchronize with other + // threads unless we are going to delete the object. + let old_count = (*self.data).count.fetch_sub(1, Release); // FIXME(#12049): this needs some sort of debug assertion if cfg!(test) { assert!(old_count >= 1); } if old_count == 1 { + // This fence is needed to prevent reordering of use of the data and deletion of + // the data. Because it is marked `Release`, the decreasing of the reference count + // sychronizes with this `Acquire` fence. This means that use of the data happens + // before decreasing the refernce count, which happens before this fence, which + // happens before the deletion of the data. + // + // As explained in the [Boost documentation][1], + // It is important to enforce any possible access to the object in one thread + // (through an existing reference) to *happen before* deleting the object in a + // different thread. This is achieved by a "release" operation after dropping a + // reference (any access to the object through this reference must obviously + // happened before), and an "acquire" operation before deleting the object. + // [1]: (www.boost.org/doc/libs/1_55_0/doc/html/atomic/usage_examples.html) + fence(Acquire); let _: ~ArcData = cast::transmute(self.data); } } From 783a00e7962bcf348aedaa0446c12b03ba1f0397 Mon Sep 17 00:00:00 2001 From: Lindsey Kuper Date: Sun, 16 Mar 2014 20:12:49 -0400 Subject: [PATCH 18/22] Typo fixes. --- src/doc/rustdoc.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/doc/rustdoc.md b/src/doc/rustdoc.md index 3359cd4f40d95..5d41f297e7d05 100644 --- a/src/doc/rustdoc.md +++ b/src/doc/rustdoc.md @@ -43,7 +43,7 @@ pub fn recalibrate() { Doc comments are markdown, and are currently parsed with the [sundown][sundown] library. rustdoc does not yet do any fanciness such as referencing other items inline, like javadoc's `@see`. One exception to this -is that the first paragrah will be used as the "summary" of an item in the +is that the first paragraph will be used as the "summary" of an item in the generated documentation: ~~~ @@ -79,11 +79,11 @@ rustdoc can also generate JSON, for consumption by other tools, with # Using the Documentation -The web pages generated by rustdoc present the same logical heirarchy that one +The web pages generated by rustdoc present the same logical hierarchy that one writes a library with. Every kind of item (function, struct, etc) has its own color, and one can always click on a colored type to jump to its documentation. There is a search bar at the top, which is powered by some -javascript and a statically-generated search index. No special web server is +JavaScript and a statically-generated search index. No special web server is required for the search. [sundown]: https://github.com/vmg/sundown/ @@ -108,7 +108,7 @@ code, the `ignore` string can be added to the three-backtick form of markdown code block. /** - # nested codefences confuse sundown => indentation + comment to + # nested code fences confuse sundown => indentation + comment to # avoid failing tests ``` // This is a testable code block @@ -126,7 +126,7 @@ You can specify that the test's execution should fail with the `should_fail` directive. /** - # nested codefences confuse sundown => indentation + comment to + # nested code fences confuse sundown => indentation + comment to # avoid failing tests ```should_fail // This code block is expected to generate a failure when run @@ -138,7 +138,7 @@ You can specify that the code block should be compiled but not run with the `no_run` directive. /** - # nested codefences confuse sundown => indentation + comment to + # nested code fences confuse sundown => indentation + comment to # avoid failing tests ```no_run // This code will be compiled but not executed @@ -153,7 +153,7 @@ testing the code block (NB. the space after the `#` is required, so that one can still write things like `#[deriving(Eq)]`). /** - # nested codefences confuse sundown => indentation + comment to + # nested code fences confuse sundown => indentation + comment to # avoid failing tests ```rust # /!\ The three following lines are comments, which are usually stripped off by @@ -162,7 +162,7 @@ that one can still write things like `#[deriving(Eq)]`). # these first five lines but a non breakable one. # # // showing 'fib' in this documentation would just be tedious and detracts from - # // what's actualy being documented. + # // what's actually being documented. # fn fib(n: int) { n + 2 } do spawn { fib(200); } @@ -190,7 +190,7 @@ $ rustdoc --test lib.rs --test-args '--help' ~~~ When testing a library, code examples will often show how functions are used, -and this code often requires `use`-ing paths from the crate. To accomodate this, +and this code often requires `use`-ing paths from the crate. To accommodate this, rustdoc will implicitly add `extern crate ;` where `` is the name of the crate being tested to the top of each code example. This means that rustdoc must be able to find a compiled version of the library crate being tested. Extra From d717d613e34482d7ddb738cea927900ca6601094 Mon Sep 17 00:00:00 2001 From: Matthew McPherrin Date: Sun, 16 Mar 2014 15:35:35 -0700 Subject: [PATCH 19/22] Docsprint: Document ops module, primarily Deref. --- src/libstd/ops.rs | 80 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 77 insertions(+), 3 deletions(-) diff --git a/src/libstd/ops.rs b/src/libstd/ops.rs index 2d5d37e1abc51..49bd95f621def 100644 --- a/src/libstd/ops.rs +++ b/src/libstd/ops.rs @@ -8,9 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// So we don't have to document the actual methods on the traits. -#[allow(missing_doc)]; - /*! * * Traits representing built-in operators, useful for overloading @@ -83,6 +80,7 @@ */ #[lang="drop"] pub trait Drop { + /// The `drop` method, called when the value goes out of scope. fn drop(&mut self); } @@ -112,6 +110,7 @@ pub trait Drop { */ #[lang="add"] pub trait Add { + /// The method for the `+` operator fn add(&self, rhs: &RHS) -> Result; } @@ -141,6 +140,7 @@ pub trait Add { */ #[lang="sub"] pub trait Sub { + /// The method for the `-` operator fn sub(&self, rhs: &RHS) -> Result; } @@ -170,6 +170,7 @@ pub trait Sub { */ #[lang="mul"] pub trait Mul { + /// The method for the `*` operator fn mul(&self, rhs: &RHS) -> Result; } @@ -199,6 +200,7 @@ pub trait Mul { */ #[lang="div"] pub trait Div { + /// The method for the `/` operator fn div(&self, rhs: &RHS) -> Result; } @@ -228,6 +230,7 @@ pub trait Div { */ #[lang="rem"] pub trait Rem { + /// The method for the `%` operator fn rem(&self, rhs: &RHS) -> Result; } @@ -257,6 +260,7 @@ pub trait Rem { */ #[lang="neg"] pub trait Neg { + /// The method for the unary `-` operator fn neg(&self) -> Result; } @@ -286,6 +290,7 @@ pub trait Neg { */ #[lang="not"] pub trait Not { + /// The method for the unary `!` operator fn not(&self) -> Result; } @@ -315,6 +320,7 @@ pub trait Not { */ #[lang="bitand"] pub trait BitAnd { + /// The method for the `&` operator fn bitand(&self, rhs: &RHS) -> Result; } @@ -344,6 +350,7 @@ pub trait BitAnd { */ #[lang="bitor"] pub trait BitOr { + /// The method for the `|` operator fn bitor(&self, rhs: &RHS) -> Result; } @@ -373,6 +380,7 @@ pub trait BitOr { */ #[lang="bitxor"] pub trait BitXor { + /// The method for the `^` operator fn bitxor(&self, rhs: &RHS) -> Result; } @@ -402,6 +410,7 @@ pub trait BitXor { */ #[lang="shl"] pub trait Shl { + /// The method for the `<<` operator fn shl(&self, rhs: &RHS) -> Result; } @@ -431,6 +440,7 @@ pub trait Shl { */ #[lang="shr"] pub trait Shr { + /// The method for the `>>` operator fn shr(&self, rhs: &RHS) -> Result; } @@ -461,6 +471,7 @@ pub trait Shr { */ #[lang="index"] pub trait Index { + /// The method for the indexing (`Foo[Bar]`) operation fn index(&self, index: &Index) -> Result; } @@ -469,9 +480,37 @@ pub trait Deref { fn deref<'a>(&'a self) -> &'a Result; } +/** + * + * The `Deref` trait is used to specify the functionality of dereferencing + * operations like `*v`. + * + * # Example + * + * A struct with a single field which is accessible via dereferencing the + * struct. + * + * ``` + * struct DerefExample { + * value: T + * } + * + * impl Deref for DerefExample { + * fn deref<'a>(&'a self) -> &'a T { + * &self.value + * } + * } + * + * fn main() { + * let x = DerefExample { value: 'a' }; + * assert_eq!('a', *x); + * } + * ``` + */ #[cfg(not(stage0))] #[lang="deref"] pub trait Deref { + /// The method called to dereference a value fn deref<'a>(&'a self) -> &'a Result; } @@ -480,9 +519,44 @@ pub trait DerefMut: Deref { fn deref_mut<'a>(&'a mut self) -> &'a mut Result; } +/** + * + * The `DerefMut` trait is used to specify the functionality of dereferencing + * mutably like `*v = 1;` + * + * # Example + * + * A struct with a single field which is modifiable via dereferencing the + * struct. + * + * ``` + * struct DerefMutExample { + * value: T + * } + * + * impl Deref for DerefMutExample { + * fn deref<'a>(&'a self) -> &'a T { + * &self.value + * } + * } + * + * impl DerefMut for DerefMutExample { + * fn deref_mut<'a>(&'a mut self) -> &'a mut T { + * &mut self.value + * } + * } + * + * fn main() { + * let mut x = DerefMutExample { value: 'a' }; + * *x = 'b'; + * assert_eq!('b', *x); + * } + * ``` + */ #[cfg(not(stage0))] #[lang="deref_mut"] pub trait DerefMut: Deref { + /// The method called to mutably dereference a value fn deref_mut<'a>(&'a mut self) -> &'a mut Result; } From 848f7b734ec88964879f5a3051b940d48469ce2e Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sun, 16 Mar 2014 01:08:56 -0700 Subject: [PATCH 20/22] rustdoc: Implement cross-crate searching A major discoverability issue with rustdoc is that all crates have their documentation built in isolation, so it's difficult when looking at the documentation for libstd to learn that there's a libcollections crate with a HashMap in it. This commit moves rustdoc a little closer to improving the multiple crate experience. This unifies all search indexes for all crates into one file so all pages share the same search index. This allows searching to work across crates in the same documentation directory (as the standard distribution is currently built). This strategy involves updating a shared file amongst many rustdoc processes, so I implemented a simple file locking API for handling synchronization for updates to the shared files. cc #12554 --- src/librustdoc/flock.rs | 191 ++++++++++++++++++++++ src/librustdoc/html/layout.rs | 17 +- src/librustdoc/html/render.rs | 85 ++++++---- src/librustdoc/html/static/main.js | 244 +++++++++++++++-------------- src/librustdoc/lib.rs | 1 + src/libstd/libc.rs | 2 +- 6 files changed, 383 insertions(+), 157 deletions(-) create mode 100644 src/librustdoc/flock.rs diff --git a/src/librustdoc/flock.rs b/src/librustdoc/flock.rs new file mode 100644 index 0000000000000..f5f755751133c --- /dev/null +++ b/src/librustdoc/flock.rs @@ -0,0 +1,191 @@ +// 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. + +//! Simple file-locking apis for each OS. +//! +//! This is not meant to be in the standard library, it does nothing with +//! green/native threading. This is just a bare-bones enough solution for +//! librustdoc, it is not production quality at all. + +#[allow(non_camel_case_types)]; + +pub use self::imp::Lock; + +#[cfg(unix)] +mod imp { + use std::libc; + + #[cfg(target_os = "linux")] + mod os { + use std::libc; + + pub struct flock { + l_type: libc::c_short, + l_whence: libc::c_short, + l_start: libc::off_t, + l_len: libc::off_t, + l_pid: libc::pid_t, + + // not actually here, but brings in line with freebsd + l_sysid: libc::c_int, + } + + pub static F_WRLCK: libc::c_short = 1; + pub static F_UNLCK: libc::c_short = 2; + pub static F_SETLK: libc::c_int = 6; + pub static F_SETLKW: libc::c_int = 7; + } + + #[cfg(target_os = "freebsd")] + mod os { + use std::libc; + + pub struct flock { + l_start: libc::off_t, + l_len: libc::off_t, + l_pid: libc::pid_t, + l_type: libc::c_short, + l_whence: libc::c_short, + l_sysid: libc::c_int, + } + + pub static F_UNLCK: libc::c_short = 2; + pub static F_WRLCK: libc::c_short = 3; + pub static F_SETLK: libc::c_int = 12; + pub static F_SETLKW: libc::c_int = 13; + } + + #[cfg(target_os = "macos")] + mod os { + use std::libc; + + pub struct flock { + l_start: libc::off_t, + l_len: libc::off_t, + l_pid: libc::pid_t, + l_type: libc::c_short, + l_whence: libc::c_short, + + // not actually here, but brings in line with freebsd + l_sysid: libc::c_int, + } + + pub static F_UNLCK: libc::c_short = 2; + pub static F_WRLCK: libc::c_short = 3; + pub static F_SETLK: libc::c_int = 8; + pub static F_SETLKW: libc::c_int = 9; + } + + pub struct Lock { + priv fd: libc::c_int, + } + + impl Lock { + pub fn new(p: &Path) -> Lock { + let fd = p.with_c_str(|s| unsafe { + libc::open(s, libc::O_RDWR | libc::O_CREAT, libc::S_IRWXU) + }); + assert!(fd > 0); + let flock = os::flock { + l_start: 0, + l_len: 0, + l_pid: 0, + l_whence: libc::SEEK_SET as libc::c_short, + l_type: os::F_WRLCK, + l_sysid: 0, + }; + let ret = unsafe { + libc::fcntl(fd, os::F_SETLKW, &flock as *os::flock) + }; + if ret == -1 { + unsafe { libc::close(fd); } + fail!("could not lock `{}`", p.display()) + } + Lock { fd: fd } + } + } + + impl Drop for Lock { + fn drop(&mut self) { + let flock = os::flock { + l_start: 0, + l_len: 0, + l_pid: 0, + l_whence: libc::SEEK_SET as libc::c_short, + l_type: os::F_UNLCK, + l_sysid: 0, + }; + unsafe { + libc::fcntl(self.fd, os::F_SETLK, &flock as *os::flock); + libc::close(self.fd); + } + } + } +} + +#[cfg(windows)] +mod imp { + use std::libc; + use std::mem; + use std::os::win32::as_utf16_p; + use std::ptr; + + static LOCKFILE_EXCLUSIVE_LOCK: libc::DWORD = 0x00000002; + + extern "system" { + fn LockFileEx(hFile: libc::HANDLE, + dwFlags: libc::DWORD, + dwReserved: libc::DWORD, + nNumberOfBytesToLockLow: libc::DWORD, + nNumberOfBytesToLockHigh: libc::DWORD, + lpOverlapped: libc::LPOVERLAPPED) -> libc::BOOL; + fn UnlockFileEx(hFile: libc::HANDLE, + dwReserved: libc::DWORD, + nNumberOfBytesToLockLow: libc::DWORD, + nNumberOfBytesToLockHigh: libc::DWORD, + lpOverlapped: libc::LPOVERLAPPED) -> libc::BOOL; + } + + pub struct Lock { + priv handle: libc::HANDLE, + } + + impl Lock { + pub fn new(p: &Path) -> Lock { + let handle = as_utf16_p(p.as_str().unwrap(), |p| unsafe { + libc::CreateFileW(p, libc::GENERIC_READ, 0, ptr::mut_null(), + libc::CREATE_ALWAYS, + libc::FILE_ATTRIBUTE_NORMAL, + ptr::mut_null()) + }); + assert!(handle as uint != libc::INVALID_HANDLE_VALUE as uint); + let mut overlapped: libc::OVERLAPPED = unsafe { mem::init() }; + let ret = unsafe { + LockFileEx(handle, LOCKFILE_EXCLUSIVE_LOCK, 0, 100, 0, + &mut overlapped) + }; + if ret == 0 { + unsafe { libc::CloseHandle(handle); } + fail!("could not lock `{}`", p.display()) + } + Lock { handle: handle } + } + } + + impl Drop for Lock { + fn drop(&mut self) { + let mut overlapped: libc::OVERLAPPED = unsafe { mem::init() }; + unsafe { + UnlockFileEx(self.handle, 0, 100, 0, &mut overlapped); + libc::CloseHandle(self.handle); + } + } + } +} diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs index c49df49dc1111..317571ebc3ff6 100644 --- a/src/librustdoc/html/layout.rs +++ b/src/librustdoc/html/layout.rs @@ -37,7 +37,7 @@ pub fn render( - + {favicon, select, none{} other{}} @@ -74,13 +74,6 @@ pub fn render(
- - - - -

Keyboard shortcuts

@@ -111,6 +104,14 @@ pub fn render(

+ + + + + ", diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 6ad7b7d9da122..26723482595cd 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -36,7 +36,7 @@ use std::fmt; use std::local_data; use std::io; -use std::io::{fs, File, BufferedWriter}; +use std::io::{fs, File, BufferedWriter, MemWriter, BufferedReader}; use std::str; use std::vec; use std::vec_ng::Vec; @@ -283,48 +283,75 @@ pub fn run(mut krate: clean::Crate, dst: Path) -> io::IoResult<()> { }; } - // Add all the static files - let mut dst = cx.dst.join(krate.name.as_slice()); - try!(mkdir(&dst)); - try!(write(dst.join("jquery.js"), - include_str!("static/jquery-2.1.0.min.js"))); - try!(write(dst.join("main.js"), include_str!("static/main.js"))); - try!(write(dst.join("main.css"), include_str!("static/main.css"))); - try!(write(dst.join("normalize.css"), - include_str!("static/normalize.css"))); - // Publish the search index - { - dst.push("search-index.js"); - let mut w = BufferedWriter::new(File::create(&dst).unwrap()); - let w = &mut w as &mut Writer; - try!(write!(w, "var searchIndex = [")); + let index = { + let mut w = MemWriter::new(); + try!(write!(&mut w, "searchIndex['{}'] = [", krate.name)); for (i, item) in cache.search_index.iter().enumerate() { if i > 0 { - try!(write!(w, ",")); + try!(write!(&mut w, ",")); } - try!(write!(w, "\\{ty:\"{}\",name:\"{}\",path:\"{}\",desc:{}", - item.ty, item.name, item.path, - item.desc.to_json().to_str())); + try!(write!(&mut w, "\\{ty:\"{}\",name:\"{}\",path:\"{}\",desc:{}", + item.ty, item.name, item.path, + item.desc.to_json().to_str())); match item.parent { Some(id) => { - try!(write!(w, ",parent:'{}'", id)); + try!(write!(&mut w, ",parent:'{}'", id)); } None => {} } - try!(write!(w, "\\}")); + try!(write!(&mut w, "\\}")); } - try!(write!(w, "];")); - try!(write!(w, "var allPaths = \\{")); + try!(write!(&mut w, "];")); + try!(write!(&mut w, "allPaths['{}'] = \\{", krate.name)); for (i, (&id, &(ref fqp, short))) in cache.paths.iter().enumerate() { if i > 0 { - try!(write!(w, ",")); + try!(write!(&mut w, ",")); } - try!(write!(w, "'{}':\\{type:'{}',name:'{}'\\}", - id, short, *fqp.last().unwrap())); + try!(write!(&mut w, "'{}':\\{type:'{}',name:'{}'\\}", + id, short, *fqp.last().unwrap())); } - try!(write!(w, "\\};")); - try!(w.flush()); + try!(write!(&mut w, "\\};")); + + str::from_utf8_owned(w.unwrap()).unwrap() + }; + + // Write out the shared files. Note that these are shared among all rustdoc + // docs placed in the output directory, so this needs to be a synchronized + // operation with respect to all other rustdocs running around. + { + try!(mkdir(&cx.dst)); + let _lock = ::flock::Lock::new(&cx.dst.join(".lock")); + + // Add all the static files. These may already exist, but we just + // overwrite them anyway to make sure that they're fresh and up-to-date. + try!(write(cx.dst.join("jquery.js"), + include_str!("static/jquery-2.1.0.min.js"))); + try!(write(cx.dst.join("main.js"), include_str!("static/main.js"))); + try!(write(cx.dst.join("main.css"), include_str!("static/main.css"))); + try!(write(cx.dst.join("normalize.css"), + include_str!("static/normalize.css"))); + + // Update the search index + let dst = cx.dst.join("search-index.js"); + let mut all_indexes = Vec::new(); + all_indexes.push(index); + if dst.exists() { + for line in BufferedReader::new(File::open(&dst)).lines() { + let line = try!(line); + if !line.starts_with("searchIndex") { continue } + if line.starts_with(format!("searchIndex['{}']", krate.name)) { + continue + } + all_indexes.push(line); + } + } + let mut w = try!(File::create(&dst)); + try!(writeln!(&mut w, r"var searchIndex = \{\}; var allPaths = \{\};")); + for index in all_indexes.iter() { + try!(writeln!(&mut w, "{}", *index)); + } + try!(writeln!(&mut w, "initSearch(searchIndex);")); } // Render all source files (this may turn into a giant no-op) diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 3056bca68d784..ffdf67e56cf7f 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -9,7 +9,7 @@ // except according to those terms. /*jslint browser: true, es5: true */ -/*globals $: true, searchIndex: true, rootPath: true, allPaths: true */ +/*globals $: true, rootPath: true, allPaths: true */ (function() { "use strict"; @@ -23,7 +23,8 @@ map(function(s) { var pair = s.split("="); params[decodeURIComponent(pair[0])] = - typeof pair[1] === "undefined" ? null : decodeURIComponent(pair[1]); + typeof pair[1] === "undefined" ? + null : decodeURIComponent(pair[1]); }); return params; } @@ -111,8 +112,9 @@ document.location.href = url; }); - function initSearch(searchIndex) { - var currentResults, index, params = getQueryStringParams(); + function initSearch(rawSearchIndex) { + var currentResults, index, searchIndex; + var params = getQueryStringParams(); // Populate search bar with query string search term when provided, // but only if the input bar is empty. This avoid the obnoxious issue @@ -126,7 +128,8 @@ * Executes the query and builds an index of results * @param {[Object]} query [The user query] * @param {[type]} max [The maximum results returned] - * @param {[type]} searchWords [The list of search words to query against] + * @param {[type]} searchWords [The list of search words to query + * against] * @return {[type]} [A search index of results] */ function execQuery(query, max, searchWords) { @@ -148,7 +151,9 @@ // quoted values mean literal search bb = searchWords.length; - if ((val.charAt(0) === "\"" || val.charAt(0) === "'") && val.charAt(val.length - 1) === val.charAt(0)) { + if ((val.charAt(0) === "\"" || val.charAt(0) === "'") && + val.charAt(val.length - 1) === val.charAt(0)) + { val = val.substr(1, val.length - 2); for (aa = 0; aa < bb; aa += 1) { if (searchWords[aa] === val) { @@ -166,7 +171,10 @@ val = val.replace(/\_/g, ""); for (var i = 0; i < split.length; i++) { for (aa = 0; aa < bb; aa += 1) { - if (searchWords[aa].indexOf(split[i]) > -1 || searchWords[aa].indexOf(val) > -1 || searchWords[aa].replace(/_/g, "").indexOf(val) > -1) { + if (searchWords[aa].indexOf(split[i]) > -1 || + searchWords[aa].indexOf(val) > -1 || + searchWords[aa].replace(/_/g, "").indexOf(val) > -1) + { // filter type: ... queries if (!typeFilter || typeFilter === searchIndex[aa].ty) { results.push([aa, searchWords[aa].replace(/_/g, "").indexOf(val)]); @@ -185,6 +193,7 @@ results[aa].push(searchIndex[results[aa][0]].path); results[aa].push(searchIndex[results[aa][0]].name); results[aa].push(searchIndex[results[aa][0]].parent); + results[aa].push(searchIndex[results[aa][0]].crate); } // if there are no results then return to default and fail if (results.length === 0) { @@ -193,7 +202,8 @@ // sort by exact match results.sort(function search_complete_sort0(aaa, bbb) { - if (searchWords[aaa[0]] === valLower && searchWords[bbb[0]] !== valLower) { + if (searchWords[aaa[0]] === valLower && + searchWords[bbb[0]] !== valLower) { return 1; } }); @@ -207,7 +217,8 @@ // second sorting attempt // sort by item name results.sort(function search_complete_sort1(aaa, bbb) { - if (searchWords[aaa[0]].length === searchWords[bbb[0]].length && searchWords[aaa[0]] > searchWords[bbb[0]]) { + if (searchWords[aaa[0]].length === searchWords[bbb[0]].length && + searchWords[aaa[0]] > searchWords[bbb[0]]) { return 1; } }); @@ -223,21 +234,26 @@ // fourth sorting attempt // sort by type results.sort(function search_complete_sort3(aaa, bbb) { - if (searchWords[aaa[0]] === searchWords[bbb[0]] && aaa[2] > bbb[2]) { + if (searchWords[aaa[0]] === searchWords[bbb[0]] && + aaa[2] > bbb[2]) { return 1; } }); // fifth sorting attempt // sort by path results.sort(function search_complete_sort4(aaa, bbb) { - if (searchWords[aaa[0]] === searchWords[bbb[0]] && aaa[2] === bbb[2] && aaa[3] > bbb[3]) { + if (searchWords[aaa[0]] === searchWords[bbb[0]] && + aaa[2] === bbb[2] && aaa[3] > bbb[3]) { return 1; } }); // sixth sorting attempt // remove duplicates, according to the data provided for (aa = results.length - 1; aa > 0; aa -= 1) { - if (searchWords[results[aa][0]] === searchWords[results[aa - 1][0]] && results[aa][2] === results[aa - 1][2] && results[aa][3] === results[aa - 1][3]) { + if (searchWords[results[aa][0]] === searchWords[results[aa - 1][0]] && + results[aa][2] === results[aa - 1][2] && + results[aa][3] === results[aa - 1][3]) + { results[aa][0] = -1; } } @@ -245,7 +261,7 @@ var result = results[i], name = result[4].toLowerCase(), path = result[3].toLowerCase(), - parent = allPaths[result[5]]; + parent = allPaths[result[6]][result[5]]; var valid = validateResult(name, path, split, parent); if (!valid) { @@ -256,11 +272,14 @@ } /** - * Validate performs the following boolean logic. For example: "File::open" will give - * IF A PARENT EXISTS => ("file" && "open") exists in (name || path || parent) - * OR => ("file" && "open") exists in (name || path ) + * Validate performs the following boolean logic. For example: + * "File::open" will give IF A PARENT EXISTS => ("file" && "open") + * exists in (name || path || parent) OR => ("file" && "open") exists in + * (name || path ) + * + * This could be written functionally, but I wanted to minimise + * functions on stack. * - * This could be written functionally, but I wanted to minimise functions on stack. * @param {[string]} name [The name of the result] * @param {[string]} path [The path of the result] * @param {[string]} keys [The keys to be used (["file", "open"])] @@ -273,8 +292,13 @@ //if there is a parent, then validate against parent if (parent !== undefined) { for (var i = 0; i < keys.length; i++) { - // if previous keys are valid and current key is in the path, name or parent - if ((validate) && (name.toLowerCase().indexOf(keys[i]) > -1 || path.toLowerCase().indexOf(keys[i]) > -1 || parent.name.toLowerCase().indexOf(keys[i]) > -1)) { + // if previous keys are valid and current key is in the + // path, name or parent + if ((validate) && + (name.toLowerCase().indexOf(keys[i]) > -1 || + path.toLowerCase().indexOf(keys[i]) > -1 || + parent.name.toLowerCase().indexOf(keys[i]) > -1)) + { validate = true; } else { validate = false; @@ -282,8 +306,12 @@ } } else { for (var i = 0; i < keys.length; i++) { - // if previous keys are valid and current key is in the path, name - if ((validate) && (name.toLowerCase().indexOf(keys[i]) > -1 || path.toLowerCase().indexOf(keys[i]) > -1)) { + // if previous keys are valid and current key is in the + // path, name + if ((validate) && + (name.toLowerCase().indexOf(keys[i]) > -1 || + path.toLowerCase().indexOf(keys[i]) > -1)) + { validate = true; } else { validate = false; @@ -298,7 +326,10 @@ matches = query.match(/^(fn|mod|str(uct)?|enum|trait|t(ype)?d(ef)?)\s*:\s*/i); if (matches) { - type = matches[1].replace(/^td$/, 'typedef').replace(/^str$/, 'struct').replace(/^tdef$/, 'typedef').replace(/^typed$/, 'typedef'); + type = matches[1].replace(/^td$/, 'typedef') + .replace(/^str$/, 'struct') + .replace(/^tdef$/, 'typedef') + .replace(/^typed$/, 'typedef'); query = query.substring(matches[0].length); } @@ -314,7 +345,6 @@ $results.on('click', function() { var dst = $(this).find('a')[0]; - console.log(window.location.pathname, dst.pathname); if (window.location.pathname == dst.pathname) { $('#search').addClass('hidden'); $('#main').removeClass('hidden'); @@ -362,7 +392,8 @@ var output, shown, query = getQuery(); currentResults = query.id; - output = '

Results for ' + query.query + (query.type ? ' (type: ' + query.type + ')' : '') + '

'; + output = '

Results for ' + query.query + + (query.type ? ' (type: ' + query.type + ')' : '') + '

'; output += ''; if (results.length > 0) { @@ -394,7 +425,7 @@ '/index.html" class="' + type + '">' + name + ''; } else if (item.parent !== undefined) { - var myparent = allPaths[item.parent]; + var myparent = allPaths[item.crate][item.parent]; var anchor = '#' + type + '.' + name; output += item.path + '::' + myparent.name + ':: yy[op].toLowerCase())) { - // return 1; - // } - // }); - // }; - showResults(results); } - function buildIndex(searchIndex) { - var len = searchIndex.length, - i = 0, - searchWords = []; - - // before any analysis is performed lets gather the search terms to - // search against apart from the rest of the data. This is a quick - // operation that is cached for the life of the page state so that - // all other search operations have access to this cached data for - // faster analysis operations - for (i = 0; i < len; i += 1) { - if (typeof searchIndex[i].name === "string") { - searchWords.push(searchIndex[i].name.toLowerCase()); - } else { - searchWords.push(""); + function buildIndex(rawSearchIndex) { + searchIndex = []; + var searchWords = []; + for (var crate in rawSearchIndex) { + if (!rawSearchIndex.hasOwnProperty(crate)) { continue } + var len = rawSearchIndex[crate].length; + var i = 0; + + // before any analysis is performed lets gather the search terms to + // search against apart from the rest of the data. This is a quick + // operation that is cached for the life of the page state so that + // all other search operations have access to this cached data for + // faster analysis operations + for (i = 0; i < len; i += 1) { + rawSearchIndex[crate][i].crate = crate; + searchIndex.push(rawSearchIndex[crate][i]); + if (typeof rawSearchIndex[crate][i].name === "string") { + var word = rawSearchIndex[crate][i].name.toLowerCase(); + searchWords.push(word); + } else { + searchWords.push(""); + } } } - return searchWords; } @@ -567,17 +542,21 @@ clearTimeout(keyUpTimeout); keyUpTimeout = setTimeout(search, 100); }); - // Push and pop states are used to add search results to the browser history. + + // Push and pop states are used to add search results to the browser + // history. if (browserSupportsHistoryApi()) { $(window).on('popstate', function(e) { var params = getQueryStringParams(); - // When browsing back from search results the main page visibility must be reset. + // When browsing back from search results the main page + // visibility must be reset. if (!params.search) { $('#main.content').removeClass('hidden'); $('#search.content').addClass('hidden'); } - // When browsing forward to search results the previous search will be repeated, - // so the currentResults are cleared to ensure the search is successful. + // When browsing forward to search results the previous + // search will be repeated, so the currentResults are + // cleared to ensure the search is successful. currentResults = null; // Synchronize search bar with query string state and // perform the search, but don't empty the bar if there's @@ -585,19 +564,46 @@ if (params.search !== undefined) { $('.search-input').val(params.search); } - // Some browsers fire 'onpopstate' for every page load (Chrome), while others fire the - // event only when actually popping a state (Firefox), which is why search() is called - // both here and at the end of the startSearch() function. + // Some browsers fire 'onpopstate' for every page load + // (Chrome), while others fire the event only when actually + // popping a state (Firefox), which is why search() is + // called both here and at the end of the startSearch() + // function. search(); }); } search(); } - index = buildIndex(searchIndex); + index = buildIndex(rawSearchIndex); startSearch(); - } - initSearch(searchIndex); + // Draw a convenient sidebar of known crates if we have a listing + if (rootPath == '../') { + console.log('here'); + var sidebar = $('.sidebar'); + var div = $('
').attr('class', 'block crate'); + div.append($('

').text('Crates')); + + var crates = []; + for (var crate in rawSearchIndex) { + if (!rawSearchIndex.hasOwnProperty(crate)) { continue } + crates.push(crate); + } + crates.sort(); + for (var i = 0; i < crates.length; i++) { + var klass = 'crate'; + if (crates[i] == window.currentCrate) { + klass += ' current'; + } + div.append($('', {'href': '../' + crates[i] + '/index.html', + 'class': klass}).text(crates[i])); + div.append($('
')); + } + sidebar.append(div); + } + } + window.initSearch = initSearch; }()); + diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index e64292285d00d..6dc3c2073f176 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -52,6 +52,7 @@ pub mod passes; pub mod plugins; pub mod visit_ast; pub mod test; +mod flock; pub static SCHEMA_VERSION: &'static str = "0.8.1"; diff --git a/src/libstd/libc.rs b/src/libstd/libc.rs index 0fb7a5f85032c..42221f074491d 100644 --- a/src/libstd/libc.rs +++ b/src/libstd/libc.rs @@ -3643,7 +3643,7 @@ pub mod funcs { pub fn open(path: *c_char, oflag: c_int, mode: c_int) -> c_int; pub fn creat(path: *c_char, mode: mode_t) -> c_int; - pub fn fcntl(fd: c_int, cmd: c_int) -> c_int; + pub fn fcntl(fd: c_int, cmd: c_int, ...) -> c_int; } } From 113596655aede43576c3107b62ba98ecaac5ebae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marvin=20L=C3=B6bel?= Date: Tue, 18 Mar 2014 23:16:21 +0100 Subject: [PATCH 21/22] Made the `clone_from` implementation for `~T` reuse the `T` itself if possible by also calling `clone_from` on it. In general, `Clone` implementors that overwrite `clone_from` should try to to use it recursivly for substructures. --- src/libstd/clone.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libstd/clone.rs b/src/libstd/clone.rs index ce5f056622f36..cf5a9c6711c62 100644 --- a/src/libstd/clone.rs +++ b/src/libstd/clone.rs @@ -45,8 +45,9 @@ impl Clone for ~T { fn clone(&self) -> ~T { ~(**self).clone() } /// Perform copy-assignment from `source` by reusing the existing allocation. + #[inline] fn clone_from(&mut self, source: &~T) { - **self = (**source).clone() + (**self).clone_from(&(**source)); } } From 2a5e04c2a427b00051424b916d9e306f0de470cd Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 18 Mar 2014 14:03:45 -0700 Subject: [PATCH 22/22] Test fixes from the rollup --- src/libstd/ops.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/libstd/ops.rs b/src/libstd/ops.rs index 49bd95f621def..849e2a79e08b9 100644 --- a/src/libstd/ops.rs +++ b/src/libstd/ops.rs @@ -475,8 +475,10 @@ pub trait Index { fn index(&self, index: &Index) -> Result; } +/// Dummy dox #[cfg(stage0)] pub trait Deref { + /// dummy dox fn deref<'a>(&'a self) -> &'a Result; } @@ -514,8 +516,10 @@ pub trait Deref { fn deref<'a>(&'a self) -> &'a Result; } +/// dummy dox #[cfg(stage0)] pub trait DerefMut: Deref { + /// dummy dox fn deref_mut<'a>(&'a mut self) -> &'a mut Result; }