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. 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 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)]; diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs index e7c1e214d070a..94965e7e0dc3f 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); } @@ -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/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/librustc/lib/llvm.rs b/src/librustc/lib/llvm.rs index 448b9e30dcd3d..b98f3f6fd5d48 100644 --- a/src/librustc/lib/llvm.rs +++ b/src/librustc/lib/llvm.rs @@ -43,24 +43,22 @@ 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, - LinkerPrivateLinkage = 15, - LinkerPrivateWeakLinkage = 16, } #[deriving(Clone)] 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/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), 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/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 1ebb51cb65e9f..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) @@ -463,6 +490,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 +516,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/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/libserialize/json.rs b/src/libserialize/json.rs index 6ce555ba9f74a..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,13 +1330,19 @@ 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) } } - 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 { @@ -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); + } } 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] 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)); } } 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; } } diff --git a/src/libstd/ops.rs b/src/libstd/ops.rs index 2d5d37e1abc51..849e2a79e08b9 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,28 +471,96 @@ pub trait Shr { */ #[lang="index"] pub trait Index { + /// The method for the indexing (`Foo[Bar]`) operation fn index(&self, index: &Index) -> Result; } +/// Dummy dox #[cfg(stage0)] pub trait Deref { + /// dummy dox 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; } +/// dummy dox #[cfg(stage0)] pub trait DerefMut: Deref { + /// dummy dox 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; } 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 } } 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; 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); } } 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 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/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(); 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/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) { } 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()); +} 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 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()); 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() {}