New upstream version 1.14.0+dfsg1

This commit is contained in:
Sylvestre Ledru 2016-12-23 16:36:51 +01:00
parent 9e0c209edc
commit c30ab7b35a
1523 changed files with 37451 additions and 22628 deletions

View File

@ -89,6 +89,7 @@ build.
$ pacman -S git \
make \
diffutils \
tar \
mingw-w64-x86_64-python2 \
mingw-w64-x86_64-cmake \
mingw-w64-x86_64-gcc
@ -126,7 +127,7 @@ ones from MSYS if you have it installed). You'll also need Visual Studio 2013 or
newer with the C++ tools. Then all you need to do is to kick off rustbuild.
```
python .\src\bootstrap\bootstrap.py
python x.py build
```
Currently rustbuild only works with some known versions of Visual Studio. If you
@ -136,7 +137,7 @@ by manually calling the appropriate vcvars file before running the bootstrap.
```
CALL "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin\amd64\vcvars64.bat"
python .\src\bootstrap\bootstrap.py
python x.py build
```
## Building Documentation

View File

@ -1,260 +1,3 @@
Version 1.13.0 (2016-11-10)
===========================
Language
--------
* [Stabilize the `?` operator][36995]. `?` is a simple way to propagate
errors, like the `try!` macro, described in [RFC 0243].
* [Stabilize macros in type position][36014]. Described in [RFC 873].
* [Stabilize attributes on statements][36995]. Described in [RFC 0016].
* [Fix `#[derive]` for empty tuple structs/variants][35728]
* [Fix lifetime rules for 'if' conditions][36029]
* [Avoid loading and parsing unconfigured non-inline modules][36482]
Compiler
--------
* [Add the `-C link-arg` argument][36574]
* [Remove the old AST-based backend from rustc_trans][35764]
* [Don't enable NEON by default on armv7 Linux][35814]
* [Fix debug line number info for macro expansions][35238]
* [Do not emit "class method" debuginfo for types that are not
DICompositeType][36008]
* [Warn about multiple conflicting #[repr] hints][34623]
* [When sizing DST, don't double-count nested struct prefixes][36351]
* [Default RUST_MIN_STACK to 16MiB for now][36505]
* [Improve rlib metadata format][36551]. Reduces rlib size significantly.
* [Reject macros with empty repetitions to avoid infinite loop][36721]
* [Expand macros without recursing to avoid stack overflows][36214]
Diagnostics
-----------
* [Replace macro backtraces with labeled local uses][35702]
* [Improve error message for missplaced doc comments][33922]
* [Buffer unix and lock windows to prevent message interleaving][35975]
* [Update lifetime errors to specifically note temporaries][36171]
* [Special case a few colors for Windows][36178]
* [Suggest `use self` when such an import resolves][36289]
* [Be more specific when type parameter shadows primitive type][36338]
* Many minor improvements
Compile-time Optimizations
--------------------------
* [Compute and cache HIR hashes at beginning][35854]
* [Don't hash types in loan paths][36004]
* [Cache projections in trans][35761]
* [Optimize the parser's last token handling][36527]
* [Only instantiate #[inline] functions in codegen units referencing
them][36524]. This leads to big improvements in cases where crates export
define many inline functions without using them directly.
* [Lazily allocate TypedArena's first chunk][36592]
* [Don't allocate during default HashSet creation][36734]
Stabilized APIs
---------------
* [`checked_abs`]
* [`wrapping_abs`]
* [`overflowing_abs`]
* [`RefCell::try_borrow`]
* [`RefCell::try_borrow_mut`]
Libraries
---------
* [Add `assert_ne!` and `debug_assert_ne!`][35074]
* [Make `vec_deque::Drain`, `hash_map::Drain`, and `hash_set::Drain`
covariant][35354]
* [Implement `AsRef<[T]>` for `std::slice::Iter`][35559]
* [Implement `Debug` for `std::vec::IntoIter`][35707]
* [`CString`: avoid excessive growth just to 0-terminate][35871]
* [Implement `CoerceUnsized` for `{Cell, RefCell, UnsafeCell}`][35627]
* [Use arc4rand on FreeBSD][35884]
* [memrchr: Correct aligned offset computation][35969]
* [Improve Demangling of Rust Symbols][36059]
* [Use monotonic time in condition variables][35048]
* [Implement `Debug` for `std::path::{Components,Iter}`][36101]
* [Implement conversion traits for `char`][35755]
* [Fix illegal instruction caused by overflow in channel cloning][36104]
* [Zero first byte of CString on drop][36264]
* [Inherit overflow checks for sum and product][36372]
* [Add missing Eq implementations][36423]
* [Implement `Debug` for `DirEntry`][36631]
* [When `getaddrinfo` returns `EAI_SYSTEM` retrieve actual error from
`errno`][36754]
* [`SipHasher`] is deprecated. Use [`DefaultHasher`].
* [Implement more traits for `std::io::ErrorKind`][35911]
* [Optimize BinaryHeap bounds checking][36072]
* [Work around pointer aliasing issue in `Vec::extend_from_slice`,
`extend_with_element`][36355]
* [Fix overflow checking in unsigned pow()][34942]
Cargo
-----
* This release includes security fixes to both curl and OpenSSL.
* [Fix transitive doctests when panic=abort][cargo/3021]
* [Add --all-features flag to cargo][cargo/3038]
* [Reject path-based dependencies in `cargo package`][cargo/3060]
* [Don't parse the home directory more than once][cargo/3078]
* [Don't try to generate Cargo.lock on empty workspaces][cargo/3092]
* [Update OpenSSL to 1.0.2j][cargo/3121]
* [Add license and license_file to cargo metadata output][cargo/3110]
* [Make crates-io registry URL optional in config; ignore all changes to
source.crates-io][cargo/3089]
* [Don't download dependencies from other platforms][cargo/3123]
* [Build transitive dev-dependencies when needed][cargo/3125]
* [Add support for per-target rustflags in .cargo/config][cargo/3157]
* [Avoid updating registry when adding existing deps][cargo/3144]
* [Warn about path overrides that won't work][cargo/3136]
* [Use workspaces during `cargo install`][cargo/3146]
* [Leak mspdbsrv.exe processes on Windows][cargo/3162]
* [Add --message-format flag][cargo/3000]
* [Pass target environment for rustdoc][cargo/3205]
* [Use `CommandExt::exec` for `cargo run` on Unix][cargo/2818]
* [Update curl and curl-sys][cargo/3241]
* [Call rustdoc test with the correct cfg flags of a package][cargo/3242]
Tooling
-------
* [rustdoc: Add the `--sysroot` argument][36586]
* [rustdoc: Fix a couple of issues with the search results][35655]
* [rustdoc: remove the `!` from macro URLs and titles][35234]
* [gdb: Fix pretty-printing special-cased Rust types][35585]
* [rustdoc: Filter more incorrect methods inherited through Deref][36266]
Misc
----
* [Remove unmaintained style guide][35124]
* [Add s390x support][36369]
* [Initial work at Haiku OS support][36727]
* [Add mips-uclibc targets][35734]
* [Crate-ify compiler-rt into compiler-builtins][35021]
* [Add rustc version info (git hash + date) to dist tarball][36213]
* Many documentation improvements
Compatibility Notes
-------------------
* [`SipHasher`] is deprecated. Use [`DefaultHasher`].
* [Deny (by default) transmuting from fn item types to pointer-sized
types][34923]. Continuing the long transition to zero-sized fn items,
per [RFC 401].
* [Fix `#[derive]` for empty tuple structs/variants][35728].
Part of [RFC 1506].
* [Issue deprecation warnings for safe accesses to extern statics][36173]
* [Fix lifetime rules for 'if' conditions][36029].
* [Inherit overflow checks for sum and product][36372].
* [Forbid user-defined macros named "macro_rules"][36730].
[33922]: https://github.com/rust-lang/rust/pull/33922
[34623]: https://github.com/rust-lang/rust/pull/34623
[34923]: https://github.com/rust-lang/rust/pull/34923
[34942]: https://github.com/rust-lang/rust/pull/34942
[34982]: https://github.com/rust-lang/rust/pull/34982
[35021]: https://github.com/rust-lang/rust/pull/35021
[35048]: https://github.com/rust-lang/rust/pull/35048
[35074]: https://github.com/rust-lang/rust/pull/35074
[35124]: https://github.com/rust-lang/rust/pull/35124
[35234]: https://github.com/rust-lang/rust/pull/35234
[35238]: https://github.com/rust-lang/rust/pull/35238
[35354]: https://github.com/rust-lang/rust/pull/35354
[35559]: https://github.com/rust-lang/rust/pull/35559
[35585]: https://github.com/rust-lang/rust/pull/35585
[35627]: https://github.com/rust-lang/rust/pull/35627
[35655]: https://github.com/rust-lang/rust/pull/35655
[35702]: https://github.com/rust-lang/rust/pull/35702
[35707]: https://github.com/rust-lang/rust/pull/35707
[35728]: https://github.com/rust-lang/rust/pull/35728
[35734]: https://github.com/rust-lang/rust/pull/35734
[35755]: https://github.com/rust-lang/rust/pull/35755
[35761]: https://github.com/rust-lang/rust/pull/35761
[35764]: https://github.com/rust-lang/rust/pull/35764
[35814]: https://github.com/rust-lang/rust/pull/35814
[35854]: https://github.com/rust-lang/rust/pull/35854
[35871]: https://github.com/rust-lang/rust/pull/35871
[35884]: https://github.com/rust-lang/rust/pull/35884
[35911]: https://github.com/rust-lang/rust/pull/35911
[35969]: https://github.com/rust-lang/rust/pull/35969
[35975]: https://github.com/rust-lang/rust/pull/35975
[36004]: https://github.com/rust-lang/rust/pull/36004
[36008]: https://github.com/rust-lang/rust/pull/36008
[36014]: https://github.com/rust-lang/rust/pull/36014
[36029]: https://github.com/rust-lang/rust/pull/36029
[36059]: https://github.com/rust-lang/rust/pull/36059
[36072]: https://github.com/rust-lang/rust/pull/36072
[36101]: https://github.com/rust-lang/rust/pull/36101
[36104]: https://github.com/rust-lang/rust/pull/36104
[36171]: https://github.com/rust-lang/rust/pull/36171
[36173]: https://github.com/rust-lang/rust/pull/36173
[36178]: https://github.com/rust-lang/rust/pull/36178
[36213]: https://github.com/rust-lang/rust/pull/36213
[36214]: https://github.com/rust-lang/rust/pull/36214
[36264]: https://github.com/rust-lang/rust/pull/36264
[36266]: https://github.com/rust-lang/rust/pull/36266
[36289]: https://github.com/rust-lang/rust/pull/36289
[36338]: https://github.com/rust-lang/rust/pull/36338
[36351]: https://github.com/rust-lang/rust/pull/36351
[36355]: https://github.com/rust-lang/rust/pull/36355
[36369]: https://github.com/rust-lang/rust/pull/36369
[36372]: https://github.com/rust-lang/rust/pull/36372
[36423]: https://github.com/rust-lang/rust/pull/36423
[36482]: https://github.com/rust-lang/rust/pull/36482
[36505]: https://github.com/rust-lang/rust/pull/36505
[36524]: https://github.com/rust-lang/rust/pull/36524
[36527]: https://github.com/rust-lang/rust/pull/36527
[36551]: https://github.com/rust-lang/rust/pull/36551
[36574]: https://github.com/rust-lang/rust/pull/36574
[36586]: https://github.com/rust-lang/rust/pull/36586
[36592]: https://github.com/rust-lang/rust/pull/36592
[36631]: https://github.com/rust-lang/rust/pull/36631
[36639]: https://github.com/rust-lang/rust/pull/36639
[36721]: https://github.com/rust-lang/rust/pull/36721
[36727]: https://github.com/rust-lang/rust/pull/36727
[36730]: https://github.com/rust-lang/rust/pull/36730
[36734]: https://github.com/rust-lang/rust/pull/36734
[36754]: https://github.com/rust-lang/rust/pull/36754
[36995]: https://github.com/rust-lang/rust/pull/36995
[RFC 0016]: https://github.com/rust-lang/rfcs/blob/master/text/0016-more-attributes.md
[RFC 0243]: https://github.com/rust-lang/rfcs/blob/master/text/0243-trait-based-exception-handling.md
[RFC 1506]: https://github.com/rust-lang/rfcs/blob/master/text/1506-adt-kinds.md
[RFC 401]: https://github.com/rust-lang/rfcs/blob/master/text/0401-coercions.md
[RFC 873]: https://github.com/rust-lang/rfcs/blob/master/text/0873-type-macros.md
[cargo/2818]: https://github.com/rust-lang/cargo/pull/2818
[cargo/3000]: https://github.com/rust-lang/cargo/pull/3000
[cargo/3021]: https://github.com/rust-lang/cargo/pull/3021
[cargo/3038]: https://github.com/rust-lang/cargo/pull/3038
[cargo/3060]: https://github.com/rust-lang/cargo/pull/3060
[cargo/3078]: https://github.com/rust-lang/cargo/pull/3078
[cargo/3089]: https://github.com/rust-lang/cargo/pull/3089
[cargo/3092]: https://github.com/rust-lang/cargo/pull/3092
[cargo/3110]: https://github.com/rust-lang/cargo/pull/3110
[cargo/3121]: https://github.com/rust-lang/cargo/pull/3121
[cargo/3123]: https://github.com/rust-lang/cargo/pull/3123
[cargo/3125]: https://github.com/rust-lang/cargo/pull/3125
[cargo/3136]: https://github.com/rust-lang/cargo/pull/3136
[cargo/3144]: https://github.com/rust-lang/cargo/pull/3144
[cargo/3146]: https://github.com/rust-lang/cargo/pull/3146
[cargo/3157]: https://github.com/rust-lang/cargo/pull/3157
[cargo/3162]: https://github.com/rust-lang/cargo/pull/3162
[cargo/3205]: https://github.com/rust-lang/cargo/pull/3205
[cargo/3241]: https://github.com/rust-lang/cargo/pull/3241
[cargo/3242]: https://github.com/rust-lang/cargo/pull/3242
[rustup]: https://www.rustup.rs
[`checked_abs`]: https://doc.rust-lang.org/std/primitive.i32.html#method.checked_abs
[`wrapping_abs`]: https://doc.rust-lang.org/std/primitive.i32.html#method.wrapping_abs
[`overflowing_abs`]: https://doc.rust-lang.org/std/primitive.i32.html#method.overflowing_abs
[`RefCell::try_borrow`]: https://doc.rust-lang.org/std/cell/struct.RefCell.html#method.try_borrow
[`RefCell::try_borrow_mut`]: https://doc.rust-lang.org/std/cell/struct.RefCell.html#method.try_borrow_mut
[`SipHasher`]: https://doc.rust-lang.org/std/hash/struct.SipHasher.html
[`DefaultHasher`]: https://doc.rust-lang.org/std/collections/hash_map/struct.DefaultHasher.html
Version 1.12.1 (2016-10-20)
===========================
@ -338,7 +81,7 @@ Diagnostics
Most common editors supporting Rust have been updated to work with it. It was
previously described [on the Rust blog]
(https://blog.rust-lang.org/2016/08/10/Shape-of-errors-to-come.html).
* [In error descriptions, references are now described in plain english,
* [In error descriptions, references are now described in plain English,
instead of as "&-ptr"]
(https://github.com/rust-lang/rust/pull/35611)
* [In error type descriptions, unknown numeric types are named `{integer}` or
@ -432,7 +175,7 @@ Libraries
(https://github.com/rust-lang/rust/pull/34946)
* [`hash_map::Entry`, `hash_map::VacantEntry` and `hash_map::OccupiedEntry`
implement `Debug`]
(https://github.com/rust-lang/rust/pull/34946)
(https://github.com/rust-lang/rust/pull/34937)
* [`btree_map::Entry`, `btree_map::VacantEntry` and `btree_map::OccupiedEntry`
implement `Debug`]
(https://github.com/rust-lang/rust/pull/34885)
@ -1169,7 +912,7 @@ Cargo
Performance
-----------
* [The time complexity of comparing variables for equivalence during type
* [The time complexity of comparing variables for equivalence during type
unification is reduced from _O_(_n_!) to _O_(_n_)][1.9tu]. This leads
to major compilation time improvement in some scenarios.
* [`ToString` is specialized for `str`, giving it the same performance

63
configure vendored
View File

@ -507,11 +507,16 @@ case $CFG_CPUTYPE in
CFG_CPUTYPE=arm
;;
armv7l)
armv6l)
CFG_CPUTYPE=arm
CFG_OSTYPE="${CFG_OSTYPE}eabihf"
;;
armv7l)
CFG_CPUTYPE=armv7
CFG_OSTYPE="${CFG_OSTYPE}eabihf"
;;
aarch64)
CFG_CPUTYPE=aarch64
;;
@ -610,6 +615,7 @@ opt docs 1 "build standard library documentation"
opt compiler-docs 0 "build compiler documentation"
opt optimize-tests 1 "build tests with optimizations"
opt debuginfo-tests 0 "build tests with debugger metadata"
opt quiet-tests 0 "enable quieter output when running tests"
opt libcpp 1 "build llvm with libc++ instead of libstdc++ when using clang"
opt llvm-assertions 0 "build LLVM with assertions"
opt debug-assertions 0 "build with debugging assertions"
@ -636,6 +642,7 @@ opt_nosave optimize-llvm 1 "build optimized LLVM"
opt_nosave llvm-assertions 0 "build LLVM with assertions"
opt_nosave debug-assertions 0 "build with debugging assertions"
opt_nosave debuginfo 0 "build with debugger metadata"
opt_nosave debuginfo-lines 0 "build with line number debugger metadata"
opt_nosave debug-jemalloc 0 "build jemalloc with --enable-debug --enable-fill"
valopt localstatedir "/var/lib" "local state directory"
@ -645,7 +652,6 @@ valopt datadir "${CFG_PREFIX}/share" "install data"
valopt infodir "${CFG_PREFIX}/share/info" "install additional info"
valopt llvm-root "" "set LLVM root"
valopt python "" "set path to python"
valopt nodejs "" "set path to nodejs"
valopt jemalloc-root "" "set directory where libjemalloc_pic.a is located"
valopt build "${DEFAULT_BUILD}" "GNUs ./configure syntax LLVM build triple"
valopt android-cross-path "" "Android NDK standalone path (deprecated)"
@ -654,7 +660,12 @@ valopt arm-linux-androideabi-ndk "" "arm-linux-androideabi NDK standalone path"
valopt armv7-linux-androideabi-ndk "" "armv7-linux-androideabi NDK standalone path"
valopt aarch64-linux-android-ndk "" "aarch64-linux-android NDK standalone path"
valopt nacl-cross-path "" "NaCl SDK path (Pepper Canary is recommended). Must be absolute!"
valopt musl-root "/usr/local" "MUSL root installation directory"
valopt musl-root "/usr/local" "MUSL root installation directory (deprecated)"
valopt musl-root-x86_64 "/usr/local" "x86_64-unknown-linux-musl install directory"
valopt musl-root-i686 "/usr/local" "i686-unknown-linux-musl install directory"
valopt musl-root-arm "/usr/local" "arm-unknown-linux-musleabi install directory"
valopt musl-root-armhf "/usr/local" "arm-unknown-linux-musleabihf install directory"
valopt musl-root-armv7 "/usr/local" "armv7-unknown-linux-musleabihf install directory"
valopt extra-filename "" "Additional data that is hashed and passed to the -C extra-filename flag"
if [ -e ${CFG_SRC_DIR}.git ]
@ -717,8 +728,27 @@ case "$CFG_RELEASE_CHANNEL" in
nightly )
msg "overriding settings for $CFG_RELEASE_CHANNEL"
CFG_ENABLE_LLVM_ASSERTIONS=1
# FIXME(#37364) shouldn't have to disable this on windows-gnu
case "$CFG_BUILD" in
*-pc-windows-gnu)
;;
*)
CFG_ENABLE_DEBUGINFO_LINES=1
;;
esac
;;
dev | beta | stable)
beta | stable)
msg "overriding settings for $CFG_RELEASE_CHANNEL"
case "$CFG_BUILD" in
*-pc-windows-gnu)
;;
*)
CFG_ENABLE_DEBUGINFO_LINES=1
;;
esac
;;
dev)
;;
*)
err "release channel must be 'dev', 'nightly', 'beta' or 'stable'"
@ -748,6 +778,7 @@ if [ -n "$CFG_DISABLE_OPTIMIZE_LLVM" ]; then putvar CFG_DISABLE_OPTIMIZE_LLVM; f
if [ -n "$CFG_ENABLE_LLVM_ASSERTIONS" ]; then putvar CFG_ENABLE_LLVM_ASSERTIONS; fi
if [ -n "$CFG_ENABLE_DEBUG_ASSERTIONS" ]; then putvar CFG_ENABLE_DEBUG_ASSERTIONS; fi
if [ -n "$CFG_ENABLE_DEBUGINFO" ]; then putvar CFG_ENABLE_DEBUGINFO; fi
if [ -n "$CFG_ENABLE_DEBUGINFO_LINES" ]; then putvar CFG_ENABLE_DEBUGINFO_LINES; fi
if [ -n "$CFG_ENABLE_DEBUG_JEMALLOC" ]; then putvar CFG_ENABLE_DEBUG_JEMALLOC; fi
step_msg "looking for build programs"
@ -762,9 +793,6 @@ if [ $(echo $python_version | grep -c '^Python 2\.7') -ne 1 ]; then
err "Found $python_version, but Python 2.7 is required"
fi
# Checking for node, but not required
probe CFG_NODEJS nodejs node
# If we have no git directory then we are probably a tarball distribution
# and shouldn't attempt to load submodules
if [ ! -e ${CFG_SRC_DIR}.git ]
@ -840,13 +868,6 @@ then
fi
fi
if [ -n "$CFG_GDB" ]
then
# Store GDB's version
CFG_GDB_VERSION=$($CFG_GDB --version 2>/dev/null | head -1)
putvar CFG_GDB_VERSION
fi
if [ -n "$CFG_LLDB" ]
then
# Store LLDB's version
@ -1216,14 +1237,6 @@ do
fi
;;
x86_64-*-musl | arm-*-musleabi)
if [ ! -f $CFG_MUSL_ROOT/lib/libc.a ]
then
err "musl libc $CFG_MUSL_ROOT/lib/libc.a not found"
fi
;;
*-msvc)
# There are three builds of cmake on windows: MSVC, MinGW and Cygwin
# The Cygwin build does not have generators for Visual Studio, so
@ -1642,8 +1655,8 @@ do
("ccache gcc")
LLVM_CXX_32="ccache"
LLVM_CC_32="ccache"
LLVM_CXX_32_ARG1="clang++"
LLVM_CC_32_ARG1="clang"
LLVM_CXX_32_ARG1="g++"
LLVM_CC_32_ARG1="gcc"
LLVM_CXX_64="ccache"
LLVM_CC_64="ccache"
@ -1768,7 +1781,7 @@ do
CMAKE_ARGS="$CMAKE_ARGS -DLLVM_ENABLE_ASSERTIONS=ON"
fi
CMAKE_ARGS="$CMAKE_ARGS -DLLVM_TARGETS_TO_BUILD='X86;ARM;AArch64;Mips;PowerPC;SystemZ'"
CMAKE_ARGS="$CMAKE_ARGS -DLLVM_TARGETS_TO_BUILD='X86;ARM;AArch64;Mips;PowerPC;SystemZ;JSBackend'"
CMAKE_ARGS="$CMAKE_ARGS -G '$CFG_CMAKE_GENERATOR'"
CMAKE_ARGS="$CMAKE_ARGS $CFG_LLVM_SRC_DIR"

View File

@ -0,0 +1 @@
# rustbuild-only target

View File

@ -0,0 +1,24 @@
# wasm32-unknown-emscripten configuration
CC_wasm32-unknown-emscripten=emcc
CXX_wasm32-unknown-emscripten=em++
CPP_wasm32-unknown-emscripten=$(CPP)
AR_wasm32-unknown-emscripten=emar
CFG_LIB_NAME_wasm32-unknown-emscripten=lib$(1).so
CFG_STATIC_LIB_NAME_wasm32-unknown-emscripten=lib$(1).a
CFG_LIB_GLOB_wasm32-unknown-emscripten=lib$(1)-*.so
CFG_LIB_DSYM_GLOB_wasm32-unknown-emscripten=lib$(1)-*.dylib.dSYM
CFG_JEMALLOC_CFLAGS_wasm32-unknown-emscripten := -m32 $(CFLAGS)
CFG_GCCISH_CFLAGS_wasm32-unknown-emscripten := -g -fPIC -m32 -s BINARYEN=1 $(CFLAGS)
CFG_GCCISH_CXXFLAGS_wasm32-unknown-emscripten := -fno-rtti -s BINARYEN=1 $(CXXFLAGS)
CFG_GCCISH_LINK_FLAGS_wasm32-unknown-emscripten := -shared -fPIC -ldl -pthread -lrt -g -m32 -s BINARYEN=1
CFG_GCCISH_DEF_FLAG_wasm32-unknown-emscripten := -Wl,--export-dynamic,--dynamic-list=
CFG_LLC_FLAGS_wasm32-unknown-emscripten :=
CFG_INSTALL_NAME_wasm32-unknown-emscripten =
CFG_EXE_SUFFIX_wasm32-unknown-emscripten =
CFG_WINDOWSY_wasm32-unknown-emscripten :=
CFG_UNIXY_wasm32-unknown-emscripten := 1
CFG_LDPATH_wasm32-unknown-emscripten :=
CFG_RUN_wasm32-unknown-emscripten=$(2)
CFG_RUN_TARG_wasm32-unknown-emscripten=$(call CFG_RUN_wasm32-unknown-emscripten,,$(2))
CFG_GNU_TRIPLE_wasm32-unknown-emscripten := wasm32-unknown-emscripten
CFG_DISABLE_JEMALLOC_wasm32-unknown-emscripten := 1

View File

@ -0,0 +1 @@
# rustbuild-only target

View File

@ -59,9 +59,9 @@ RUSTC_CRATES := rustc rustc_typeck rustc_mir rustc_borrowck rustc_resolve rustc_
rustc_trans rustc_back rustc_llvm rustc_privacy rustc_lint \
rustc_data_structures rustc_platform_intrinsics rustc_errors \
rustc_plugin rustc_metadata rustc_passes rustc_save_analysis \
rustc_const_eval rustc_const_math rustc_incremental rustc_macro
HOST_CRATES := syntax syntax_ext proc_macro syntax_pos $(RUSTC_CRATES) rustdoc fmt_macros \
flate arena graphviz log serialize
rustc_const_eval rustc_const_math rustc_incremental proc_macro
HOST_CRATES := syntax syntax_ext proc_macro_tokens proc_macro_plugin syntax_pos $(RUSTC_CRATES) \
rustdoc fmt_macros flate arena graphviz log serialize
TOOLS := compiletest rustdoc rustc rustbook error_index_generator
DEPS_core :=
@ -101,9 +101,10 @@ DEPS_term := std
DEPS_test := std getopts term native:rust_test_helpers
DEPS_syntax := std term serialize log arena libc rustc_bitflags rustc_unicode rustc_errors syntax_pos
DEPS_syntax_ext := syntax syntax_pos rustc_errors fmt_macros rustc_macro
DEPS_proc_macro := syntax syntax_pos rustc_plugin log
DEPS_syntax_ext := syntax syntax_pos rustc_errors fmt_macros proc_macro
DEPS_syntax_pos := serialize
DEPS_proc_macro_tokens := syntax syntax_pos log
DEPS_proc_macro_plugin := syntax syntax_pos rustc_plugin log proc_macro_tokens
DEPS_rustc_const_math := std syntax log serialize
DEPS_rustc_const_eval := rustc_const_math rustc syntax log serialize \
@ -118,15 +119,15 @@ DEPS_rustc_data_structures := std log serialize libc
DEPS_rustc_driver := arena flate getopts graphviz libc rustc rustc_back rustc_borrowck \
rustc_typeck rustc_mir rustc_resolve log syntax serialize rustc_llvm \
rustc_trans rustc_privacy rustc_lint rustc_plugin \
rustc_metadata syntax_ext proc_macro \
rustc_metadata syntax_ext proc_macro_plugin \
rustc_passes rustc_save_analysis rustc_const_eval \
rustc_incremental syntax_pos rustc_errors rustc_macro
rustc_incremental syntax_pos rustc_errors proc_macro rustc_data_structures
DEPS_rustc_errors := log libc serialize syntax_pos
DEPS_rustc_lint := rustc log syntax syntax_pos rustc_const_eval
DEPS_rustc_llvm := native:rustllvm libc std rustc_bitflags
DEPS_rustc_macro := std syntax
DEPS_proc_macro := std syntax
DEPS_rustc_metadata := rustc syntax syntax_pos rustc_errors rustc_const_math \
rustc_macro syntax_ext
proc_macro syntax_ext
DEPS_rustc_passes := syntax syntax_pos rustc core rustc_const_eval rustc_errors
DEPS_rustc_mir := rustc syntax syntax_pos rustc_const_math rustc_const_eval rustc_bitflags
DEPS_rustc_resolve := arena rustc log syntax syntax_pos rustc_errors

View File

@ -36,22 +36,27 @@ endif
# If CFG_LLVM_ROOT is defined then we don't build LLVM ourselves
ifeq ($(CFG_LLVM_ROOT),)
LLVM_STAMP_$(1) = $$(CFG_LLVM_BUILD_DIR_$(1))/llvm-auto-clean-stamp
LLVM_STAMP_$(1) = $(S)src/rustllvm/llvm-auto-clean-trigger
LLVM_DONE_$(1) = $$(CFG_LLVM_BUILD_DIR_$(1))/llvm-finished-building
$$(LLVM_CONFIG_$(1)): $$(LLVM_DONE_$(1))
ifneq ($$(CFG_NINJA),)
BUILD_LLVM_$(1) := $$(CFG_NINJA) -C $$(CFG_LLVM_BUILD_DIR_$(1))
else ifeq ($$(findstring msvc,$(1)),msvc)
BUILD_LLVM_$(1) := $$(CFG_CMAKE) --build $$(CFG_LLVM_BUILD_DIR_$(1)) \
--config $$(LLVM_BUILD_CONFIG_MODE)
else
BUILD_LLVM_$(1) := $$(MAKE) -C $$(CFG_LLVM_BUILD_DIR_$(1))
endif
$$(LLVM_DONE_$(1)): $$(LLVM_DEPS_TARGET_$(1)) $$(LLVM_STAMP_$(1))
@$$(call E, cmake: llvm)
ifneq ($$(CFG_NINJA),)
$$(Q)$$(CFG_NINJA) -C $$(CFG_LLVM_BUILD_DIR_$(1))
else ifeq ($$(findstring msvc,$(1)),msvc)
$$(Q)$$(CFG_CMAKE) --build $$(CFG_LLVM_BUILD_DIR_$(1)) \
--config $$(LLVM_BUILD_CONFIG_MODE)
else
$$(Q)$$(MAKE) -C $$(CFG_LLVM_BUILD_DIR_$(1))
endif
$$(Q)touch $$@
$$(Q)if ! cmp $$(LLVM_STAMP_$(1)) $$(LLVM_DONE_$(1)); then \
$$(MAKE) clean-llvm$(1); \
$$(BUILD_LLVM_$(1)); \
fi
$$(Q)cp $$(LLVM_STAMP_$(1)) $$@
ifneq ($$(CFG_NINJA),)
clean-llvm$(1):
@ -75,17 +80,6 @@ endif
$$(LLVM_AR_$(1)): $$(LLVM_CONFIG_$(1))
# This is used to independently force an LLVM clean rebuild
# when we changed something not otherwise captured by builtin
# dependencies. In these cases, commit a change that touches
# the stamp in the source dir.
$$(LLVM_STAMP_$(1)): $$(S)src/rustllvm/llvm-auto-clean-trigger
@$$(call E, make: cleaning llvm)
$$(Q)touch $$@.start_time
$$(Q)$$(MAKE) clean-llvm$(1)
@$$(call E, make: done cleaning llvm)
touch -r $$@.start_time $$@ && rm $$@.start_time
ifeq ($$(CFG_ENABLE_LLVM_STATIC_STDCPP),1)
LLVM_STDCPP_RUSTFLAGS_$(1) = -L "$$(dir $$(shell $$(CC_$(1)) $$(CFG_GCCISH_CFLAGS_$(1)) \
-print-file-name=lib$(CFG_STDCPP_NAME).a))"

View File

@ -13,12 +13,12 @@
######################################################################
# The version number
CFG_RELEASE_NUM=1.13.0
CFG_RELEASE_NUM=1.14.0
# An optional number to put after the label, e.g. '.2' -> '-beta.2'
# NB Make sure it starts with a dot to conform to semver pre-release
# versions (section 9)
CFG_PRERELEASE_VERSION=.3
CFG_PRERELEASE_VERSION=.5
ifeq ($(CFG_RELEASE_CHANNEL),stable)
# This is the normal semver version string, e.g. "0.12.0", "0.12.0-nightly"
@ -53,11 +53,12 @@ endif
# versions in the same place
CFG_FILENAME_EXTRA=$(shell printf '%s' $(CFG_RELEASE)$(CFG_EXTRA_FILENAME) | $(CFG_HASH_COMMAND))
# If local-rust is the same as the current version, then force a local-rebuild
# If local-rust is the same major.minor as the current version, then force a local-rebuild
ifdef CFG_ENABLE_LOCAL_RUST
ifeq ($(CFG_RELEASE),\
$(shell $(S)src/etc/local_stage0.sh --print-rustc-release $(CFG_LOCAL_RUST_ROOT)))
CFG_INFO := $(info cfg: auto-detected local-rebuild $(CFG_RELEASE))
SEMVER_PREFIX=$(shell echo $(CFG_RELEASE_NUM) | grep -E -o '^[[:digit:]]+\.[[:digit:]]+')
LOCAL_RELEASE=$(shell $(S)src/etc/local_stage0.sh --print-rustc-release $(CFG_LOCAL_RUST_ROOT))
ifneq (,$(filter $(SEMVER_PREFIX).%,$(LOCAL_RELEASE)))
CFG_INFO := $(info cfg: auto-detected local-rebuild using $(LOCAL_RELEASE))
CFG_ENABLE_LOCAL_REBUILD = 1
endif
endif
@ -141,6 +142,9 @@ endif
ifdef CFG_ENABLE_DEBUGINFO
$(info cfg: enabling debuginfo (CFG_ENABLE_DEBUGINFO))
CFG_RUSTC_FLAGS += -g
else ifdef CFG_ENABLE_DEBUGINFO_LINES
$(info cfg: enabling line number debuginfo (CFG_ENABLE_DEBUGINFO_LINES))
CFG_RUSTC_FLAGS += -Cdebuginfo=1
endif
ifdef SAVE_TEMPS
@ -281,7 +285,7 @@ endif
# LLVM macros
######################################################################
LLVM_OPTIONAL_COMPONENTS=x86 arm aarch64 mips powerpc pnacl systemz
LLVM_OPTIONAL_COMPONENTS=x86 arm aarch64 mips powerpc pnacl systemz jsbackend
LLVM_REQUIRED_COMPONENTS=ipo bitreader bitwriter linker asmparser mcjit \
interpreter instrumentation
@ -376,7 +380,7 @@ endif
# FIXME: Transitionary measure to bootstrap using the old bootstrap logic.
# Remove this once the bootstrap compiler uses the new login in Issue #36548.
export RUSTC_BOOTSTRAP_KEY=5c6cf767
export RUSTC_BOOTSTRAP_KEY=62b3e239
######################################################################
# Per-stage targets and runner

View File

@ -632,6 +632,7 @@ endif
# is a separate choice from whether to pass `-g` when building the
# compiler and standard library themselves.
CTEST_RUSTC_FLAGS := $$(subst -g,,$$(CTEST_RUSTC_FLAGS))
CTEST_RUSTC_FLAGS := $$(subst -Cdebuginfo=1,,$$(CTEST_RUSTC_FLAGS))
ifdef CFG_ENABLE_DEBUGINFO_TESTS
CTEST_RUSTC_FLAGS += -g
endif
@ -647,7 +648,7 @@ CTEST_COMMON_ARGS$(1)-T-$(2)-H-$(3) = \
--host $(3) \
--docck-python $$(CFG_PYTHON) \
--lldb-python $$(CFG_LLDB_PYTHON) \
--gdb-version="$(CFG_GDB_VERSION)" \
--gdb="$(CFG_GDB)" \
--lldb-version="$(CFG_LLDB_VERSION)" \
--llvm-version="$$(LLVM_VERSION_$(3))" \
--android-cross-path=$(CFG_ARM_LINUX_ANDROIDEABI_NDK) \

180
src/bootstrap/Cargo.lock generated
View File

@ -1,180 +0,0 @@
[root]
name = "bootstrap"
version = "0.0.0"
dependencies = [
"build_helper 0.1.0",
"cmake 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)",
"filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"gcc 0.3.31 (git+https://github.com/alexcrichton/gcc-rs)",
"getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
"md5 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 0.1.73 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
"toml 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "aho-corasick"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "build_helper"
version = "0.1.0"
[[package]]
name = "cmake"
version = "0.1.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"gcc 0.3.31 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "filetime"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "gcc"
version = "0.3.31"
source = "git+https://github.com/alexcrichton/gcc-rs#b8e2400883f1a2749b323354dad372cdd1c838c7"
[[package]]
name = "gcc"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "getopts"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "kernel32-sys"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "libc"
version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "md5"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "memchr"
version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num_cpus"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "regex"
version = "0.1.73"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"aho-corasick 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
"regex-syntax 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"thread_local 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
"utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "regex-syntax"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "rustc-serialize"
version = "0.3.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "thread-id"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "thread_local"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "toml"
version = "0.1.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "utf8-ranges"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "winapi"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "winapi-build"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[metadata]
"checksum aho-corasick 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2b3fb52b09c1710b961acb35390d514be82e4ac96a9969a8e38565a29b878dc9"
"checksum cmake 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "dfcf5bcece56ef953b8ea042509e9dcbdfe97820b7e20d86beb53df30ed94978"
"checksum filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "5363ab8e4139b8568a6237db5248646e5a8a2f89bd5ccb02092182b11fd3e922"
"checksum gcc 0.3.31 (git+https://github.com/alexcrichton/gcc-rs)" = "<none>"
"checksum gcc 0.3.31 (registry+https://github.com/rust-lang/crates.io-index)" = "cfe877476e53690ebb0ce7325d0bf43e198d9500291b54b3c65e518de5039b07"
"checksum getopts 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9047cfbd08a437050b363d35ef160452c5fe8ea5187ae0a624708c91581d685"
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
"checksum libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "55f3730be7e803cf350d32061958171731c2395831fbd67a61083782808183e0"
"checksum md5 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a5539a8dee9b4ae308c9c406a379838b435a8f2c84cf9fedc6d5a576be9888db"
"checksum memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d8b629fb514376c675b98c1421e80b151d3817ac42d7c667717d282761418d20"
"checksum num_cpus 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "51fedae97a05f7353612fe017ab705a37e6db8f4d67c5c6fe739a9e70d6eed09"
"checksum regex 0.1.73 (registry+https://github.com/rust-lang/crates.io-index)" = "56b7ee9f764ecf412c6e2fff779bca4b22980517ae335a21aeaf4e32625a5df2"
"checksum regex-syntax 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "31040aad7470ad9d8c46302dcffba337bb4289ca5da2e3cd6e37b64109a85199"
"checksum rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)" = "6159e4e6e559c81bd706afe9c8fd68f547d3e851ce12e76b1de7914bab61691b"
"checksum thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9539db560102d1cef46b8b78ce737ff0bb64e7e18d35b2a5688f7d097d0ff03"
"checksum thread_local 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "55dd963dbaeadc08aa7266bf7f91c3154a7805e32bb94b820b769d2ef3b4744d"
"checksum toml 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "fcd27a04ca509aff336ba5eb2abc58d456f52c4ff64d9724d88acb85ead560b6"
"checksum utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1ca13c08c41c9c3e04224ed9ff80461d97e121589ff27c753a16cb10830ae0f"
"checksum winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "4dfaaa8fbdaa618fa6914b59b2769d690dd7521920a18d84b42d254678dd5fd4"
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"

View File

@ -27,9 +27,10 @@ num_cpus = "0.2"
toml = "0.1"
getopts = "0.2"
rustc-serialize = "0.3"
winapi = "0.2"
kernel32-sys = "0.2"
gcc = { git = "https://github.com/alexcrichton/gcc-rs" }
gcc = "0.3.36"
libc = "0.2"
md5 = "0.1"
regex = "0.1.73"
[target.'cfg(windows)'.dependencies]
winapi = "0.2"
kernel32-sys = "0.2"

View File

@ -10,8 +10,64 @@ system.
## Using rustbuild
When configuring Rust via `./configure`, pass the following to enable building
via this build system:
The rustbuild build system has a primary entry point, a top level `x.py` script:
```
python ./x.py build
```
Note that if you're on Unix you should be able to execute the script directly:
```
./x.py build
```
The script accepts commands, flags, and filters to determine what to do:
* `build` - a general purpose command for compiling code. Alone `build` will
bootstrap the entire compiler, and otherwise arguments passed indicate what to
build. For example:
```
# build the whole compiler
./x.py build
# build the stage1 compier
./x.py build --stage 1
# build stage0 libstd
./x.py build --stage 0 src/libstd
# build a particular crate in stage0
./x.py build --stage 0 src/libtest
```
* `test` - a command for executing unit tests. Like the `build` command this
will execute the entire test suite by default, and otherwise it can be used to
select which test suite is run:
```
# run all unit tests
./x.py test
# execute the run-pass test suite
./x.py test src/test/run-pass
# execute only some tests in the run-pass test suite
./x.py test src/test/run-pass --filter my-filter
# execute tests in the standard library in stage0
./x.py test --stage 0 src/libstd
# execute all doc tests
./x.py test src/doc
```
* `doc` - a command for building documentation. Like above can take arguments
for what to document.
If you're more used to `./configure` and `make`, however, then you can also
configure the build system to use rustbuild instead of the old makefiles:
```
./configure --enable-rustbuild
@ -19,15 +75,7 @@ make
```
Afterwards the `Makefile` which is generated will have a few commands like
`make check`, `make tidy`, etc. For finer-grained control, the
`bootstrap.py` entry point can be used:
```
python src/bootstrap/bootstrap.py
```
This accepts a number of options like `--stage` and `--step` which can configure
what's actually being done.
`make check`, `make tidy`, etc.
## Configuring rustbuild
@ -47,7 +95,7 @@ being invoked manually (via the python script).
The rustbuild build system goes through a few phases to actually build the
compiler. What actually happens when you invoke rustbuild is:
1. The entry point script, `src/bootstrap/bootstrap.py` is run. This script is
1. The entry point script, `x.py` is run. This script is
responsible for downloading the stage0 compiler/Cargo binaries, and it then
compiles the build system itself (this folder). Finally, it then invokes the
actual `bootstrap` binary build system.

View File

@ -36,8 +36,9 @@ fn main() {
let args = env::args_os().skip(1).collect::<Vec<_>>();
// Detect whether or not we're a build script depending on whether --target
// is passed (a bit janky...)
let target = args.windows(2).find(|w| &*w[0] == "--target")
.and_then(|w| w[1].to_str());
let target = args.windows(2)
.find(|w| &*w[0] == "--target")
.and_then(|w| w[1].to_str());
let version = args.iter().find(|w| &**w == "-vV");
// Build scripts always use the snapshot compiler which is guaranteed to be
@ -64,9 +65,10 @@ fn main() {
let mut cmd = Command::new(rustc);
cmd.args(&args)
.arg("--cfg").arg(format!("stage{}", stage))
.env(bootstrap::util::dylib_path_var(),
env::join_paths(&dylib_path).unwrap());
.arg("--cfg")
.arg(format!("stage{}", stage))
.env(bootstrap::util::dylib_path_var(),
env::join_paths(&dylib_path).unwrap());
if let Some(target) = target {
// The stage0 compiler has a special sysroot distinct from what we
@ -101,11 +103,9 @@ fn main() {
// This... is a bit of a hack how we detect this. Ideally this
// information should be encoded in the crate I guess? Would likely
// require an RFC amendment to RFC 1513, however.
let is_panic_abort = args.windows(2).any(|a| {
&*a[0] == "--crate-name" && &*a[1] == "panic_abort"
});
// FIXME(stage0): remove this `stage != "0"` condition
if is_panic_abort && stage != "0" {
let is_panic_abort = args.windows(2)
.any(|a| &*a[0] == "--crate-name" && &*a[1] == "panic_abort");
if is_panic_abort {
cmd.arg("-C").arg("panic=abort");
}
@ -113,9 +113,11 @@ fn main() {
// code.
if env::var("RUSTC_DEBUGINFO") == Ok("true".to_string()) {
cmd.arg("-g");
} else if env::var("RUSTC_DEBUGINFO_LINES") == Ok("true".to_string()) {
cmd.arg("-Cdebuginfo=1");
}
let debug_assertions = match env::var("RUSTC_DEBUG_ASSERTIONS") {
Ok(s) => if s == "true" {"y"} else {"n"},
Ok(s) => if s == "true" { "y" } else { "n" },
Err(..) => "n",
};
cmd.arg("-C").arg(format!("debug-assertions={}", debug_assertions));

View File

@ -29,10 +29,12 @@ fn main() {
let mut cmd = Command::new(rustdoc);
cmd.args(&args)
.arg("--cfg").arg(format!("stage{}", stage))
.arg("--cfg").arg("dox")
.env(bootstrap::util::dylib_path_var(),
env::join_paths(&dylib_path).unwrap());
.arg("--cfg")
.arg(format!("stage{}", stage))
.arg("--cfg")
.arg("dox")
.env(bootstrap::util::dylib_path_var(),
env::join_paths(&dylib_path).unwrap());
std::process::exit(match cmd.status() {
Ok(s) => s.code().unwrap_or(1),
Err(e) => panic!("\n\nfailed to run {:?}: {}\n\n", cmd, e),

View File

@ -344,6 +344,22 @@ class RustBuild(object):
ostype += 'eabihf'
elif cputype == 'aarch64':
cputype = 'aarch64'
elif cputype == 'mips':
if sys.byteorder == 'big':
cputype = 'mips'
elif sys.byteorder == 'little':
cputype = 'mipsel'
else:
raise ValueError('unknown byteorder: ' + sys.byteorder)
elif cputype == 'mips64':
if sys.byteorder == 'big':
cputype = 'mips64'
elif sys.byteorder == 'little':
cputype = 'mips64el'
else:
raise ValueError('unknown byteorder: ' + sys.byteorder)
# only the n64 ABI is supported, indicate it
ostype += 'abi64'
elif cputype in {'powerpc', 'ppc', 'ppc64'}:
cputype = 'powerpc'
elif cputype in {'amd64', 'x86_64', 'x86-64', 'x64'}:
@ -399,12 +415,10 @@ def main():
# Run the bootstrap
args = [os.path.join(rb.build_dir, "bootstrap/debug/bootstrap")]
args.append('--src')
args.append(rb.rust_root)
args.append('--build')
args.append(rb.build)
args.extend(sys.argv[1:])
env = os.environ.copy()
env["BUILD"] = rb.build
env["SRC"] = rb.rust_root
env["BOOTSTRAP_PARENT_ID"] = str(os.getpid())
rb.run(args, env)

View File

@ -13,9 +13,9 @@
//! This file implements the various regression test suites that we execute on
//! our CI.
use std::collections::HashSet;
use std::env;
use std::fs::{self, File};
use std::io::prelude::*;
use std::fs;
use std::path::{PathBuf, Path};
use std::process::Command;
@ -108,6 +108,10 @@ pub fn compiletest(build: &Build,
cmd.arg("--host").arg(compiler.host);
cmd.arg("--llvm-filecheck").arg(build.llvm_filecheck(&build.config.build));
if let Some(nodejs) = build.config.nodejs.as_ref() {
cmd.arg("--nodejs").arg(nodejs);
}
let mut flags = vec!["-Crpath".to_string()];
if build.config.rust_optimize_tests {
flags.push("-O".to_string());
@ -139,8 +143,8 @@ pub fn compiletest(build: &Build,
cmd.arg("--lldb-python").arg(python_default);
}
if let Some(ref vers) = build.gdb_version {
cmd.arg("--gdb-version").arg(vers);
if let Some(ref gdb) = build.config.gdb {
cmd.arg("--gdb").arg(gdb);
}
if let Some(ref vers) = build.lldb_version {
cmd.arg("--lldb-version").arg(vers);
@ -152,12 +156,16 @@ pub fn compiletest(build: &Build,
let llvm_version = output(Command::new(&llvm_config).arg("--version"));
cmd.arg("--llvm-version").arg(llvm_version);
cmd.args(&build.flags.args);
cmd.args(&build.flags.cmd.test_args());
if build.config.verbose || build.flags.verbose {
cmd.arg("--verbose");
}
if build.config.quiet_tests {
cmd.arg("--quiet");
}
// Only pass correct values for these flags for the `run-make` suite as it
// requires that a C++ compiler was configured which isn't always the case.
if suite == "run-make" {
@ -248,7 +256,13 @@ fn markdown_test(build: &Build, compiler: &Compiler, markdown: &Path) {
build.add_rustc_lib_path(compiler, &mut cmd);
cmd.arg("--test");
cmd.arg(markdown);
cmd.arg("--test-args").arg(build.flags.args.join(" "));
let mut test_args = build.flags.cmd.test_args().join(" ");
if build.config.quiet_tests {
test_args.push_str(" --quiet");
}
cmd.arg("--test-args").arg(test_args);
build.run(&mut cmd);
}
@ -259,56 +273,58 @@ fn markdown_test(build: &Build, compiler: &Compiler, markdown: &Path) {
/// It essentially is the driver for running `cargo test`.
///
/// Currently this runs all tests for a DAG by passing a bunch of `-p foo`
/// arguments, and those arguments are discovered from `Cargo.lock`.
/// arguments, and those arguments are discovered from `cargo metadata`.
pub fn krate(build: &Build,
compiler: &Compiler,
target: &str,
mode: Mode) {
let (name, path, features) = match mode {
Mode::Libstd => ("libstd", "src/rustc/std_shim", build.std_features()),
Mode::Libtest => ("libtest", "src/rustc/test_shim", String::new()),
Mode::Librustc => ("librustc", "src/rustc", build.rustc_features()),
mode: Mode,
krate: Option<&str>) {
let (name, path, features, root) = match mode {
Mode::Libstd => {
("libstd", "src/rustc/std_shim", build.std_features(), "std_shim")
}
Mode::Libtest => {
("libtest", "src/rustc/test_shim", String::new(), "test_shim")
}
Mode::Librustc => {
("librustc", "src/rustc", build.rustc_features(), "rustc-main")
}
_ => panic!("can only test libraries"),
};
println!("Testing {} stage{} ({} -> {})", name, compiler.stage,
compiler.host, target);
// Build up the base `cargo test` command.
//
// Pass in some standard flags then iterate over the graph we've discovered
// in `cargo metadata` with the maps above and figure out what `-p`
// arguments need to get passed.
let mut cargo = build.cargo(compiler, mode, target, "test");
cargo.arg("--manifest-path")
.arg(build.src.join(path).join("Cargo.toml"))
.arg("--features").arg(features);
// Generate a list of `-p` arguments to pass to the `cargo test` invocation
// by crawling the corresponding Cargo.lock file.
let lockfile = build.src.join(path).join("Cargo.lock");
let mut contents = String::new();
t!(t!(File::open(&lockfile)).read_to_string(&mut contents));
let mut lines = contents.lines();
while let Some(line) = lines.next() {
let prefix = "name = \"";
if !line.starts_with(prefix) {
continue
match krate {
Some(krate) => {
cargo.arg("-p").arg(krate);
}
lines.next(); // skip `version = ...`
// skip crates.io or otherwise non-path crates
if let Some(line) = lines.next() {
if line.starts_with("source") {
continue
None => {
let mut visited = HashSet::new();
let mut next = vec![root];
while let Some(name) = next.pop() {
// Right now jemalloc is our only target-specific crate in the sense
// that it's not present on all platforms. Custom skip it here for now,
// but if we add more this probably wants to get more generalized.
if !name.contains("jemalloc") {
cargo.arg("-p").arg(name);
}
for dep in build.crates[name].deps.iter() {
if visited.insert(dep) {
next.push(dep);
}
}
}
}
let crate_name = &line[prefix.len()..line.len() - 1];
// Right now jemalloc is our only target-specific crate in the sense
// that it's not present on all platforms. Custom skip it here for now,
// but if we add more this probably wants to get more generalized.
if crate_name.contains("jemalloc") {
continue
}
cargo.arg("-p").arg(crate_name);
}
// The tests are going to run with the *target* libraries, so we need to
@ -320,11 +336,19 @@ pub fn krate(build: &Build,
dylib_path.insert(0, build.sysroot_libdir(compiler, target));
cargo.env(dylib_path_var(), env::join_paths(&dylib_path).unwrap());
if build.config.quiet_tests {
cargo.arg("--");
cargo.arg("--quiet");
}
if target.contains("android") {
build.run(cargo.arg("--no-run"));
krate_android(build, compiler, target, mode);
} else if target.contains("emscripten") {
build.run(cargo.arg("--no-run"));
krate_emscripten(build, compiler, target, mode);
} else {
cargo.args(&build.flags.args);
cargo.args(&build.flags.cmd.test_args());
build.run(&mut cargo);
}
}
@ -356,7 +380,7 @@ fn krate_android(build: &Build,
target = target,
test = test_file_name,
log = log,
args = build.flags.args.join(" "));
args = build.flags.cmd.test_args().join(" "));
let output = output(Command::new("adb").arg("shell").arg(&program));
println!("{}", output);
@ -371,6 +395,35 @@ fn krate_android(build: &Build,
}
}
fn krate_emscripten(build: &Build,
compiler: &Compiler,
target: &str,
mode: Mode) {
let mut tests = Vec::new();
let out_dir = build.cargo_out(compiler, mode, target);
find_tests(&out_dir, target, &mut tests);
find_tests(&out_dir.join("deps"), target, &mut tests);
for test in tests {
let test_file_name = test.to_string_lossy().into_owned();
println!("running {}", test_file_name);
let nodejs = build.config.nodejs.as_ref().expect("nodejs not configured");
let status = Command::new(nodejs)
.arg(&test_file_name)
.stderr(::std::process::Stdio::inherit())
.status();
match status {
Ok(status) => {
if !status.success() {
panic!("some tests failed");
}
}
Err(e) => panic!(format!("failed to execute command: {}", e)),
};
}
}
fn find_tests(dir: &Path,
target: &str,
dst: &mut Vec<PathBuf>) {
@ -381,7 +434,8 @@ fn find_tests(dir: &Path,
}
let filename = e.file_name().into_string().unwrap();
if (target.contains("windows") && filename.ends_with(".exe")) ||
(!target.contains("windows") && !filename.contains(".")) {
(!target.contains("windows") && !filename.contains(".")) ||
(target.contains("emscripten") && filename.contains(".js")){
dst.push(e.path());
}
}

View File

@ -16,6 +16,7 @@
//! directory as we want that cached between builds.
use std::fs;
use std::io::{self, ErrorKind};
use std::path::Path;
use Build;
@ -25,24 +26,58 @@ pub fn clean(build: &Build) {
rm_rf(build, &build.out.join("tmp"));
for host in build.config.host.iter() {
let entries = match build.out.join(host).read_dir() {
Ok(iter) => iter,
Err(_) => continue,
};
let out = build.out.join(host);
rm_rf(build, &out.join("doc"));
for stage in 0..4 {
rm_rf(build, &out.join(format!("stage{}", stage)));
rm_rf(build, &out.join(format!("stage{}-std", stage)));
rm_rf(build, &out.join(format!("stage{}-rustc", stage)));
rm_rf(build, &out.join(format!("stage{}-tools", stage)));
rm_rf(build, &out.join(format!("stage{}-test", stage)));
for entry in entries {
let entry = t!(entry);
if entry.file_name().to_str() == Some("llvm") {
continue
}
let path = t!(entry.path().canonicalize());
rm_rf(build, &path);
}
}
}
fn rm_rf(build: &Build, path: &Path) {
if path.exists() {
build.verbose(&format!("removing `{}`", path.display()));
t!(fs::remove_dir_all(path));
if !path.exists() {
return
}
for file in t!(fs::read_dir(path)) {
let file = t!(file).path();
if file.is_dir() {
rm_rf(build, &file);
} else {
// On windows we can't remove a readonly file, and git will
// often clone files as readonly. As a result, we have some
// special logic to remove readonly files on windows.
do_op(&file, "remove file", |p| fs::remove_file(p));
}
}
do_op(path, "remove dir", |p| fs::remove_dir(p));
}
fn do_op<F>(path: &Path, desc: &str, mut f: F)
where F: FnMut(&Path) -> io::Result<()>
{
match f(path) {
Ok(()) => {}
Err(ref e) if cfg!(windows) &&
e.kind() == ErrorKind::PermissionDenied => {
let mut p = t!(path.metadata()).permissions();
p.set_readonly(false);
t!(fs::set_permissions(path, p));
f(path).unwrap_or_else(|e| {
panic!("failed to {} {}: {}", desc, path.display(), e);
})
}
Err(e) => {
panic!("failed to {} {}: {}", desc, path.display(), e);
}
}
}

View File

@ -25,7 +25,7 @@ use std::process::Command;
use build_helper::output;
use filetime::FileTime;
use util::{exe, staticlib, libdir, mtime, is_dylib, copy};
use util::{exe, libdir, mtime, is_dylib, copy};
use {Build, Compiler, Mode};
/// Build the standard library.
@ -40,20 +40,6 @@ pub fn std<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) {
let libdir = build.sysroot_libdir(compiler, target);
let _ = fs::remove_dir_all(&libdir);
t!(fs::create_dir_all(&libdir));
// FIXME(stage0) remove this `if` after the next snapshot
// The stage0 compiler still passes the `-lcompiler-rt` flag to the linker but now `bootstrap`
// never builds a `libcopmiler-rt.a`! We'll fill the hole by simply copying stage0's
// `libcompiler-rt.a` to where the stage1's one is expected (though we could as well just use
// an empty `.a` archive). Note that the symbols of that stage0 `libcompiler-rt.a` won't make
// it to the final binary because now `libcore.rlib` also contains the symbols that
// `libcompiler-rt.a` provides. Since that rlib appears first in the linker arguments, its
// symbols are used instead of `libcompiler-rt.a`'s.
if compiler.stage == 0 {
let rtlib = &staticlib("compiler-rt", target);
let src = build.rustc.parent().unwrap().parent().unwrap().join("lib").join("rustlib")
.join(target).join("lib").join(rtlib);
copy(&src, &libdir.join(rtlib));
}
// Some platforms have startup objects that may be required to produce the
// libstd dynamic library, for example.
@ -78,8 +64,8 @@ pub fn std<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) {
}
build.run(&mut cargo);
update_mtime(&libstd_stamp(build, compiler, target));
std_link(build, target, compiler, compiler.host);
update_mtime(&libstd_stamp(build, &compiler, target));
std_link(build, target, compiler.stage, compiler.host);
}
/// Link all libstd rlibs/dylibs into the sysroot location.
@ -88,11 +74,12 @@ pub fn std<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) {
/// by `compiler` into `host`'s sysroot.
pub fn std_link(build: &Build,
target: &str,
compiler: &Compiler,
stage: u32,
host: &str) {
let compiler = Compiler::new(stage, &build.config.build);
let target_compiler = Compiler::new(compiler.stage, host);
let libdir = build.sysroot_libdir(&target_compiler, target);
let out_dir = build.cargo_out(compiler, Mode::Libstd, target);
let out_dir = build.cargo_out(&compiler, Mode::Libstd, target);
// If we're linking one compiler host's output into another, then we weren't
// called from the `std` method above. In that case we clean out what's
@ -104,16 +91,16 @@ pub fn std_link(build: &Build,
add_to_sysroot(&out_dir, &libdir);
if target.contains("musl") && !target.contains("mips") {
copy_musl_third_party_objects(build, &libdir);
copy_musl_third_party_objects(build, target, &libdir);
}
}
/// Copies the crt(1,i,n).o startup objects
///
/// Only required for musl targets that statically link to libc
fn copy_musl_third_party_objects(build: &Build, into: &Path) {
fn copy_musl_third_party_objects(build: &Build, target: &str, into: &Path) {
for &obj in &["crt1.o", "crti.o", "crtn.o"] {
copy(&build.config.musl_root.as_ref().unwrap().join("lib").join(obj), &into.join(obj));
copy(&build.musl_root(target).unwrap().join("lib").join(obj), &into.join(obj));
}
}
@ -160,7 +147,7 @@ pub fn test<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) {
.arg(build.src.join("src/rustc/test_shim/Cargo.toml"));
build.run(&mut cargo);
update_mtime(&libtest_stamp(build, compiler, target));
test_link(build, target, compiler, compiler.host);
test_link(build, target, compiler.stage, compiler.host);
}
/// Link all libtest rlibs/dylibs into the sysroot location.
@ -169,11 +156,12 @@ pub fn test<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) {
/// by `compiler` into `host`'s sysroot.
pub fn test_link(build: &Build,
target: &str,
compiler: &Compiler,
stage: u32,
host: &str) {
let compiler = Compiler::new(stage, &build.config.build);
let target_compiler = Compiler::new(compiler.stage, host);
let libdir = build.sysroot_libdir(&target_compiler, target);
let out_dir = build.cargo_out(compiler, Mode::Libtest, target);
let out_dir = build.cargo_out(&compiler, Mode::Libtest, target);
add_to_sysroot(&out_dir, &libdir);
}
@ -232,7 +220,7 @@ pub fn rustc<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) {
}
build.run(&mut cargo);
rustc_link(build, target, compiler, compiler.host);
rustc_link(build, target, compiler.stage, compiler.host);
}
/// Link all librustc rlibs/dylibs into the sysroot location.
@ -241,11 +229,12 @@ pub fn rustc<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) {
/// by `compiler` into `host`'s sysroot.
pub fn rustc_link(build: &Build,
target: &str,
compiler: &Compiler,
stage: u32,
host: &str) {
let compiler = Compiler::new(stage, &build.config.build);
let target_compiler = Compiler::new(compiler.stage, host);
let libdir = build.sysroot_libdir(&target_compiler, target);
let out_dir = build.cargo_out(compiler, Mode::Librustc, target);
let out_dir = build.cargo_out(&compiler, Mode::Librustc, target);
add_to_sysroot(&out_dir, &libdir);
}
@ -273,7 +262,10 @@ fn compiler_file(compiler: &Path, file: &str) -> PathBuf {
/// must have been previously produced by the `stage - 1` build.config.build
/// compiler.
pub fn assemble_rustc(build: &Build, stage: u32, host: &str) {
assert!(stage > 0, "the stage0 compiler isn't assembled, it's downloaded");
// nothing to do in stage0
if stage == 0 {
return
}
// The compiler that we're assembling
let target_compiler = Compiler::new(stage, host);

View File

@ -23,6 +23,7 @@ use std::process;
use num_cpus;
use rustc_serialize::Decodable;
use toml::{Parser, Decoder, Value};
use util::push_exe_path;
/// Global configuration for the entire build and/or bootstrap.
///
@ -56,6 +57,7 @@ pub struct Config {
pub rust_codegen_units: u32,
pub rust_debug_assertions: bool,
pub rust_debuginfo: bool,
pub rust_debuginfo_lines: bool,
pub rust_rpath: bool,
pub rustc_default_linker: Option<String>,
pub rustc_default_ar: Option<String>,
@ -76,11 +78,16 @@ pub struct Config {
// misc
pub channel: String,
pub quiet_tests: bool,
// Fallback musl-root for all targets
pub musl_root: Option<PathBuf>,
pub prefix: Option<String>,
pub docdir: Option<String>,
pub libdir: Option<String>,
pub mandir: Option<String>,
pub codegen_tests: bool,
pub nodejs: Option<PathBuf>,
pub gdb: Option<PathBuf>,
}
/// Per-target configuration stored in the global configuration structure.
@ -117,6 +124,8 @@ struct Build {
rustc: Option<String>,
compiler_docs: Option<bool>,
docs: Option<bool>,
submodules: Option<bool>,
gdb: Option<String>,
}
/// TOML representation of how the LLVM build is configured.
@ -137,6 +146,7 @@ struct Rust {
codegen_units: Option<u32>,
debug_assertions: Option<bool>,
debuginfo: Option<bool>,
debuginfo_lines: Option<bool>,
debug_jemalloc: Option<bool>,
use_jemalloc: Option<bool>,
backtrace: Option<bool>,
@ -158,6 +168,7 @@ struct TomlTarget {
cc: Option<String>,
cxx: Option<String>,
android_ndk: Option<String>,
musl_root: Option<String>,
}
impl Config {
@ -219,8 +230,10 @@ impl Config {
}
config.rustc = build.rustc.map(PathBuf::from);
config.cargo = build.cargo.map(PathBuf::from);
config.gdb = build.gdb.map(PathBuf::from);
set(&mut config.compiler_docs, build.compiler_docs);
set(&mut config.docs, build.docs);
set(&mut config.submodules, build.submodules);
if let Some(ref llvm) = toml.llvm {
set(&mut config.ccache, llvm.ccache);
@ -233,6 +246,7 @@ impl Config {
if let Some(ref rust) = toml.rust {
set(&mut config.rust_debug_assertions, rust.debug_assertions);
set(&mut config.rust_debuginfo, rust.debuginfo);
set(&mut config.rust_debuginfo_lines, rust.debuginfo_lines);
set(&mut config.rust_optimize, rust.optimize);
set(&mut config.rust_optimize_tests, rust.optimize_tests);
set(&mut config.rust_debuginfo_tests, rust.debuginfo_tests);
@ -268,6 +282,7 @@ impl Config {
}
target.cxx = cfg.cxx.clone().map(PathBuf::from);
target.cc = cfg.cc.clone().map(PathBuf::from);
target.musl_root = cfg.musl_root.clone().map(PathBuf::from);
config.target_config.insert(triple.clone(), target);
}
@ -322,11 +337,13 @@ impl Config {
("OPTIMIZE", self.rust_optimize),
("DEBUG_ASSERTIONS", self.rust_debug_assertions),
("DEBUGINFO", self.rust_debuginfo),
("DEBUGINFO_LINES", self.rust_debuginfo_lines),
("JEMALLOC", self.use_jemalloc),
("DEBUG_JEMALLOC", self.debug_jemalloc),
("RPATH", self.rust_rpath),
("OPTIMIZE_TESTS", self.rust_optimize_tests),
("DEBUGINFO_TESTS", self.rust_debuginfo_tests),
("QUIET_TESTS", self.quiet_tests),
("LOCAL_REBUILD", self.local_rebuild),
("NINJA", self.ninja),
("CODEGEN_TESTS", self.codegen_tests),
@ -343,7 +360,37 @@ impl Config {
.collect();
}
"CFG_MUSL_ROOT" if value.len() > 0 => {
self.musl_root = Some(PathBuf::from(value));
self.musl_root = Some(parse_configure_path(value));
}
"CFG_MUSL_ROOT_X86_64" if value.len() > 0 => {
let target = "x86_64-unknown-linux-musl".to_string();
let target = self.target_config.entry(target)
.or_insert(Target::default());
target.musl_root = Some(parse_configure_path(value));
}
"CFG_MUSL_ROOT_I686" if value.len() > 0 => {
let target = "i686-unknown-linux-musl".to_string();
let target = self.target_config.entry(target)
.or_insert(Target::default());
target.musl_root = Some(parse_configure_path(value));
}
"CFG_MUSL_ROOT_ARM" if value.len() > 0 => {
let target = "arm-unknown-linux-musleabi".to_string();
let target = self.target_config.entry(target)
.or_insert(Target::default());
target.musl_root = Some(parse_configure_path(value));
}
"CFG_MUSL_ROOT_ARMHF" if value.len() > 0 => {
let target = "arm-unknown-linux-musleabihf".to_string();
let target = self.target_config.entry(target)
.or_insert(Target::default());
target.musl_root = Some(parse_configure_path(value));
}
"CFG_MUSL_ROOT_ARMV7" if value.len() > 0 => {
let target = "armv7-unknown-linux-musleabihf".to_string();
let target = self.target_config.entry(target)
.or_insert(Target::default());
target.musl_root = Some(parse_configure_path(value));
}
"CFG_DEFAULT_AR" if value.len() > 0 => {
self.rustc_default_ar = Some(value.to_string());
@ -351,53 +398,63 @@ impl Config {
"CFG_DEFAULT_LINKER" if value.len() > 0 => {
self.rustc_default_linker = Some(value.to_string());
}
"CFG_GDB" if value.len() > 0 => {
self.gdb = Some(parse_configure_path(value));
}
"CFG_RELEASE_CHANNEL" => {
self.channel = value.to_string();
}
"CFG_PREFIX" => {
self.prefix = Some(value.to_string());
}
"CFG_DOCDIR" => {
self.docdir = Some(value.to_string());
}
"CFG_LIBDIR" => {
self.libdir = Some(value.to_string());
}
"CFG_MANDIR" => {
self.mandir = Some(value.to_string());
}
"CFG_LLVM_ROOT" if value.len() > 0 => {
let target = self.target_config.entry(self.build.clone())
.or_insert(Target::default());
let root = PathBuf::from(value);
target.llvm_config = Some(root.join("bin/llvm-config"));
let root = parse_configure_path(value);
target.llvm_config = Some(push_exe_path(root, &["bin", "llvm-config"]));
}
"CFG_JEMALLOC_ROOT" if value.len() > 0 => {
let target = self.target_config.entry(self.build.clone())
.or_insert(Target::default());
target.jemalloc = Some(PathBuf::from(value));
target.jemalloc = Some(parse_configure_path(value));
}
"CFG_ARM_LINUX_ANDROIDEABI_NDK" if value.len() > 0 => {
let target = "arm-linux-androideabi".to_string();
let target = self.target_config.entry(target)
.or_insert(Target::default());
target.ndk = Some(PathBuf::from(value));
target.ndk = Some(parse_configure_path(value));
}
"CFG_ARMV7_LINUX_ANDROIDEABI_NDK" if value.len() > 0 => {
let target = "armv7-linux-androideabi".to_string();
let target = self.target_config.entry(target)
.or_insert(Target::default());
target.ndk = Some(PathBuf::from(value));
target.ndk = Some(parse_configure_path(value));
}
"CFG_I686_LINUX_ANDROID_NDK" if value.len() > 0 => {
let target = "i686-linux-android".to_string();
let target = self.target_config.entry(target)
.or_insert(Target::default());
target.ndk = Some(PathBuf::from(value));
target.ndk = Some(parse_configure_path(value));
}
"CFG_AARCH64_LINUX_ANDROID_NDK" if value.len() > 0 => {
let target = "aarch64-linux-android".to_string();
let target = self.target_config.entry(target)
.or_insert(Target::default());
target.ndk = Some(PathBuf::from(value));
target.ndk = Some(parse_configure_path(value));
}
"CFG_LOCAL_RUST_ROOT" if value.len() > 0 => {
self.rustc = Some(PathBuf::from(value).join("bin/rustc"));
self.cargo = Some(PathBuf::from(value).join("bin/cargo"));
}
"CFG_NODEJS" if value.len() > 0 => {
self.nodejs = Some(PathBuf::from(value));
let path = parse_configure_path(value);
self.rustc = Some(push_exe_path(path.clone(), &["bin", "rustc"]));
self.cargo = Some(push_exe_path(path, &["bin", "cargo"]));
}
_ => {}
}
@ -405,6 +462,30 @@ impl Config {
}
}
#[cfg(not(windows))]
fn parse_configure_path(path: &str) -> PathBuf {
path.into()
}
#[cfg(windows)]
fn parse_configure_path(path: &str) -> PathBuf {
// on windows, configure produces unix style paths e.g. /c/some/path but we
// only want real windows paths
use std::process::Command;
use build_helper;
// '/' is invalid in windows paths, so we can detect unix paths by the presence of it
if !path.contains('/') {
return path.into();
}
let win_path = build_helper::output(Command::new("cygpath").arg("-w").arg(path));
let win_path = win_path.trim();
win_path.into()
}
fn set<T>(field: &mut T, val: Option<T>) {
if let Some(v) = val {
*field = v;

View File

@ -76,6 +76,12 @@
# library and facade crates.
#compiler-docs = false
# Indicate whether submodules are managed and updated automatically.
#submodules = true
# The path to (or name of) the GDB executable to use
#gdb = "gdb"
# =============================================================================
# Options for compiling Rust code itself
# =============================================================================
@ -96,6 +102,9 @@
# Whether or not debuginfo is emitted
#debuginfo = false
# Whether or not line number debug information is emitted
#debuginfo-lines = false
# Whether or not jemalloc is built and enabled
#use-jemalloc = true

View File

@ -25,9 +25,8 @@ use std::process::Command;
use {Build, Compiler};
use util::{cp_r, libdir, is_dylib, cp_filtered, copy};
use regex::{RegexSet, quote};
fn package_vers(build: &Build) -> &str {
pub fn package_vers(build: &Build) -> &str {
match &build.config.channel[..] {
"stable" => &build.release,
"beta" => "beta",
@ -40,7 +39,7 @@ fn distdir(build: &Build) -> PathBuf {
build.out.join("dist")
}
fn tmpdir(build: &Build) -> PathBuf {
pub fn tmpdir(build: &Build) -> PathBuf {
build.out.join("tmp/dist")
}
@ -315,49 +314,31 @@ pub fn rust_src(build: &Build) {
"mk"
];
// Exclude paths matching these wildcard expressions
let excludes = [
// exclude-vcs
"CVS", "RCS", "SCCS", ".git", ".gitignore", ".gitmodules", ".gitattributes", ".cvsignore",
".svn", ".arch-ids", "{arch}", "=RELEASE-ID", "=meta-update", "=update", ".bzr",
".bzrignore", ".bzrtags", ".hg", ".hgignore", ".hgrags", "_darcs",
// extensions
"*~", "*.pyc",
// misc
"llvm/test/*/*.ll",
"llvm/test/*/*.td",
"llvm/test/*/*.s",
"llvm/test/*/*/*.ll",
"llvm/test/*/*/*.td",
"llvm/test/*/*/*.s"
];
// Construct a set of regexes for efficiently testing whether paths match one of the above
// expressions.
let regex_set = t!(RegexSet::new(
// This converts a wildcard expression to a regex
excludes.iter().map(|&s| {
// Prefix ensures that matching starts on a path separator boundary
r"^(.*[\\/])?".to_owned() + (
// Escape the expression to produce a regex matching exactly that string
&quote(s)
// Replace slashes with a pattern matching either forward or backslash
.replace(r"/", r"[\\/]")
// Replace wildcards with a pattern matching a single path segment, ie. containing
// no slashes.
.replace(r"\*", r"[^\\/]*")
// Suffix anchors to the end of the path
) + "$"
})
));
// Create a filter which skips files which match the regex set or contain invalid unicode
let filter_fn = move |path: &Path| {
if let Some(path) = path.to_str() {
!regex_set.is_match(path)
} else {
false
let spath = match path.to_str() {
Some(path) => path,
None => return false,
};
if spath.ends_with("~") || spath.ends_with(".pyc") {
return false
}
if spath.contains("llvm/test") || spath.contains("llvm\\test") {
if spath.ends_with(".ll") ||
spath.ends_with(".td") ||
spath.ends_with(".s") {
return false
}
}
let excludes = [
"CVS", "RCS", "SCCS", ".git", ".gitignore", ".gitmodules",
".gitattributes", ".cvsignore", ".svn", ".arch-ids", "{arch}",
"=RELEASE-ID", "=meta-update", "=update", ".bzr", ".bzrignore",
".bzrtags", ".hg", ".hgignore", ".hgrags", "_darcs",
];
!path.iter()
.map(|s| s.to_str().unwrap())
.any(|s| excludes.contains(&s))
};
// Copy the directories using our filter
@ -418,7 +399,7 @@ fn chmod(_path: &Path, _perms: u32) {}
// We have to run a few shell scripts, which choke quite a bit on both `\`
// characters and on `C:\` paths, so normalize both of them away.
fn sanitize_sh(path: &Path) -> String {
pub fn sanitize_sh(path: &Path) -> String {
let path = path.to_str().unwrap().replace("\\", "/");
return change_drive(&path).unwrap_or(path);

View File

@ -19,7 +19,6 @@
use std::fs::{self, File};
use std::io::prelude::*;
use std::path::Path;
use std::process::Command;
use {Build, Compiler, Mode};
@ -30,8 +29,9 @@ use util::{up_to_date, cp_r};
///
/// This will not actually generate any documentation if the documentation has
/// already been generated.
pub fn rustbook(build: &Build, stage: u32, target: &str, name: &str, out: &Path) {
t!(fs::create_dir_all(out));
pub fn rustbook(build: &Build, stage: u32, target: &str, name: &str) {
let out = build.doc_out(target);
t!(fs::create_dir_all(&out));
let out = out.join(name);
let compiler = Compiler::new(stage, &build.config.build);
@ -57,9 +57,10 @@ pub fn rustbook(build: &Build, stage: u32, target: &str, name: &str, out: &Path)
/// `STAMP` alongw ith providing the various header/footer HTML we've cutomized.
///
/// In the end, this is just a glorified wrapper around rustdoc!
pub fn standalone(build: &Build, stage: u32, target: &str, out: &Path) {
pub fn standalone(build: &Build, stage: u32, target: &str) {
println!("Documenting stage{} standalone ({})", stage, target);
t!(fs::create_dir_all(out));
let out = build.doc_out(target);
t!(fs::create_dir_all(&out));
let compiler = Compiler::new(stage, &build.config.build);
@ -109,7 +110,7 @@ pub fn standalone(build: &Build, stage: u32, target: &str, out: &Path) {
.arg("--html-in-header").arg(&favicon)
.arg("--markdown-playground-url")
.arg("https://play.rust-lang.org/")
.arg("-o").arg(out)
.arg("-o").arg(&out)
.arg(&path);
if filename == "reference.md" {
@ -131,9 +132,10 @@ pub fn standalone(build: &Build, stage: u32, target: &str, out: &Path) {
///
/// This will generate all documentation for the standard library and its
/// dependencies. This is largely just a wrapper around `cargo doc`.
pub fn std(build: &Build, stage: u32, target: &str, out: &Path) {
pub fn std(build: &Build, stage: u32, target: &str) {
println!("Documenting stage{} std ({})", stage, target);
t!(fs::create_dir_all(out));
let out = build.doc_out(target);
t!(fs::create_dir_all(&out));
let compiler = Compiler::new(stage, &build.config.build);
let out_dir = build.stage_out(&compiler, Mode::Libstd)
.join(target).join("doc");
@ -146,16 +148,17 @@ pub fn std(build: &Build, stage: u32, target: &str, out: &Path) {
.arg(build.src.join("src/rustc/std_shim/Cargo.toml"))
.arg("--features").arg(build.std_features());
build.run(&mut cargo);
cp_r(&out_dir, out)
cp_r(&out_dir, &out)
}
/// Compile all libtest documentation.
///
/// This will generate all documentation for libtest and its dependencies. This
/// is largely just a wrapper around `cargo doc`.
pub fn test(build: &Build, stage: u32, target: &str, out: &Path) {
pub fn test(build: &Build, stage: u32, target: &str) {
println!("Documenting stage{} test ({})", stage, target);
t!(fs::create_dir_all(out));
let out = build.doc_out(target);
t!(fs::create_dir_all(&out));
let compiler = Compiler::new(stage, &build.config.build);
let out_dir = build.stage_out(&compiler, Mode::Libtest)
.join(target).join("doc");
@ -167,16 +170,17 @@ pub fn test(build: &Build, stage: u32, target: &str, out: &Path) {
cargo.arg("--manifest-path")
.arg(build.src.join("src/rustc/test_shim/Cargo.toml"));
build.run(&mut cargo);
cp_r(&out_dir, out)
cp_r(&out_dir, &out)
}
/// Generate all compiler documentation.
///
/// This will generate all documentation for the compiler libraries and their
/// dependencies. This is largely just a wrapper around `cargo doc`.
pub fn rustc(build: &Build, stage: u32, target: &str, out: &Path) {
pub fn rustc(build: &Build, stage: u32, target: &str) {
println!("Documenting stage{} compiler ({})", stage, target);
t!(fs::create_dir_all(out));
let out = build.doc_out(target);
t!(fs::create_dir_all(&out));
let compiler = Compiler::new(stage, &build.config.build);
let out_dir = build.stage_out(&compiler, Mode::Librustc)
.join(target).join("doc");
@ -189,14 +193,15 @@ pub fn rustc(build: &Build, stage: u32, target: &str, out: &Path) {
.arg(build.src.join("src/rustc/Cargo.toml"))
.arg("--features").arg(build.rustc_features());
build.run(&mut cargo);
cp_r(&out_dir, out)
cp_r(&out_dir, &out)
}
/// Generates the HTML rendered error-index by running the
/// `error_index_generator` tool.
pub fn error_index(build: &Build, stage: u32, target: &str, out: &Path) {
pub fn error_index(build: &Build, stage: u32, target: &str) {
println!("Documenting stage{} error index ({})", stage, target);
t!(fs::create_dir_all(out));
let out = build.doc_out(target);
t!(fs::create_dir_all(&out));
let compiler = Compiler::new(stage, &build.config.build);
let mut index = build.tool_cmd(&compiler, "error_index_generator");
index.arg("html");

View File

@ -13,30 +13,46 @@
//! This module implements the command-line parsing of the build system which
//! has various flags to configure how it's run.
use std::env;
use std::fs;
use std::path::PathBuf;
use std::process;
use std::slice;
use getopts::Options;
use getopts::{Matches, Options};
use Build;
use config::Config;
use metadata;
use step;
/// Deserialized version of all flags for this compile.
pub struct Flags {
pub verbose: bool,
pub stage: Option<u32>,
pub build: String,
pub host: Filter,
pub target: Filter,
pub step: Vec<String>,
pub host: Vec<String>,
pub target: Vec<String>,
pub config: Option<PathBuf>,
pub src: Option<PathBuf>,
pub jobs: Option<u32>,
pub args: Vec<String>,
pub clean: bool,
pub cmd: Subcommand,
}
pub struct Filter {
values: Vec<String>,
pub enum Subcommand {
Build {
paths: Vec<PathBuf>,
},
Doc {
paths: Vec<PathBuf>,
},
Test {
paths: Vec<PathBuf>,
test_args: Vec<String>,
},
Clean,
Dist {
install: bool,
},
}
impl Flags {
@ -44,29 +60,177 @@ impl Flags {
let mut opts = Options::new();
opts.optflag("v", "verbose", "use verbose output");
opts.optopt("", "config", "TOML configuration file for build", "FILE");
opts.optopt("", "build", "build target of the stage0 compiler", "BUILD");
opts.optmulti("", "host", "host targets to build", "HOST");
opts.reqopt("", "build", "build target of the stage0 compiler", "BUILD");
opts.optmulti("", "target", "targets to build", "TARGET");
opts.optmulti("s", "step", "build step to execute", "STEP");
opts.optmulti("", "target", "target targets to build", "TARGET");
opts.optopt("", "stage", "stage to build", "N");
opts.optopt("", "src", "path to repo root", "DIR");
opts.optopt("", "src", "path to the root of the rust checkout", "DIR");
opts.optopt("j", "jobs", "number of jobs to run in parallel", "JOBS");
opts.optflag("", "clean", "clean output directory");
opts.optflag("h", "help", "print this help message");
let usage = |n| -> ! {
let brief = format!("Usage: rust.py [options]");
print!("{}", opts.usage(&brief));
let usage = |n, opts: &Options| -> ! {
let command = args.get(0).map(|s| &**s);
let brief = format!("Usage: x.py {} [options] [<args>...]",
command.unwrap_or("<command>"));
println!("{}", opts.usage(&brief));
match command {
Some("build") => {
println!("\
Arguments:
This subcommand accepts a number of positional arguments of directories to
the crates and/or artifacts to compile. For example:
./x.py build src/libcore
./x.py build src/libproc_macro
./x.py build src/libstd --stage 1
If no arguments are passed then the complete artifacts for that stage are
also compiled.
./x.py build
./x.py build --stage 1
For a quick build with a usable compile, you can pass:
./x.py build --stage 1 src/libtest
");
}
Some("test") => {
println!("\
Arguments:
This subcommand accepts a number of positional arguments of directories to
tests that should be compiled and run. For example:
./x.py test src/test/run-pass
./x.py test src/test/run-pass/assert-*
./x.py test src/libstd --test-args hash_map
./x.py test src/libstd --stage 0
If no arguments are passed then the complete artifacts for that stage are
compiled and tested.
./x.py test
./x.py test --stage 1
");
}
Some("doc") => {
println!("\
Arguments:
This subcommand accepts a number of positional arguments of directories of
documentation to build. For example:
./x.py doc src/doc/book
./x.py doc src/doc/nomicon
./x.py doc src/libstd
If no arguments are passed then everything is documented:
./x.py doc
./x.py doc --stage 1
");
}
_ => {}
}
if let Some(command) = command {
if command == "build" ||
command == "dist" ||
command == "doc" ||
command == "test" ||
command == "clean" {
println!("Available invocations:");
if args.iter().any(|a| a == "-v") {
let flags = Flags::parse(&["build".to_string()]);
let mut config = Config::default();
config.build = flags.build.clone();
let mut build = Build::new(flags, config);
metadata::build(&mut build);
step::build_rules(&build).print_help(command);
} else {
println!(" ... elided, run `./x.py {} -h -v` to see",
command);
}
println!("");
}
}
println!("\
Subcommands:
build Compile either the compiler or libraries
test Build and run some test suites
doc Build documentation
clean Clean out build directories
dist Build and/or install distribution artifacts
To learn more about a subcommand, run `./x.py <command> -h`
");
process::exit(n);
};
let m = opts.parse(args).unwrap_or_else(|e| {
println!("failed to parse options: {}", e);
usage(1);
});
if m.opt_present("h") {
usage(0);
if args.len() == 0 {
println!("a command must be passed");
usage(1, &opts);
}
let parse = |opts: &Options| {
let m = opts.parse(&args[1..]).unwrap_or_else(|e| {
println!("failed to parse options: {}", e);
usage(1, opts);
});
if m.opt_present("h") {
usage(0, opts);
}
return m
};
let cwd = t!(env::current_dir());
let remaining_as_path = |m: &Matches| {
m.free.iter().map(|p| cwd.join(p)).collect::<Vec<_>>()
};
let m: Matches;
let cmd = match &args[0][..] {
"build" => {
m = parse(&opts);
Subcommand::Build { paths: remaining_as_path(&m) }
}
"doc" => {
m = parse(&opts);
Subcommand::Doc { paths: remaining_as_path(&m) }
}
"test" => {
opts.optmulti("", "test-args", "extra arguments", "ARGS");
m = parse(&opts);
Subcommand::Test {
paths: remaining_as_path(&m),
test_args: m.opt_strs("test-args"),
}
}
"clean" => {
m = parse(&opts);
if m.free.len() > 0 {
println!("clean takes no arguments");
usage(1, &opts);
}
Subcommand::Clean
}
"dist" => {
opts.optflag("", "install", "run installer as well");
m = parse(&opts);
Subcommand::Dist {
install: m.opt_present("install"),
}
}
cmd => {
println!("unknown command: {}", cmd);
usage(1, &opts);
}
};
let cfg_file = m.opt_str("config").map(PathBuf::from).or_else(|| {
if fs::metadata("config.toml").is_ok() {
@ -78,26 +242,27 @@ impl Flags {
Flags {
verbose: m.opt_present("v"),
clean: m.opt_present("clean"),
stage: m.opt_str("stage").map(|j| j.parse().unwrap()),
build: m.opt_str("build").unwrap(),
host: Filter { values: m.opt_strs("host") },
target: Filter { values: m.opt_strs("target") },
step: m.opt_strs("step"),
build: m.opt_str("build").unwrap_or_else(|| {
env::var("BUILD").unwrap()
}),
host: m.opt_strs("host"),
target: m.opt_strs("target"),
config: cfg_file,
src: m.opt_str("src").map(PathBuf::from),
jobs: m.opt_str("jobs").map(|j| j.parse().unwrap()),
args: m.free.clone(),
cmd: cmd,
}
}
}
impl Filter {
pub fn contains(&self, name: &str) -> bool {
self.values.len() == 0 || self.values.iter().any(|s| s == name)
}
pub fn iter(&self) -> slice::Iter<String> {
self.values.iter()
impl Subcommand {
pub fn test_args(&self) -> Vec<&str> {
match *self {
Subcommand::Test { ref test_args, .. } => {
test_args.iter().flat_map(|s| s.split_whitespace()).collect()
}
_ => Vec::new(),
}
}
}

61
src/bootstrap/install.rs Normal file
View File

@ -0,0 +1,61 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Implementation of the install aspects of the compiler.
//!
//! This module is responsible for installing the standard library,
//! compiler, and documentation.
use std::fs;
use std::borrow::Cow;
use std::path::Path;
use std::process::Command;
use Build;
use dist::{package_vers, sanitize_sh, tmpdir};
/// Installs everything.
pub fn install(build: &Build, stage: u32, host: &str) {
let prefix = build.config.prefix.as_ref().clone().map(|x| Path::new(x))
.unwrap_or(Path::new("/usr/local"));
let docdir = build.config.docdir.as_ref().clone().map(|x| Cow::Borrowed(Path::new(x)))
.unwrap_or(Cow::Owned(prefix.join("share/doc/rust")));
let libdir = build.config.libdir.as_ref().clone().map(|x| Cow::Borrowed(Path::new(x)))
.unwrap_or(Cow::Owned(prefix.join("lib")));
let mandir = build.config.mandir.as_ref().clone().map(|x| Cow::Borrowed(Path::new(x)))
.unwrap_or(Cow::Owned(prefix.join("share/man")));
let empty_dir = build.out.join("tmp/empty_dir");
t!(fs::create_dir_all(&empty_dir));
if build.config.docs {
install_sh(&build, "docs", "rust-docs", stage, host, prefix,
&docdir, &libdir, &mandir, &empty_dir);
}
install_sh(&build, "std", "rust-std", stage, host, prefix,
&docdir, &libdir, &mandir, &empty_dir);
install_sh(&build, "rustc", "rustc", stage, host, prefix,
&docdir, &libdir, &mandir, &empty_dir);
t!(fs::remove_dir_all(&empty_dir));
}
fn install_sh(build: &Build, package: &str, name: &str, stage: u32, host: &str,
prefix: &Path, docdir: &Path, libdir: &Path, mandir: &Path, empty_dir: &Path) {
println!("Install {} stage{} ({})", package, stage, host);
let package_name = format!("{}-{}-{}", name, package_vers(build), host);
let mut cmd = Command::new("sh");
cmd.current_dir(empty_dir)
.arg(sanitize_sh(&tmpdir(build).join(&package_name).join("install.sh")))
.arg(format!("--prefix={}", sanitize_sh(prefix)))
.arg(format!("--docdir={}", sanitize_sh(docdir)))
.arg(format!("--libdir={}", sanitize_sh(libdir)))
.arg(format!("--mandir={}", sanitize_sh(mandir)))
.arg("--disable-ldconfig");
build.run(&mut cmd);
}

View File

@ -26,7 +26,6 @@ extern crate md5;
extern crate num_cpus;
extern crate rustc_serialize;
extern crate toml;
extern crate regex;
use std::collections::HashMap;
use std::env;
@ -58,10 +57,12 @@ mod channel;
mod check;
mod clean;
mod compile;
mod metadata;
mod config;
mod dist;
mod doc;
mod flags;
mod install;
mod native;
mod sanity;
mod step;
@ -76,7 +77,7 @@ mod job {
}
pub use config::Config;
pub use flags::Flags;
pub use flags::{Flags, Subcommand};
/// A structure representing a Rust compiler.
///
@ -123,13 +124,23 @@ pub struct Build {
bootstrap_key_stage0: String,
// Probed tools at runtime
gdb_version: Option<String>,
lldb_version: Option<String>,
lldb_python_dir: Option<String>,
// Runtime state filled in later on
cc: HashMap<String, (gcc::Tool, Option<PathBuf>)>,
cxx: HashMap<String, gcc::Tool>,
crates: HashMap<String, Crate>,
}
#[derive(Debug)]
struct Crate {
name: String,
deps: Vec<String>,
path: PathBuf,
doc_step: String,
build_step: String,
test_step: String,
}
/// The various "modes" of invoking Cargo.
@ -162,7 +173,9 @@ impl Build {
/// By default all build output will be placed in the current directory.
pub fn new(flags: Flags, config: Config) -> Build {
let cwd = t!(env::current_dir());
let src = flags.src.clone().unwrap_or(cwd.clone());
let src = flags.src.clone().or_else(|| {
env::var_os("SRC").map(|x| x.into())
}).unwrap_or(cwd.clone());
let out = cwd.join("build");
let stage0_root = out.join(&config.build).join("stage0/bin");
@ -196,7 +209,7 @@ impl Build {
package_vers: String::new(),
cc: HashMap::new(),
cxx: HashMap::new(),
gdb_version: None,
crates: HashMap::new(),
lldb_version: None,
lldb_python_dir: None,
}
@ -204,13 +217,11 @@ impl Build {
/// Executes the entire build, as configured by the flags and configuration.
pub fn build(&mut self) {
use step::Source::*;
unsafe {
job::setup();
}
if self.flags.clean {
if let Subcommand::Clean = self.flags.cmd {
return clean::clean(self);
}
@ -220,257 +231,22 @@ impl Build {
sanity::check(self);
self.verbose("collecting channel variables");
channel::collect(self);
// If local-rust is the same as the current version, then force a local-rebuild
// If local-rust is the same major.minor as the current version, then force a local-rebuild
let local_version_verbose = output(
Command::new(&self.rustc).arg("--version").arg("--verbose"));
let local_release = local_version_verbose
.lines().filter(|x| x.starts_with("release:"))
.next().unwrap().trim_left_matches("release:").trim();
if local_release == self.release {
self.verbose(&format!("auto-detected local-rebuild {}", self.release));
if local_release.split('.').take(2).eq(self.release.split('.').take(2)) {
self.verbose(&format!("auto-detected local-rebuild {}", local_release));
self.local_rebuild = true;
}
self.verbose("updating submodules");
self.update_submodules();
self.verbose("learning about cargo");
metadata::build(self);
// The main loop of the build system.
//
// The `step::all` function returns a topographically sorted list of all
// steps that need to be executed as part of this build. Each step has a
// corresponding entry in `step.rs` and indicates some unit of work that
// needs to be done as part of the build.
//
// Almost all of these are simple one-liners that shell out to the
// corresponding functionality in the extra modules, where more
// documentation can be found.
let steps = step::all(self);
self.verbose("bootstrap build plan:");
for step in &steps {
self.verbose(&format!("{:?}", step));
}
for target in steps {
let doc_out = self.out.join(&target.target).join("doc");
match target.src {
Llvm { _dummy } => {
native::llvm(self, target.target);
}
TestHelpers { _dummy } => {
native::test_helpers(self, target.target);
}
Libstd { compiler } => {
compile::std(self, target.target, &compiler);
}
Libtest { compiler } => {
compile::test(self, target.target, &compiler);
}
Librustc { compiler } => {
compile::rustc(self, target.target, &compiler);
}
LibstdLink { compiler, host } => {
compile::std_link(self, target.target, &compiler, host);
}
LibtestLink { compiler, host } => {
compile::test_link(self, target.target, &compiler, host);
}
LibrustcLink { compiler, host } => {
compile::rustc_link(self, target.target, &compiler, host);
}
Rustc { stage: 0 } => {
// nothing to do...
}
Rustc { stage } => {
compile::assemble_rustc(self, stage, target.target);
}
ToolLinkchecker { stage } => {
compile::tool(self, stage, target.target, "linkchecker");
}
ToolRustbook { stage } => {
compile::tool(self, stage, target.target, "rustbook");
}
ToolErrorIndex { stage } => {
compile::tool(self, stage, target.target,
"error_index_generator");
}
ToolCargoTest { stage } => {
compile::tool(self, stage, target.target, "cargotest");
}
ToolTidy { stage } => {
compile::tool(self, stage, target.target, "tidy");
}
ToolCompiletest { stage } => {
compile::tool(self, stage, target.target, "compiletest");
}
DocBook { stage } => {
doc::rustbook(self, stage, target.target, "book", &doc_out);
}
DocNomicon { stage } => {
doc::rustbook(self, stage, target.target, "nomicon",
&doc_out);
}
DocStandalone { stage } => {
doc::standalone(self, stage, target.target, &doc_out);
}
DocStd { stage } => {
doc::std(self, stage, target.target, &doc_out);
}
DocTest { stage } => {
doc::test(self, stage, target.target, &doc_out);
}
DocRustc { stage } => {
doc::rustc(self, stage, target.target, &doc_out);
}
DocErrorIndex { stage } => {
doc::error_index(self, stage, target.target, &doc_out);
}
CheckLinkcheck { stage } => {
check::linkcheck(self, stage, target.target);
}
CheckCargoTest { stage } => {
check::cargotest(self, stage, target.target);
}
CheckTidy { stage } => {
check::tidy(self, stage, target.target);
}
CheckRPass { compiler } => {
check::compiletest(self, &compiler, target.target,
"run-pass", "run-pass");
}
CheckRPassFull { compiler } => {
check::compiletest(self, &compiler, target.target,
"run-pass", "run-pass-fulldeps");
}
CheckCFail { compiler } => {
check::compiletest(self, &compiler, target.target,
"compile-fail", "compile-fail");
}
CheckCFailFull { compiler } => {
check::compiletest(self, &compiler, target.target,
"compile-fail", "compile-fail-fulldeps")
}
CheckPFail { compiler } => {
check::compiletest(self, &compiler, target.target,
"parse-fail", "parse-fail");
}
CheckRFail { compiler } => {
check::compiletest(self, &compiler, target.target,
"run-fail", "run-fail");
}
CheckRFailFull { compiler } => {
check::compiletest(self, &compiler, target.target,
"run-fail", "run-fail-fulldeps");
}
CheckPretty { compiler } => {
check::compiletest(self, &compiler, target.target,
"pretty", "pretty");
}
CheckPrettyRPass { compiler } => {
check::compiletest(self, &compiler, target.target,
"pretty", "run-pass");
}
CheckPrettyRPassFull { compiler } => {
check::compiletest(self, &compiler, target.target,
"pretty", "run-pass-fulldeps");
}
CheckPrettyRFail { compiler } => {
check::compiletest(self, &compiler, target.target,
"pretty", "run-fail");
}
CheckPrettyRFailFull { compiler } => {
check::compiletest(self, &compiler, target.target,
"pretty", "run-fail-fulldeps");
}
CheckPrettyRPassValgrind { compiler } => {
check::compiletest(self, &compiler, target.target,
"pretty", "run-pass-valgrind");
}
CheckMirOpt { compiler } => {
check::compiletest(self, &compiler, target.target,
"mir-opt", "mir-opt");
}
CheckCodegen { compiler } => {
if self.config.codegen_tests {
check::compiletest(self, &compiler, target.target,
"codegen", "codegen");
}
}
CheckCodegenUnits { compiler } => {
check::compiletest(self, &compiler, target.target,
"codegen-units", "codegen-units");
}
CheckIncremental { compiler } => {
check::compiletest(self, &compiler, target.target,
"incremental", "incremental");
}
CheckUi { compiler } => {
check::compiletest(self, &compiler, target.target,
"ui", "ui");
}
CheckDebuginfo { compiler } => {
if target.target.contains("msvc") {
// nothing to do
} else if target.target.contains("apple") {
check::compiletest(self, &compiler, target.target,
"debuginfo-lldb", "debuginfo");
} else {
check::compiletest(self, &compiler, target.target,
"debuginfo-gdb", "debuginfo");
}
}
CheckRustdoc { compiler } => {
check::compiletest(self, &compiler, target.target,
"rustdoc", "rustdoc");
}
CheckRPassValgrind { compiler } => {
check::compiletest(self, &compiler, target.target,
"run-pass-valgrind", "run-pass-valgrind");
}
CheckDocs { compiler } => {
check::docs(self, &compiler);
}
CheckErrorIndex { compiler } => {
check::error_index(self, &compiler);
}
CheckRMake { compiler } => {
check::compiletest(self, &compiler, target.target,
"run-make", "run-make")
}
CheckCrateStd { compiler } => {
check::krate(self, &compiler, target.target, Mode::Libstd)
}
CheckCrateTest { compiler } => {
check::krate(self, &compiler, target.target, Mode::Libtest)
}
CheckCrateRustc { compiler } => {
check::krate(self, &compiler, target.target, Mode::Librustc)
}
DistDocs { stage } => dist::docs(self, stage, target.target),
DistMingw { _dummy } => dist::mingw(self, target.target),
DistRustc { stage } => dist::rustc(self, stage, target.target),
DistStd { compiler } => dist::std(self, &compiler, target.target),
DistSrc { _dummy } => dist::rust_src(self),
DebuggerScripts { stage } => {
let compiler = Compiler::new(stage, target.target);
dist::debugger_scripts(self,
&self.sysroot(&compiler),
target.target);
}
AndroidCopyLibs { compiler } => {
check::android_copy_libs(self, &compiler, target.target);
}
// pseudo-steps
Dist { .. } |
Doc { .. } |
CheckTarget { .. } |
Check { .. } => {}
}
}
step::run(self);
}
/// Updates all git submodules that we have.
@ -557,12 +333,23 @@ impl Build {
continue
}
// `submodule.path` is the relative path to a submodule (from the repository root)
// `submodule_path` is the path to a submodule from the cwd
// use `submodule.path` when e.g. executing a submodule specific command from the
// repository root
// use `submodule_path` when e.g. executing a normal git command for the submodule
// (set via `current_dir`)
let submodule_path = self.src.join(submodule.path);
match submodule.state {
State::MaybeDirty => {
// drop staged changes
self.run(git().arg("-C").arg(submodule.path).args(&["reset", "--hard"]));
self.run(git().current_dir(&submodule_path)
.args(&["reset", "--hard"]));
// drops unstaged changes
self.run(git().arg("-C").arg(submodule.path).args(&["clean", "-fdx"]));
self.run(git().current_dir(&submodule_path)
.args(&["clean", "-fdx"]));
},
State::NotInitialized => {
self.run(git_submodule().arg("init").arg(submodule.path));
@ -571,8 +358,10 @@ impl Build {
State::OutOfSync => {
// drops submodule commits that weren't reported to the (outer) git repository
self.run(git_submodule().arg("update").arg(submodule.path));
self.run(git().arg("-C").arg(submodule.path).args(&["reset", "--hard"]));
self.run(git().arg("-C").arg(submodule.path).args(&["clean", "-fdx"]));
self.run(git().current_dir(&submodule_path)
.args(&["reset", "--hard"]));
self.run(git().current_dir(&submodule_path)
.args(&["clean", "-fdx"]));
},
}
}
@ -634,6 +423,7 @@ impl Build {
.env("RUSTC_REAL", self.compiler_path(compiler))
.env("RUSTC_STAGE", stage.to_string())
.env("RUSTC_DEBUGINFO", self.config.rust_debuginfo.to_string())
.env("RUSTC_DEBUGINFO_LINES", self.config.rust_debuginfo_lines.to_string())
.env("RUSTC_CODEGEN_UNITS",
self.config.rust_codegen_units.to_string())
.env("RUSTC_DEBUG_ASSERTIONS",
@ -659,12 +449,6 @@ impl Build {
.env(format!("CFLAGS_{}", target), self.cflags(target).join(" "));
}
// If we're building for OSX, inform the compiler and the linker that
// we want to build a compiler runnable on 10.7
if target.contains("apple-darwin") {
cargo.env("MACOSX_DEPLOYMENT_TARGET", "10.7");
}
// Environment variables *required* needed throughout the build
//
// FIXME: should update code to not require this env var
@ -802,6 +586,11 @@ impl Build {
self.out.join(target).join("llvm")
}
/// Output directory for all documentation for a target
fn doc_out(&self, target: &str) -> PathBuf {
self.out.join(target).join("doc")
}
/// Returns true if no custom `llvm-config` is set for the specified target.
///
/// If no custom `llvm-config` was specified then Rust's llvm will be used.
@ -866,7 +655,7 @@ impl Build {
cmd.env("RUSTC_BOOTSTRAP", "1");
// FIXME: Transitionary measure to bootstrap using the old bootstrap logic.
// Remove this once the bootstrap compiler uses the new login in Issue #36548.
cmd.env("RUSTC_BOOTSTRAP_KEY", "5c6cf767");
cmd.env("RUSTC_BOOTSTRAP_KEY", "62b3e239");
}
/// Returns the compiler's libdir where it stores the dynamic libraries that
@ -928,7 +717,6 @@ impl Build {
// LLVM/jemalloc/etc are all properly compiled.
if target.contains("apple-darwin") {
base.push("-stdlib=libc++".into());
base.push("-mmacosx-version-min=10.7".into());
}
// This is a hack, because newer binutils broke things on some vms/distros
// (i.e., linking against unknown relocs disabled by the following flag)
@ -969,7 +757,8 @@ impl Build {
// than an entry here.
let mut base = Vec::new();
if target != self.config.build && !target.contains("msvc") {
if target != self.config.build && !target.contains("msvc") &&
!target.contains("emscripten") {
base.push(format!("-Clinker={}", self.cc(target).display()));
}
return base
@ -977,7 +766,8 @@ impl Build {
/// Returns the "musl root" for this `target`, if defined
fn musl_root(&self, target: &str) -> Option<&Path> {
self.config.target_config[target].musl_root.as_ref()
self.config.target_config.get(target)
.and_then(|t| t.musl_root.as_ref())
.or(self.config.musl_root.as_ref())
.map(|p| &**p)
}

95
src/bootstrap/metadata.rs Normal file
View File

@ -0,0 +1,95 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::collections::HashMap;
use std::process::Command;
use std::path::PathBuf;
use build_helper::output;
use rustc_serialize::json;
use {Build, Crate};
#[derive(RustcDecodable)]
struct Output {
packages: Vec<Package>,
resolve: Resolve,
}
#[derive(RustcDecodable)]
struct Package {
id: String,
name: String,
source: Option<String>,
manifest_path: String,
}
#[derive(RustcDecodable)]
struct Resolve {
nodes: Vec<ResolveNode>,
}
#[derive(RustcDecodable)]
struct ResolveNode {
id: String,
dependencies: Vec<String>,
}
pub fn build(build: &mut Build) {
build_krate(build, "src/rustc/std_shim");
build_krate(build, "src/rustc/test_shim");
build_krate(build, "src/rustc");
}
fn build_krate(build: &mut Build, krate: &str) {
// Run `cargo metadata` to figure out what crates we're testing.
//
// Down below we're going to call `cargo test`, but to test the right set
// of packages we're going to have to know what `-p` arguments to pass it
// to know what crates to test. Here we run `cargo metadata` to learn about
// the dependency graph and what `-p` arguments there are.
let mut cargo = Command::new(&build.cargo);
cargo.arg("metadata")
.arg("--manifest-path").arg(build.src.join(krate).join("Cargo.toml"));
let output = output(&mut cargo);
let output: Output = json::decode(&output).unwrap();
let mut id2name = HashMap::new();
for package in output.packages {
if package.source.is_none() {
id2name.insert(package.id, package.name.clone());
let mut path = PathBuf::from(package.manifest_path);
path.pop();
build.crates.insert(package.name.clone(), Crate {
build_step: format!("build-crate-{}", package.name),
doc_step: format!("doc-crate-{}", package.name),
test_step: format!("test-crate-{}", package.name),
name: package.name,
deps: Vec::new(),
path: path,
});
}
}
for node in output.resolve.nodes {
let name = match id2name.get(&node.id) {
Some(name) => name,
None => continue,
};
let krate = build.crates.get_mut(name).unwrap();
for dep in node.dependencies.iter() {
let dep = match id2name.get(dep) {
Some(dep) => dep,
None => continue,
};
krate.deps.push(dep.clone());
}
}
}

View File

@ -17,41 +17,46 @@ else
BOOTSTRAP_ARGS :=
endif
BOOTSTRAP := $(CFG_PYTHON) $(CFG_SRC_DIR)src/bootstrap/bootstrap.py $(BOOTSTRAP_ARGS)
BOOTSTRAP := $(CFG_PYTHON) $(CFG_SRC_DIR)src/bootstrap/bootstrap.py
all:
$(Q)$(BOOTSTRAP)
$(Q)$(BOOTSTRAP) build $(BOOTSTRAP_ARGS)
$(Q)$(BOOTSTRAP) doc $(BOOTSTRAP_ARGS)
# Dont use $(Q) here, always show how to invoke the bootstrap script directly
help:
$(BOOTSTRAP) --help
clean:
$(Q)$(BOOTSTRAP) --clean
$(Q)$(BOOTSTRAP) clean $(BOOTSTRAP_ARGS)
rustc-stage1:
$(Q)$(BOOTSTRAP) --step libtest --stage 1
$(Q)$(BOOTSTRAP) build --stage 1 src/libtest $(BOOTSTRAP_ARGS)
rustc-stage2:
$(Q)$(BOOTSTRAP) --step libtest --stage 2
$(Q)$(BOOTSTRAP) build --stage 2 src/libtest $(BOOTSTRAP_ARGS)
docs: doc
doc:
$(Q)$(BOOTSTRAP) --step doc
style:
$(Q)$(BOOTSTRAP) --step doc-style
$(Q)$(BOOTSTRAP) doc $(BOOTSTRAP_ARGS)
nomicon:
$(Q)$(BOOTSTRAP) --step doc-nomicon
$(Q)$(BOOTSTRAP) doc src/doc/nomicon $(BOOTSTRAP_ARGS)
book:
$(Q)$(BOOTSTRAP) --step doc-book
$(Q)$(BOOTSTRAP) doc src/doc/book $(BOOTSTRAP_ARGS)
standalone-docs:
$(Q)$(BOOTSTRAP) --step doc-standalone
$(Q)$(BOOTSTRAP) doc src/doc $(BOOTSTRAP_ARGS)
check:
$(Q)$(BOOTSTRAP) --step check
$(Q)$(BOOTSTRAP) test $(BOOTSTRAP_ARGS)
check-cargotest:
$(Q)$(BOOTSTRAP) --step check-cargotest
$(Q)$(BOOTSTRAP) test src/tools/cargotest $(BOOTSTRAP_ARGS)
dist:
$(Q)$(BOOTSTRAP) --step dist
$(Q)$(BOOTSTRAP) dist $(BOOTSTRAP_ARGS)
install:
ifeq (root user, $(USER) $(patsubst %,user,$(SUDO_USER)))
$(Q)echo "'sudo make install' is not supported currently."
else
$(Q)$(BOOTSTRAP) dist --install $(BOOTSTRAP_ARGS)
endif
tidy:
$(Q)$(BOOTSTRAP) --step check-tidy --stage 0
$(Q)$(BOOTSTRAP) test src/tools/tidy $(BOOTSTRAP_ARGS)
.PHONY: dist

View File

@ -18,9 +18,10 @@
//! LLVM and compiler-rt are essentially just wired up to everything else to
//! ensure that they're always in place if needed.
use std::fs::{self, File};
use std::io::{Read, Write};
use std::path::Path;
use std::process::Command;
use std::fs::{self, File};
use build_helper::output;
use cmake;
@ -43,11 +44,17 @@ pub fn llvm(build: &Build, target: &str) {
// artifacts are missing) then we keep going, otherwise we bail out.
let dst = build.llvm_out(target);
let stamp = build.src.join("src/rustllvm/llvm-auto-clean-trigger");
let mut stamp_contents = String::new();
t!(t!(File::open(&stamp)).read_to_string(&mut stamp_contents));
let done_stamp = dst.join("llvm-finished-building");
build.clear_if_dirty(&dst, &stamp);
if fs::metadata(&done_stamp).is_ok() {
return
if done_stamp.exists() {
let mut done_contents = String::new();
t!(t!(File::open(&done_stamp)).read_to_string(&mut done_contents));
if done_contents == stamp_contents {
return
}
}
drop(fs::remove_dir_all(&dst));
println!("Building LLVM for {}", target);
@ -65,7 +72,7 @@ pub fn llvm(build: &Build, target: &str) {
.out_dir(&dst)
.profile(if build.config.llvm_optimize {"Release"} else {"Debug"})
.define("LLVM_ENABLE_ASSERTIONS", assertions)
.define("LLVM_TARGETS_TO_BUILD", "X86;ARM;AArch64;Mips;PowerPC;SystemZ")
.define("LLVM_TARGETS_TO_BUILD", "X86;ARM;AArch64;Mips;PowerPC;SystemZ;JSBackend")
.define("LLVM_INCLUDE_EXAMPLES", "OFF")
.define("LLVM_INCLUDE_TESTS", "OFF")
.define("LLVM_INCLUDE_DOCS", "OFF")
@ -73,7 +80,9 @@ pub fn llvm(build: &Build, target: &str) {
.define("WITH_POLLY", "OFF")
.define("LLVM_ENABLE_TERMINFO", "OFF")
.define("LLVM_ENABLE_LIBEDIT", "OFF")
.define("LLVM_PARALLEL_COMPILE_JOBS", build.jobs().to_string());
.define("LLVM_PARALLEL_COMPILE_JOBS", build.jobs().to_string())
.define("LLVM_TARGET_ARCH", target.split('-').next().unwrap())
.define("LLVM_DEFAULT_TARGET_TRIPLE", target);
if target.starts_with("i686") {
cfg.define("LLVM_BUILD_32_BITS", "ON");
@ -86,9 +95,7 @@ pub fn llvm(build: &Build, target: &str) {
// actually exists most of the time in normal installs of LLVM.
let host = build.llvm_out(&build.config.build).join("bin/llvm-tblgen");
cfg.define("CMAKE_CROSSCOMPILING", "True")
.define("LLVM_TARGET_ARCH", target.split('-').next().unwrap())
.define("LLVM_TABLEGEN", &host)
.define("LLVM_DEFAULT_TARGET_TRIPLE", target);
.define("LLVM_TABLEGEN", &host);
}
// MSVC handles compiler business itself
@ -114,7 +121,7 @@ pub fn llvm(build: &Build, target: &str) {
// tools and libs on all platforms.
cfg.build();
t!(File::create(&done_stamp));
t!(t!(File::create(&done_stamp)).write_all(stamp_contents.as_bytes()));
}
fn check_llvm_version(build: &Build, llvm_config: &Path) {

View File

@ -40,17 +40,23 @@ pub fn check(build: &mut Build) {
panic!("PATH contains invalid character '\"'");
}
}
let have_cmd = |cmd: &OsStr| {
for path in env::split_paths(&path).map(|p| p.join(cmd)) {
if fs::metadata(&path).is_ok() ||
fs::metadata(path.with_extension("exe")).is_ok() {
return Some(path);
}
}
return None;
};
let mut need_cmd = |cmd: &OsStr| {
if !checked.insert(cmd.to_owned()) {
return
}
for path in env::split_paths(&path).map(|p| p.join(cmd)) {
if fs::metadata(&path).is_ok() ||
fs::metadata(path.with_extension("exe")).is_ok() {
return
}
if have_cmd(cmd).is_none() {
panic!("\n\ncouldn't find required command: {:?}\n\n", cmd);
}
panic!("\n\ncouldn't find required command: {:?}\n\n", cmd);
};
// If we've got a git directory we're gona need git to update
@ -75,15 +81,33 @@ pub fn check(build: &mut Build) {
need_cmd("python".as_ref());
// If a manual nodejs was added to the config,
// of if a nodejs install is detected through config, use it.
// Look for the nodejs command, needed for emscripten testing
if let Some(node) = have_cmd("node".as_ref()) {
build.config.nodejs = Some(node);
} else if let Some(node) = have_cmd("nodejs".as_ref()) {
build.config.nodejs = Some(node);
}
if let Some(ref s) = build.config.nodejs {
need_cmd(s.as_ref());
}
if let Some(ref gdb) = build.config.gdb {
need_cmd(gdb.as_ref());
} else {
build.config.gdb = have_cmd("gdb".as_ref());
}
// We're gonna build some custom C code here and there, host triples
// also build some C++ shims for LLVM so we need a C++ compiler.
for target in build.config.target.iter() {
// On emscripten we don't actually need the C compiler to just
// build the target artifacts, only for testing. For the sake
// of easier bot configuration, just skip detection.
if target.contains("emscripten") {
continue;
}
need_cmd(build.cc(target).as_ref());
if let Some(ar) = build.ar(target) {
need_cmd(ar.as_ref());
@ -93,6 +117,14 @@ pub fn check(build: &mut Build) {
need_cmd(build.cxx(host).as_ref());
}
// The msvc hosts don't use jemalloc, turn it off globally to
// avoid packaging the dummy liballoc_jemalloc on that platform.
for host in build.config.host.iter() {
if host.contains("msvc") {
build.config.use_jemalloc = false;
}
}
// Externally configured LLVM requires FileCheck to exist
let filecheck = build.llvm_filecheck(&build.config.build);
if !filecheck.starts_with(&build.out) && !filecheck.exists() && build.config.codegen_tests {
@ -100,15 +132,6 @@ pub fn check(build: &mut Build) {
}
for target in build.config.target.iter() {
// Either can't build or don't want to run jemalloc on these targets
if target.contains("rumprun") ||
target.contains("bitrig") ||
target.contains("openbsd") ||
target.contains("msvc") ||
target.contains("emscripten") {
build.config.use_jemalloc = false;
}
// Can't compile for iOS unless we're on OSX
if target.contains("apple-ios") &&
!build.config.build.contains("apple-darwin") {
@ -129,8 +152,8 @@ pub fn check(build: &mut Build) {
}
}
None => {
panic!("when targeting MUSL either the build.musl-root \
option or the target.$TARGET.musl-root one must \
panic!("when targeting MUSL either the rust.musl-root \
option or the target.$TARGET.musl-root option must \
be specified in config.toml")
}
}
@ -181,7 +204,6 @@ $ pacman -R cmake && pacman -S mingw-w64-x86_64-cmake
.to_string()
})
};
build.gdb_version = run(Command::new("gdb").arg("--version")).ok();
build.lldb_version = run(Command::new("lldb").arg("--version")).ok();
if build.lldb_version.is_some() {
build.lldb_python_dir = run(Command::new("lldb").arg("-P")).ok();

File diff suppressed because it is too large Load Diff

View File

@ -57,8 +57,7 @@ pub fn cp_r(src: &Path, dst: &Path) {
let name = path.file_name().unwrap();
let dst = dst.join(name);
if t!(f.file_type()).is_dir() {
let _ = fs::remove_dir_all(&dst);
t!(fs::create_dir(&dst));
t!(fs::create_dir_all(&dst));
cp_r(&path, &dst);
} else {
let _ = fs::remove_file(&dst);
@ -172,3 +171,21 @@ pub fn dylib_path() -> Vec<PathBuf> {
env::split_paths(&env::var_os(dylib_path_var()).unwrap_or(OsString::new()))
.collect()
}
/// `push` all components to `buf`. On windows, append `.exe` to the last component.
pub fn push_exe_path(mut buf: PathBuf, components: &[&str]) -> PathBuf {
let (&file, components) = components.split_last().expect("at least one component required");
let mut file = file.to_owned();
if cfg!(windows) {
file.push_str(".exe");
}
for c in components {
buf.push(c);
}
buf.push(file);
buf
}

View File

@ -25,7 +25,9 @@ pub fn run_silent(cmd: &mut Command) {
};
if !status.success() {
fail(&format!("command did not execute successfully: {:?}\n\
expected success, got: {}", cmd, status));
expected success, got: {}",
cmd,
status));
}
}
@ -65,7 +67,9 @@ pub fn output(cmd: &mut Command) -> String {
};
if !output.status.success() {
panic!("command did not execute successfully: {:?}\n\
expected success, got: {}", cmd, output.status);
expected success, got: {}",
cmd,
output.status);
}
String::from_utf8(output.stdout).unwrap()
}

View File

@ -32,7 +32,7 @@
#if __ARM_EABI__
# define ARM_EABI_FNALIAS(aeabi_name, name) \
void __aeabi_##aeabi_name() __attribute__((alias("__" #name)));
# define COMPILER_RT_ABI
# define COMPILER_RT_ABI __attribute__((pcs("aapcs")))
#else
# define ARM_EABI_FNALIAS(aeabi_name, name)
# define COMPILER_RT_ABI

View File

@ -16,7 +16,7 @@
/* Returns: a ^ b */
COMPILER_RT_ABI double
double
__powidf2(double a, si_int b)
{
const int recip = b < 0;

View File

@ -16,7 +16,7 @@
/* Returns: a ^ b */
COMPILER_RT_ABI float
float
__powisf2(float a, si_int b)
{
const int recip = b < 0;

View File

@ -327,7 +327,7 @@ that takes a reference like so:
fn call_with_ref<F>(some_closure:F) -> i32
where F: Fn(&i32) -> i32 {
let mut value = 0;
let value = 0;
some_closure(&value)
}
```
@ -340,14 +340,15 @@ fn call_with_ref<'a, F>(some_closure:F) -> i32
where F: Fn(&'a i32) -> i32 {
```
However this presents a problem in our case. When you specify the explicit
lifetime on a function it binds that lifetime to the *entire* scope of the function
instead of just the invocation scope of our closure. This means that the borrow checker
will see a mutable reference in the same lifetime as our immutable reference and fail
to compile.
However, this presents a problem in our case. When a function has an explicit
lifetime parameter, that lifetime must be at least as long as the *entire*
call to that function. The borrow checker will complain that `value` doesn't
live long enough, because it is only in scope after its declaration inside the
function body.
In order to say that we only need the lifetime to be valid for the invocation scope
of the closure we can use Higher-Ranked Trait Bounds with the `for<...>` syntax:
What we need is a closure that can borrow its argument only for its own
invocation scope, not for the outer function's scope. In order to say that,
we can use Higher-Ranked Trait Bounds with the `for<...>` syntax:
```ignore
fn call_with_ref<F>(some_closure:F) -> i32
@ -362,7 +363,7 @@ expect.
fn call_with_ref<F>(some_closure:F) -> i32
where F: for<'a> Fn(&'a i32) -> i32 {
let mut value = 0;
let value = 0;
some_closure(&value)
}
```
@ -510,12 +511,11 @@ fn factory() -> Box<Fn(i32) -> i32> {
Box::new(|x| x + num)
}
# fn main() {
let f = factory();
let answer = f(1);
assert_eq!(6, answer);
# }
```
Theres just one last problem:
@ -540,12 +540,11 @@ fn factory() -> Box<Fn(i32) -> i32> {
Box::new(move |x| x + num)
}
fn main() {
let f = factory();
let answer = f(1);
assert_eq!(6, answer);
}
```
By making the inner closure a `move Fn`, we create a new stack frame for our

View File

@ -4,7 +4,7 @@ Concurrency and parallelism are incredibly important topics in computer
science, and are also a hot topic in industry today. Computers are gaining more
and more cores, yet many programmers aren't prepared to fully utilize them.
Rust's memory safety features also apply to its concurrency story too. Even
Rust's memory safety features also apply to its concurrency story. Even
concurrent Rust programs must be memory safe, having no data races. Rust's type
system is up to the task, and gives you powerful ways to reason about
concurrent code at compile time.
@ -281,8 +281,8 @@ And... still gives us an error.
```
`Arc<T>` by default has immutable contents. It allows the _sharing_ of data
between threads, but shared mutable data is unsafe and when threads are
involved can cause data races!
between threads, but shared mutable data is unsafeand when threads are
involvedcan cause data races!
Usually when we wish to make something in an immutable position mutable, we use

View File

@ -1,4 +1,4 @@
% `const` and `static`
% const and static
Rust has a way of defining constants with the `const` keyword:

View File

@ -69,7 +69,7 @@ foo(&counted);
All weve done is wrap our `String` in an `Rc<T>`. But we can now pass the
`Rc<String>` around anywhere wed have a `String`. The signature of `foo`
didnt change, but works just as well with either type. This example has two
conversions: `Rc<String>` to `String` and then `String` to `&str`. Rust will do
conversions: `&Rc<String>` to `&String` and then `&String` to `&str`. Rust will do
this as many times as possible until the types match.
Another very common implementation provided by the standard library is:

View File

@ -111,41 +111,40 @@ unofficial locations.
Note that this table can be expanded over time, this isn't the exhaustive set of
tier 3 platforms that will ever be!
## Installing on Linux or Mac
## Installing Rust
If we're on Linux or a Mac, all we need to do is open a terminal and type this:
All you need to do on Unix systems like Linux and macOS is open a
terminal and type this:
```bash
$ curl -sSf https://static.rust-lang.org/rustup.sh | sh
$ curl https://sh.rustup.rs -sSf | sh
```
This will download a script, and start the installation. If it all goes well,
youll see this appear:
It will download a script, and start the installation. If everything
goes well, youll see this appear:
```text
Rust is ready to roll.
Rust is installed now. Great!
```
From here, press `y` for yes, and then follow the rest of the prompts.
Installing on Windows is nearly as easy: download and run
[rustup-init.exe]. It will start the installation in a console and
present the above message on success.
## Installing on Windows
For other installation options and information, visit the [install]
page of the Rust website.
If you're on Windows, please download the appropriate [installer][install-page].
[install-page]: https://www.rust-lang.org/install.html
[rustup-init.exe]: https://win.rustup.rs
[install]: https://www.rust-lang.org/install.html
## Uninstalling
Uninstalling Rust is as easy as installing it. On Linux or Mac, run
the uninstall script:
Uninstalling Rust is as easy as installing it:
```bash
$ sudo /usr/local/lib/rustlib/uninstall.sh
$ rustup self uninstall
```
If we used the Windows installer, we can re-run the `.msi` and it will give us
an uninstall option.
## Troubleshooting
If we've got Rust installed, we can open up a shell, and type this:
@ -158,20 +157,33 @@ You should see the version number, commit hash, and commit date.
If you do, Rust has been installed successfully! Congrats!
If you don't and you're on Windows, check that Rust is in your %PATH% system
variable: `$ echo %PATH%`. If it isn't, run the installer again, select "Change"
on the "Change, repair, or remove installation" page and ensure "Add to PATH" is
installed on the local hard drive. If you need to configure your path manually,
you can find the Rust executables in a directory like
`"C:\Program Files\Rust stable GNU 1.x\bin"`.
If you don't, that probably means that the `PATH` environment variable
doesn't include Cargo's binary directory, `~/.cargo/bin` on Unix, or
`%USERPROFILE%\.cargo\bin` on Windows. This is the directory where
Rust development tools live, and most Rust developers keep it in their
`PATH` environment variable, which makes it possible to run `rustc` on
the command line. Due to differences in operating systems, command
shells, and bugs in installation, you may need to restart your shell,
log out of the system, or configure `PATH` manually as appropriate for
your operating environment.
Rust does not do its own linking, and so youll need to have a linker
installed. Doing so will depend on your specific system, consult its
documentation for more details.
installed. Doing so will depend on your specific system. For
Linux-based systems, Rust will attempt to call `cc` for linking. On
`windows-msvc` (Rust built on Windows with Microsoft Visual Studio),
this depends on having [Microsoft Visual C++ Build Tools][msvbt]
installed. These do not need to be in `%PATH%` as `rustc` will find
them automatically. In general, if you have your linker in a
non-traditional location you can call `rustc
linker=/path/to/cc`, where `/path/to/cc` should point to your linker path.
If not, there are a number of places where we can get help. The easiest is
[the #rust-beginners IRC channel on irc.mozilla.org][irc-beginners] and for
general discussion [the #rust IRC channel on irc.mozilla.org][irc], which we
[msvbt]: http://landinghub.visualstudio.com/visual-cpp-build-tools
If you are still stuck, there are a number of places where we can get
help. The easiest is
[the #rust-beginners IRC channel on irc.mozilla.org][irc-beginners]
and for general discussion
[the #rust IRC channel on irc.mozilla.org][irc], which we
can access through [Mibbit][mibbit]. Then we'll be chatting with other
Rustaceans (a silly nickname we call ourselves) who can help us out. Other great
resources include [the users forum][users] and [Stack Overflow][stackoverflow].
@ -183,9 +195,7 @@ resources include [the users forum][users] and [Stack Overflow][stackoverflow
[stackoverflow]: http://stackoverflow.com/questions/tagged/rust
This installer also installs a copy of the documentation locally, so we can
read it offline. On UNIX systems, `/usr/local/share/doc/rust` is the location.
On Windows, it's in a `share/doc` directory, inside the directory to which Rust
was installed.
read it offline. It's only a `rustup doc` away!
# Hello, world!
@ -495,6 +505,9 @@ $ cargo run
Hello, world!
```
The `run` command comes in handy when you need to rapidly iterate on a
project.
Notice that this example didnt re-build the project. Cargo figured out that
the file hasnt changed, and so it just ran the binary. If you'd modified your
source code, Cargo would have rebuilt the project before running it, and you

View File

@ -56,9 +56,7 @@ $ cargo build
Excellent! Open up your `src/main.rs` again. Well be writing all of
our code in this file.
Before we move on, let me show you one more Cargo command: `run`. `cargo run`
is kind of like `cargo build`, but it also then runs the produced executable.
Try it out:
Remember the `run` command from last chapter? Try it out again here:
```bash
$ cargo run
@ -67,9 +65,8 @@ $ cargo run
Hello, world!
```
Great! The `run` command comes in handy when you need to rapidly iterate on a
project. Our game is such a project, we need to quickly test each
iteration before moving on to the next one.
Great! Our game is just the kind of project `run` is good for: we need
to quickly test each iteration before moving on to the next one.
# Processing a Guess
@ -279,7 +276,7 @@ displaying the message.
[expect]: ../std/result/enum.Result.html#method.expect
[panic]: error-handling.html
If we leave off calling this method, our program will compile, but
If we do not call `expect()`, our program will compile, but
well get a warning:
```bash
@ -365,7 +362,6 @@ numbers. A bare number like above is actually shorthand for `^0.3.0`,
meaning "anything compatible with 0.3.0".
If we wanted to use only `0.3.0` exactly, we could say `rand="=0.3.0"`
(note the two equal signs).
And if we wanted to use the latest version we could use `rand="*"`.
We could also use a range of versions.
[Cargos documentation][cargodoc] contains more details.

View File

@ -50,29 +50,94 @@ complicated. For example, imagine this set of operations:
4. You decide to use the resource.
Uh oh! Your reference is pointing to an invalid resource. This is called a
dangling pointer or use after free, when the resource is memory.
dangling pointer or use after free, when the resource is memory. A small
example of such a situation would be:
```rust,compile_fail
let r; // Introduce reference: r
{
let i = 1; // Introduce scoped value: i
r = &i; // Store reference of i in r
} // i goes out of scope and is dropped.
println!("{}", r); // r still refers to i
```
To fix this, we have to make sure that step four never happens after step
three. The ownership system in Rust does this through a concept called
lifetimes, which describe the scope that a reference is valid for.
three. In the small example above the Rust compiler is able to report the issue
as it can see the lifetimes of the various values in the function.
When we have a function that takes an argument by reference, we can be
implicit or explicit about the lifetime of the reference:
When we have a function that takes arguments by reference the situation becomes
more complex. Consider the following example:
```rust
// implicit
fn foo(x: &i32) {
```rust,compile_fail,E0106
fn skip_prefix(line: &str, prefix: &str) -> &str {
// ...
# line
}
// explicit
fn bar<'a>(x: &'a i32) {
let line = "lang:en=Hello World!";
let lang = "en";
let v;
{
let p = format!("lang:{}=", lang); // -+ p goes into scope
v = skip_prefix(line, p.as_str()); // |
} // -+ p goes out of scope
println!("{}", v);
```
Here we have a function `skip_prefix` which takes two `&str` references
as parameters and returns a single `&str` reference. We call it
by passing in references to `line` and `p`: Two variables with different
lifetimes. Now the safety of the `println!`-line depends on whether the
reference returned by `skip_prefix` function references the still living
`line` or the already dropped `p` string.
Because of the above ambiguity, Rust will refuse to compile the example
code. To get it to compile we need to tell the compiler more about the
lifetimes of the references. This can be done by making the lifetimes
explicit in the function declaration:
```rust
fn skip_prefix<'a, 'b>(line: &'a str, prefix: &'b str) -> &'a str {
// ...
# line
}
```
Let's examine the changes without going too deep into the syntax for now -
we'll get to that later. The first change was adding the `<'a, 'b>` after the
method name. This introduces two lifetime parameters: `'a` and `'b`. Next each
reference in the function signature was associated with one of the lifetime
parameters by adding the lifetime name after the `&`. This tells the compiler
how the lifetimes between different references are related.
As a result the compiler is now able to deduce that the return value of
`skip_prefix` has the same lifetime as the `line` parameter, which makes the `v`
reference safe to use even after the `p` goes out of scope in the original
example.
In addition to the compiler being able to validate the usage of `skip_prefix`
return value, it can also ensure that the implementation follows the contract
established by the function declaration. This is useful especially when you are
implementing traits that are introduced [later in the book][traits].
**Note** It's important to understand that lifetime annotations are
_descriptive_, not _prescriptive_. This means that how long a reference is valid
is determined by the code, not by the annotations. The annotations, however,
give information about lifetimes to the compiler that uses them to check the
validity of references. The compiler can do so without annotations in simple
cases, but needs the programmers support in complex scenarios.
[traits]: traits.html
# Syntax
The `'a` reads the lifetime a. Technically, every reference has some lifetime
associated with it, but the compiler lets you elide (i.e. omit, see
["Lifetime Elision"][lifetime-elision] below) them in common cases.
Before we get to that, though, lets break the explicit example down:
["Lifetime Elision"][lifetime-elision] below) them in common cases. Before we
get to that, though, lets look at a short example with explicit lifetimes:
[lifetime-elision]: #lifetime-elision
@ -90,7 +155,8 @@ focus on the lifetimes aspect.
[generics]: generics.html
We use `<>` to declare our lifetimes. This says that `bar` has one lifetime,
`'a`. If we had two reference parameters, it would look like this:
`'a`. If we had two reference parameters with different lifetimes, it would
look like this:
```rust,ignore

View File

@ -86,7 +86,7 @@ fn main() {
return v.iter().fold(0, |a, &b| a + b);
}
// Borrow two vectors and sum them.
// This kind of borrowing does not allow mutation to the borrowed.
// This kind of borrowing does not allow mutation through the borrowed reference.
fn foo(v1: &Vec<i32>, v2: &Vec<i32>) -> i32 {
// do stuff with v1 and v2
let s1 = sum_vec(v1);
@ -240,7 +240,7 @@ fn main() {
In other words, the mutable borrow is held through the rest of our example. What
we want is for the mutable borrow by `y` to end so that the resource can be
returned to the owner, `x`. `x` can then provide a immutable borrow to `println!`.
returned to the owner, `x`. `x` can then provide an immutable borrow to `println!`.
In Rust, borrowing is tied to the scope that the borrow is valid for. And our
scopes look like this:

View File

@ -61,7 +61,6 @@
* `-` (`- expr`): arithmetic negation. Overloadable (`Neg`).
* `-=` (`var -= expr`): arithmetic subtraction & assignment. Overloadable (`SubAssign`).
* `->` (`fn(…) -> type`, `|…| -> type`): function and closure return type. See [Functions], [Closures].
* `-> !` (`fn(…) -> !`, `|…| -> !`): diverging function or closure. See [Diverging Functions].
* `.` (`expr.ident`): member access. See [Structs], [Method Syntax].
* `..` (`..`, `expr..`, `..expr`, `expr..expr`): right-exclusive range literal.
* `..` (`..expr`): struct literal update syntax. See [Structs (Update syntax)].
@ -95,6 +94,7 @@
* `|=` (`var |= expr`): bitwise or & assignment. Overloadable (`BitOrAssign`).
* `||` (`expr || expr`): logical or.
* `_`: "ignored" pattern binding (see [Patterns (Ignoring bindings)]). Also used to make integer-literals readable (see [Reference (Integer literals)]).
* `?` (`expr?`): Error propagation. Returns early when `Err(_)` is encountered, unwraps otherwise. Similar to the [`try!` macro].
## Other Syntax
@ -159,6 +159,10 @@
* `/*!…*/`: inner block doc comment. See [Comments].
* `/**…*/`: outer block doc comment. See [Comments].
<!-- Special types -->
* `!`: always empty Never type. See [Diverging Functions].
<!-- Various things involving parens and tuples -->
* `()`: empty tuple (*a.k.a.* unit), both literal and type.
@ -207,6 +211,7 @@
[Functions]: functions.html
[Generics]: generics.html
[Iterators]: iterators.html
[`try!` macro]: error-handling.html#the-try-macro
[Lifetimes]: lifetimes.html
[Loops (`for`)]: loops.html#for
[Loops (`loop`)]: loops.html#loop

View File

@ -24,9 +24,11 @@ Cargo will automatically generate a simple test when you make a new project.
Here's the contents of `src/lib.rs`:
```rust
# fn main() {}
#[test]
fn it_works() {
#[cfg(test)]
mod tests {
#[test]
fn it_works() {
}
}
```
@ -36,11 +38,11 @@ currently has no body. That's good enough to pass! We can run the tests with
```bash
$ cargo test
Compiling adder v0.0.1 (file:///home/you/projects/adder)
Running target/adder-91b3e234d4ed382a
Compiling adder v0.1.0 (file:///home/you/projects/adder)
Running target/debug/deps/adder-91b3e234d4ed382a
running 1 test
test it_works ... ok
test tests::it_works ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
@ -56,7 +58,7 @@ for the test we wrote, and another for documentation tests. We'll talk about
those later. For now, see this line:
```text
test it_works ... ok
test tests::it_works ... ok
```
Note the `it_works`. This comes from the name of our function:
@ -89,31 +91,30 @@ run our tests again:
```bash
$ cargo test
Compiling adder v0.0.1 (file:///home/you/projects/adder)
Running target/adder-91b3e234d4ed382a
Compiling adder v0.1.0 (file:///home/you/projects/adder)
Running target/debug/deps/adder-91b3e234d4ed382a
running 1 test
test it_works ... FAILED
test tests::it_works ... FAILED
failures:
---- it_works stdout ----
thread 'it_works' panicked at 'assertion failed: false', /home/steve/tmp/adder/src/lib.rs:3
---- test::it_works stdout ----
thread 'tests::it_works' panicked at 'assertion failed: false', src/lib.rs:5
failures:
it_works
tests::it_works
test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured
thread 'main' panicked at 'Some tests failed', /home/steve/src/rust/src/libtest/lib.rs:247
error: test failed
```
Rust indicates that our test failed:
```text
test it_works ... FAILED
test tests::it_works ... FAILED
```
And that's reflected in the summary line:
@ -159,11 +160,11 @@ This test will now succeed if we `panic!` and fail if we complete. Let's try it:
```bash
$ cargo test
Compiling adder v0.0.1 (file:///home/you/projects/adder)
Running target/adder-91b3e234d4ed382a
Compiling adder v0.1.0 (file:///home/you/projects/adder)
Running target/debug/deps/adder-91b3e234d4ed382a
running 1 test
test it_works ... ok
test tests::it_works ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
@ -191,11 +192,11 @@ passes:
```bash
$ cargo test
Compiling adder v0.0.1 (file:///home/you/projects/adder)
Running target/adder-91b3e234d4ed382a
Compiling adder v0.1.0 (file:///home/you/projects/adder)
Running target/debug/deps/adder-91b3e234d4ed382a
running 1 test
test it_works ... ok
test tests::it_works ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
@ -262,8 +263,8 @@ not:
```bash
$ cargo test
Compiling adder v0.0.1 (file:///home/you/projects/adder)
Running target/adder-91b3e234d4ed382a
Compiling adder v0.1.0 (file:///home/you/projects/adder)
Running target/debug/deps/adder-91b3e234d4ed382a
running 2 tests
test expensive_test ... ignored
@ -282,7 +283,7 @@ The expensive tests can be run explicitly using `cargo test -- --ignored`:
```bash
$ cargo test -- --ignored
Running target/adder-91b3e234d4ed382a
Running target/debug/deps/adder-91b3e234d4ed382a
running 1 test
test expensive_test ... ok
@ -302,8 +303,11 @@ which is why the command is `cargo test -- --ignored`.
# The `tests` module
There is one way in which our existing example is not idiomatic: it's
missing the `tests` module. The idiomatic way of writing our example
looks like this:
missing the `tests` module. You might have noticed this test module was
present in the code that was initially generated with `cargo new` but
was missing from our last example. Let's explain what this does.
The idiomatic way of writing our example looks like this:
```rust,ignore
# fn main() {}
@ -356,8 +360,8 @@ Note the different `use` line. Now we run our tests:
```bash
$ cargo test
Updating registry `https://github.com/rust-lang/crates.io-index`
Compiling adder v0.0.1 (file:///home/you/projects/adder)
Running target/adder-91b3e234d4ed382a
Compiling adder v0.1.0 (file:///home/you/projects/adder)
Running target/debug/deps/adder-91b3e234d4ed382a
running 1 test
test tests::it_works ... ok
@ -380,9 +384,9 @@ the `tests` directory.
# The `tests` directory
Each file in `tests/*.rs` directory is treated as individual crate.
So, to write an integration test, let's make a `tests` directory, and
put a `tests/integration_test.rs` file inside, with this as its contents:
Each file in `tests/*.rs` directory is treated as an individual crate.
To write an integration test, let's make a `tests` directory and
put a `tests/integration_test.rs` file inside with this as its contents:
```rust,ignore
extern crate adder;
@ -404,15 +408,15 @@ Let's run them:
```bash
$ cargo test
Compiling adder v0.0.1 (file:///home/you/projects/adder)
Running target/adder-91b3e234d4ed382a
Compiling adder v0.1.0 (file:///home/you/projects/adder)
Running target/debug/deps/adder-91b3e234d4ed382a
running 1 test
test tests::it_works ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
Running target/lib-c18e7d3494509e74
Running target/debug/integration_test-68064b69521c828a
running 1 test
test it_works ... ok
@ -490,15 +494,15 @@ Let's run the tests again:
```bash
$ cargo test
Compiling adder v0.0.1 (file:///home/steve/tmp/adder)
Running target/adder-91b3e234d4ed382a
Compiling adder v0.1.0. (file:///home/you/projects/adder)
Running target/debug/deps/adder-91b3e234d4ed382a
running 1 test
test tests::it_works ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
Running target/lib-c18e7d3494509e74
Running target/debug/integration_test-68064b69521c828a
running 1 test
test it_works ... ok

View File

@ -1,4 +1,4 @@
% `type` Aliases
% Type Aliases
The `type` keyword lets you declare an alias of another type:

View File

@ -161,7 +161,7 @@ Could not compile `hello_world`.
Rust will not let us use a value that has not been initialized.
Let take a minute to talk about this stuff we've added to `println!`.
Let us take a minute to talk about this stuff we've added to `println!`.
If you include two curly braces (`{}`, some call them moustaches...) in your
string to print, Rust will interpret this as a request to interpolate some sort

View File

@ -5,4 +5,3 @@ or the <a href="https://opensource.org/licenses/MIT">MIT license</a>, at your op
</p><p>
This file may not be copied, modified, or distributed except according to those terms.
</p></footer>
<script type="text/javascript" src="playpen.js"></script>

View File

@ -764,6 +764,13 @@ bound-list := bound | bound '+' bound-list
bound := path | lifetime
```
### Never type
An empty type
```antlr
never_type : "!" ;
```
### Object types
**FIXME:** grammar?

View File

@ -2479,8 +2479,6 @@ The currently implemented features of the reference compiler are:
* - `abi_vectorcall` - Allows the usage of the vectorcall calling convention
(e.g. `extern "vectorcall" func fn_();`)
* - `dotdot_in_tuple_patterns` - Allows `..` in tuple (struct) patterns.
* - `abi_sysv64` - Allows the usage of the system V AMD64 calling convention
(e.g. `extern "sysv64" func fn_();`)
@ -2860,8 +2858,8 @@ assert_eq!(x, y);
### Unary operator expressions
Rust defines the following unary operators. They are all written as prefix operators,
before the expression they apply to.
Rust defines the following unary operators. With the exception of `?`, they are
all written as prefix operators, before the expression they apply to.
* `-`
: Negation. Signed integer types and floating-point types support negation. It
@ -2890,6 +2888,10 @@ before the expression they apply to.
If the `&` or `&mut` operators are applied to an rvalue, a
temporary value is created; the lifetime of this temporary value
is defined by [syntactic rules](#temporary-lifetimes).
* `?`
: Propagating errors if applied to `Err(_)` and unwrapping if
applied to `Ok(_)`. Only works on the `Result<T, E>` type,
and written in postfix notation.
### Binary operator expressions
@ -3109,10 +3111,12 @@ the lambda expression captures its environment by reference, effectively
borrowing pointers to all outer variables mentioned inside the function.
Alternately, the compiler may infer that a lambda expression should copy or
move values (depending on their type) from the environment into the lambda
expression's captured environment.
expression's captured environment. A lambda can be forced to capture its
environment by moving values by prefixing it with the `move` keyword.
In this example, we define a function `ten_times` that takes a higher-order
function argument, and we then call it with a lambda expression as an argument:
function argument, and we then call it with a lambda expression as an argument,
followed by a lambda expression that moves values from its environment.
```
fn ten_times<F>(f: F) where F: Fn(i32) {
@ -3122,6 +3126,9 @@ fn ten_times<F>(f: F) where F: Fn(i32) {
}
ten_times(|j| println!("hello, {}", j));
let word = "konnichiwa".to_owned();
ten_times(move |j| println!("{}, {}", word, j));
```
### Infinite loops
@ -3750,6 +3757,21 @@ The special type `Self` has a meaning within traits and impls. In a trait defini
to an implicit type parameter representing the "implementing" type. In an impl,
it is an alias for the implementing type. For example, in:
```
pub trait From<T> {
fn from(T) -> Self;
}
impl From<i32> for String {
fn from(x: i32) -> Self {
x.to_string()
}
}
```
The notation `Self` in the impl refers to the implementing type: `String`. In another
example:
```
trait Printable {
fn make_string(&self) -> String;
@ -3958,6 +3980,16 @@ the top-level type for the implementation of the called method. If no such metho
found, `.deref()` is called and the compiler continues to search for the method
implementation in the returned type `U`.
## The `Send` trait
The `Send` trait indicates that a value of this type is safe to send from one
thread to another.
## The `Sync` trait
The `Sync` trait indicates that a value of this type is safe to share between
multiple threads.
# Memory model
A Rust program's memory consists of a static set of *items* and a *heap*.
@ -4008,9 +4040,9 @@ Methods that take either `self` or `Box<Self>` can optionally place them in a
mutable variable by prefixing them with `mut` (similar to regular arguments):
```
trait Changer {
fn change(mut self) -> Self;
fn modify(mut self: Box<Self>) -> Box<Self>;
trait Changer: Sized {
fn change(mut self) {}
fn modify(mut self: Box<Self>) {}
}
```
@ -4063,6 +4095,12 @@ be ignored in favor of only building the artifacts specified by command line.
Rust code into an existing non-Rust application because it will not have
dynamic dependencies on other Rust code.
* `--crate-type=cdylib`, `#[crate_type = "cdylib"]` - A dynamic system
library will be produced. This is used when compiling Rust code as
a dynamic library to be loaded from another language. This output type will
create `*.so` files on Linux, `*.dylib` files on OSX, and `*.dll` files on
Windows.
* `--crate-type=rlib`, `#[crate_type = "rlib"]` - A "Rust library" file will be
produced. This is used as an intermediate artifact and can be thought of as a
"static Rust library". These `rlib` files, unlike `staticlib` files, are

View File

@ -336,13 +336,11 @@ table th {
/* Code snippets */
.rusttest { display: none; }
pre.rust { position: relative; }
a.test-arrow {
background-color: rgba(78, 139, 202, 0.2);
display: inline-block;
position: absolute;
background-color: #4e8bca;
color: #f5f5f5;
padding: 5px 10px 5px 10px;
border-radius: 5px;
@ -350,6 +348,10 @@ a.test-arrow {
top: 5px;
right: 5px;
}
a.test-arrow:hover{
background-color: #4e8bca;
text-decoration: none;
}
.unstable-feature {
border: 2px solid red;

View File

@ -71,6 +71,7 @@ cp ${PREFIX}/${LIB_DIR}/${LIB_PREFIX}log*${LIB_SUF} ${TARG_DIR}/stage0/${LIB_DIR
cp ${PREFIX}/${LIB_DIR}/${LIB_PREFIX}rbml*${LIB_SUF} ${TARG_DIR}/stage0/${LIB_DIR}/
cp ${PREFIX}/${LIB_DIR}/${LIB_PREFIX}serialize*${LIB_SUF} ${TARG_DIR}/stage0/${LIB_DIR}/
cp ${PREFIX}/${LIB_DIR}/${LIB_PREFIX}term*${LIB_SUF} ${TARG_DIR}/stage0/${LIB_DIR}/
cp ${PREFIX}/${LIB_DIR}/${LIB_PREFIX}proc_macro*${LIB_SUF} ${TARG_DIR}/stage0/${LIB_DIR}/
# do not fail if one of the above fails, as all we need is a working rustc!
exit 0

View File

@ -10,35 +10,11 @@
#![stable(feature = "rust1", since = "1.0.0")]
//! Threadsafe reference-counted boxes (the `Arc<T>` type).
//! Thread-safe reference-counting pointers.
//!
//! The `Arc<T>` type provides shared ownership of an immutable value through
//! atomic reference counting.
//! See the [`Arc<T>`][arc] documentation for more details.
//!
//! `Weak<T>` is a weak reference to the `Arc<T>` box, and it is created by
//! the `downgrade` method.
//! # Examples
//!
//! Sharing some immutable data between threads:
//!
// Note that we **do not** run these tests here. The windows builders get super
// unhappy of a thread outlives the main thread and then exits at the same time
// (something deadlocks) so we just avoid this entirely by not running these
// tests.
//! ```no_run
//! use std::sync::Arc;
//! use std::thread;
//!
//! let five = Arc::new(5);
//!
//! for _ in 0..10 {
//! let five = five.clone();
//!
//! thread::spawn(move || {
//! println!("{:?}", five);
//! });
//! }
//! ```
//! [arc]: struct.Arc.html
use boxed::Box;
@ -60,74 +36,120 @@ use core::{isize, usize};
use core::convert::From;
use heap::deallocate;
/// A soft limit on the amount of references that may be made to an `Arc`.
///
/// Going above this limit will abort your program (although not
/// necessarily) at _exactly_ `MAX_REFCOUNT + 1` references.
const MAX_REFCOUNT: usize = (isize::MAX) as usize;
/// An atomically reference counted wrapper for shared state.
/// Destruction is deterministic, and will occur as soon as the last owner is
/// gone. It is marked as `Send` because it uses atomic reference counting.
/// A thread-safe reference-counting pointer.
///
/// If you do not need thread-safety, and just need shared ownership, consider
/// the [`Rc<T>` type](../rc/struct.Rc.html). It is the same as `Arc<T>`, but
/// does not use atomics, making it both thread-unsafe as well as significantly
/// faster when updating the reference count.
/// The type `Arc<T>` provides shared ownership of a value of type `T`,
/// allocated in the heap. Invoking [`clone`][clone] on `Arc` produces
/// a new pointer to the same value in the heap. When the last `Arc`
/// pointer to a given value is destroyed, the pointed-to value is
/// also destroyed.
///
/// Note: the inherent methods defined on `Arc<T>` are all associated functions,
/// which means that you have to call them as e.g. `Arc::get_mut(&value)`
/// instead of `value.get_mut()`. This is so that there are no conflicts with
/// methods on the inner type `T`, which are what you want to call in the
/// majority of cases.
/// Shared references in Rust disallow mutation by default, and `Arc` is no
/// exception. If you need to mutate through an `Arc`, use [`Mutex`][mutex],
/// [`RwLock`][rwlock], or one of the [`Atomic`][atomic] types.
///
/// # Examples
/// `Arc` uses atomic operations for reference counting, so `Arc`s can be
/// sent between threads. In other words, `Arc<T>` implements [`Send`][send]
/// as long as `T` implements `Send` and [`Sync`][sync]. The disadvantage is
/// that atomic operations are more expensive than ordinary memory accesses.
/// If you are not sharing reference-counted values between threads, consider
/// using [`rc::Rc`][rc] for lower overhead. `Rc` is a safe default, because
/// the compiler will catch any attempt to send an `Rc` between threads.
/// However, a library might choose `Arc` in order to give library consumers
/// more flexibility.
///
/// In this example, a large vector of data will be shared by several threads. First we
/// wrap it with a `Arc::new` and then clone the `Arc<T>` reference for every thread (which will
/// increase the reference count atomically).
/// The [`downgrade`][downgrade] method can be used to create a non-owning
/// [`Weak`][weak] pointer. A `Weak` pointer can be [`upgrade`][upgrade]d
/// to an `Arc`, but this will return [`None`][option] if the value has
/// already been dropped.
///
/// A cycle between `Arc` pointers will never be deallocated. For this reason,
/// `Weak` is used to break cycles. For example, a tree could have strong
/// `Arc` pointers from parent nodes to children, and `Weak` pointers from
/// children back to their parents.
///
/// `Arc<T>` automatically dereferences to `T` (via the [`Deref`][deref] trait),
/// so you can call `T`'s methods on a value of type `Arc<T>`. To avoid name
/// clashes with `T`'s methods, the methods of `Arc<T>` itself are [associated
/// functions][assoc], called using function-like syntax:
///
/// ```
/// use std::sync::Arc;
/// use std::thread;
/// let my_arc = Arc::new(());
///
/// fn main() {
/// let numbers: Vec<_> = (0..100).collect();
/// let shared_numbers = Arc::new(numbers);
///
/// for _ in 0..10 {
/// // prepare a copy of reference here and it will be moved to the thread
/// let child_numbers = shared_numbers.clone();
///
/// thread::spawn(move || {
/// let local_numbers = &child_numbers[..];
///
/// // Work with the local numbers
/// });
/// }
/// }
/// Arc::downgrade(&my_arc);
/// ```
/// You can also share mutable data between threads safely
/// by putting it inside `Mutex` and then share `Mutex` immutably
/// with `Arc<T>` as shown below.
///
// See comment at the top of this file for why the test is no_run
/// `Weak<T>` does not auto-dereference to `T`, because the value may have
/// already been destroyed.
///
/// [arc]: struct.Arc.html
/// [weak]: struct.Weak.html
/// [rc]: ../../std/rc/struct.Rc.html
/// [clone]: ../../std/clone/trait.Clone.html#tymethod.clone
/// [mutex]: ../../std/sync/struct.Mutex.html
/// [rwlock]: ../../std/sync/struct.RwLock.html
/// [atomic]: ../../std/sync/atomic/index.html
/// [send]: ../../std/marker/trait.Send.html
/// [sync]: ../../std/marker/trait.Sync.html
/// [deref]: ../../std/ops/trait.Deref.html
/// [downgrade]: struct.Arc.html#method.downgrade
/// [upgrade]: struct.Weak.html#method.upgrade
/// [option]: ../../std/option/enum.Option.html
/// [assoc]: ../../book/method-syntax.html#associated-functions
///
/// # Examples
///
/// Sharing some immutable data between threads:
///
// Note that we **do not** run these tests here. The windows builders get super
// unhappy if a thread outlives the main thread and then exits at the same time
// (something deadlocks) so we just avoid this entirely by not running these
// tests.
/// ```no_run
/// use std::sync::{Arc, Mutex};
/// use std::sync::Arc;
/// use std::thread;
///
/// let five = Arc::new(Mutex::new(5));
/// let five = Arc::new(5);
///
/// for _ in 0..10 {
/// let five = five.clone();
///
/// thread::spawn(move || {
/// let mut number = five.lock().unwrap();
///
/// *number += 1;
///
/// println!("{}", *number); // prints 6
/// println!("{:?}", five);
/// });
/// }
/// ```
#[cfg_attr(stage0, unsafe_no_drop_flag)]
///
/// Sharing a mutable `AtomicUsize`:
///
/// ```no_run
/// use std::sync::Arc;
/// use std::sync::atomic::{AtomicUsize, Ordering};
/// use std::thread;
///
/// let val = Arc::new(AtomicUsize::new(5));
///
/// for _ in 0..10 {
/// let val = val.clone();
///
/// thread::spawn(move || {
/// let v = val.fetch_add(1, Ordering::SeqCst);
/// println!("{:?}", v);
/// });
/// }
/// ```
///
/// See the [`rc` documentation][rc_examples] for more examples of reference
/// counting in general.
///
/// [rc_examples]: ../../std/rc/index.html#examples
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Arc<T: ?Sized> {
ptr: Shared<ArcInner<T>>,
@ -141,19 +163,18 @@ unsafe impl<T: ?Sized + Sync + Send> Sync for Arc<T> {}
#[unstable(feature = "coerce_unsized", issue = "27732")]
impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Arc<U>> for Arc<T> {}
/// A weak pointer to an `Arc`.
/// A weak version of [`Arc`][arc].
///
/// Weak pointers will not keep the data inside of the `Arc` alive, and can be
/// used to break cycles between `Arc` pointers.
/// `Weak` pointers do not count towards determining if the inner value
/// should be dropped.
///
/// A `Weak<T>` pointer can be upgraded to an `Arc<T>` pointer, but
/// will return `None` if the value has already been dropped.
/// The typical way to obtain a `Weak` pointer is to call
/// [`Arc::downgrade`][downgrade].
///
/// For example, a tree with parent pointers can be represented by putting the
/// nodes behind strong `Arc<T>` pointers, and then storing the parent pointers
/// as `Weak<T>` pointers.
#[cfg_attr(stage0, unsafe_no_drop_flag)]
/// See the [`Arc`][arc] documentation for more details.
///
/// [arc]: struct.Arc.html
/// [downgrade]: struct.Arc.html#method.downgrade
#[stable(feature = "arc_weak", since = "1.4.0")]
pub struct Weak<T: ?Sized> {
ptr: Shared<ArcInner<T>>,
@ -211,12 +232,15 @@ impl<T> Arc<T> {
Arc { ptr: unsafe { Shared::new(Box::into_raw(x)) } }
}
/// Unwraps the contained value if the `Arc<T>` has exactly one strong reference.
/// Returns the contained value, if the `Arc` has exactly one strong reference.
///
/// Otherwise, an `Err` is returned with the same `Arc<T>`.
/// Otherwise, an [`Err`][result] is returned with the same `Arc` that was
/// passed in.
///
/// This will succeed even if there are outstanding weak references.
///
/// [result]: ../../std/result/enum.Result.html
///
/// # Examples
///
/// ```
@ -227,7 +251,7 @@ impl<T> Arc<T> {
///
/// let x = Arc::new(4);
/// let _y = x.clone();
/// assert_eq!(Arc::try_unwrap(x), Err(Arc::new(4)));
/// assert_eq!(*Arc::try_unwrap(x).unwrap_err(), 4);
/// ```
#[inline]
#[stable(feature = "arc_unique", since = "1.4.0")]
@ -253,7 +277,9 @@ impl<T> Arc<T> {
}
impl<T: ?Sized> Arc<T> {
/// Downgrades the `Arc<T>` to a `Weak<T>` reference.
/// Creates a new [`Weak`][weak] pointer to this value.
///
/// [weak]: struct.Weak.html
///
/// # Examples
///
@ -291,7 +317,27 @@ impl<T: ?Sized> Arc<T> {
}
}
/// Get the number of weak references to this value.
/// Gets the number of [`Weak`][weak] pointers to this value.
///
/// Be careful how you use this information, because another thread
/// may change the weak count at any time.
///
/// [weak]: struct.Weak.html
///
/// # Examples
///
/// ```
/// #![feature(arc_counts)]
///
/// use std::sync::Arc;
///
/// let five = Arc::new(5);
/// let _weak_five = Arc::downgrade(&five);
///
/// // This assertion is deterministic because we haven't shared
/// // the `Arc` or `Weak` between threads.
/// assert_eq!(1, Arc::weak_count(&five));
/// ```
#[inline]
#[unstable(feature = "arc_counts", reason = "not clearly useful, and racy",
issue = "28356")]
@ -299,7 +345,25 @@ impl<T: ?Sized> Arc<T> {
this.inner().weak.load(SeqCst) - 1
}
/// Get the number of strong references to this value.
/// Gets the number of strong (`Arc`) pointers to this value.
///
/// Be careful how you use this information, because another thread
/// may change the strong count at any time.
///
/// # Examples
///
/// ```
/// #![feature(arc_counts)]
///
/// use std::sync::Arc;
///
/// let five = Arc::new(5);
/// let _also_five = five.clone();
///
/// // This assertion is deterministic because we haven't shared
/// // the `Arc` between threads.
/// assert_eq!(2, Arc::strong_count(&five));
/// ```
#[inline]
#[unstable(feature = "arc_counts", reason = "not clearly useful, and racy",
issue = "28356")]
@ -336,8 +400,8 @@ impl<T: ?Sized> Arc<T> {
#[unstable(feature = "ptr_eq",
reason = "newly added",
issue = "36497")]
/// Return whether two `Arc` references point to the same value
/// (not just values that compare equal).
/// Returns true if the two `Arc`s point to the same value (not
/// just values that compare as equal).
///
/// # Examples
///
@ -362,9 +426,10 @@ impl<T: ?Sized> Arc<T> {
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> Clone for Arc<T> {
/// Makes a clone of the `Arc<T>`.
/// Makes a clone of the `Arc` pointer.
///
/// This increases the strong reference count.
/// This creates another pointer to the same inner value, increasing the
/// strong reference count.
///
/// # Examples
///
@ -420,11 +485,17 @@ impl<T: ?Sized> Deref for Arc<T> {
}
impl<T: Clone> Arc<T> {
/// Make a mutable reference into the given `Arc<T>`.
/// If the `Arc<T>` has more than one strong reference, or any weak
/// references, the inner data is cloned.
/// Makes a mutable reference into the given `Arc`.
///
/// This is also referred to as a copy-on-write.
/// If there are other `Arc` or [`Weak`][weak] pointers to the same value,
/// then `make_mut` will invoke [`clone`][clone] on the inner value to
/// ensure unique ownership. This is also referred to as clone-on-write.
///
/// See also [`get_mut`][get_mut], which will fail rather than cloning.
///
/// [weak]: struct.Weak.html
/// [clone]: ../../std/clone/trait.Clone.html#tymethod.clone
/// [get_mut]: struct.Arc.html#method.get_mut
///
/// # Examples
///
@ -439,10 +510,9 @@ impl<T: Clone> Arc<T> {
/// *Arc::make_mut(&mut data) += 1; // Won't clone anything
/// *Arc::make_mut(&mut other_data) *= 2; // Won't clone anything
///
/// // Note: data and other_data now point to different numbers
/// // Now `data` and `other_data` point to different values.
/// assert_eq!(*data, 8);
/// assert_eq!(*other_data, 12);
///
/// ```
#[inline]
#[stable(feature = "arc_unique", since = "1.4.0")]
@ -501,8 +571,19 @@ impl<T: Clone> Arc<T> {
}
impl<T: ?Sized> Arc<T> {
/// Returns a mutable reference to the contained value if the `Arc<T>` has
/// one strong reference and no weak references.
/// Returns a mutable reference to the inner value, if there are
/// no other `Arc` or [`Weak`][weak] pointers to the same value.
///
/// Returns [`None`][option] otherwise, because it is not safe to
/// mutate a shared value.
///
/// See also [`make_mut`][make_mut], which will [`clone`][clone]
/// the inner value when it's shared.
///
/// [weak]: struct.Weak.html
/// [option]: ../../std/option/enum.Option.html
/// [make_mut]: struct.Arc.html#method.make_mut
/// [clone]: ../../std/clone/trait.Clone.html#tymethod.clone
///
/// # Examples
///
@ -564,30 +645,32 @@ impl<T: ?Sized> Arc<T> {
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> Drop for Arc<T> {
/// Drops the `Arc<T>`.
/// Drops the `Arc`.
///
/// This will decrement the strong reference count. If the strong reference
/// count becomes zero and the only other references are `Weak<T>` ones,
/// `drop`s the inner value.
/// count reaches zero then the only other references (if any) are
/// [`Weak`][weak], so we `drop` the inner value.
///
/// [weak]: struct.Weak.html
///
/// # Examples
///
/// ```
/// use std::sync::Arc;
///
/// {
/// let five = Arc::new(5);
/// struct Foo;
///
/// // stuff
///
/// drop(five); // explicit drop
/// impl Drop for Foo {
/// fn drop(&mut self) {
/// println!("dropped!");
/// }
/// }
/// {
/// let five = Arc::new(5);
///
/// // stuff
/// let foo = Arc::new(Foo);
/// let foo2 = foo.clone();
///
/// } // implicit drop
/// drop(foo); // Doesn't print anything
/// drop(foo2); // Prints "dropped!"
/// ```
#[unsafe_destructor_blind_to_params]
#[inline]
@ -625,10 +708,14 @@ impl<T: ?Sized> Drop for Arc<T> {
}
impl<T> Weak<T> {
/// Constructs a new `Weak<T>` without an accompanying instance of T.
/// Constructs a new `Weak<T>`, without an accompanying instance of `T`.
///
/// This allocates memory for T, but does not initialize it. Calling
/// Weak<T>::upgrade() on the return value always gives None.
/// This allocates memory for `T`, but does not initialize it. Calling
/// [`upgrade`][upgrade] on the return value always gives
/// [`None`][option].
///
/// [upgrade]: struct.Weak.html#method.upgrade
/// [option]: ../../std/option/enum.Option.html
///
/// # Examples
///
@ -636,6 +723,7 @@ impl<T> Weak<T> {
/// use std::sync::Weak;
///
/// let empty: Weak<i64> = Weak::new();
/// assert!(empty.upgrade().is_none());
/// ```
#[stable(feature = "downgraded_weak", since = "1.10.0")]
pub fn new() -> Weak<T> {
@ -652,12 +740,13 @@ impl<T> Weak<T> {
}
impl<T: ?Sized> Weak<T> {
/// Upgrades a weak reference to a strong reference.
/// Upgrades the `Weak` pointer to an [`Arc`][arc], if possible.
///
/// Upgrades the `Weak<T>` reference to an `Arc<T>`, if possible.
/// Returns [`None`][option] if the strong count has reached zero and the
/// inner value was destroyed.
///
/// Returns `None` if there were no strong references and the data was
/// destroyed.
/// [arc]: struct.Arc.html
/// [option]: ../../std/option/enum.Option.html
///
/// # Examples
///
@ -669,6 +758,13 @@ impl<T: ?Sized> Weak<T> {
/// let weak_five = Arc::downgrade(&five);
///
/// let strong_five: Option<Arc<_>> = weak_five.upgrade();
/// assert!(strong_five.is_some());
///
/// // Destroy all strong pointers.
/// drop(strong_five);
/// drop(five);
///
/// assert!(weak_five.upgrade().is_none());
/// ```
#[stable(feature = "arc_weak", since = "1.4.0")]
pub fn upgrade(&self) -> Option<Arc<T>> {
@ -711,9 +807,10 @@ impl<T: ?Sized> Weak<T> {
#[stable(feature = "arc_weak", since = "1.4.0")]
impl<T: ?Sized> Clone for Weak<T> {
/// Makes a clone of the `Weak<T>`.
/// Makes a clone of the `Weak` pointer.
///
/// This increases the weak reference count.
/// This creates another pointer to the same inner value, increasing the
/// weak reference count.
///
/// # Examples
///
@ -745,7 +842,23 @@ impl<T: ?Sized> Clone for Weak<T> {
#[stable(feature = "downgraded_weak", since = "1.10.0")]
impl<T> Default for Weak<T> {
/// Constructs a new `Weak<T>` without an accompanying instance of T.
/// Constructs a new `Weak<T>`, without an accompanying instance of `T`.
///
/// This allocates memory for `T`, but does not initialize it. Calling
/// [`upgrade`][upgrade] on the return value always gives
/// [`None`][option].
///
/// [upgrade]: struct.Weak.html#method.upgrade
/// [option]: ../../std/option/enum.Option.html
///
/// # Examples
///
/// ```
/// use std::sync::Weak;
///
/// let empty: Weak<i64> = Default::default();
/// assert!(empty.upgrade().is_none());
/// ```
fn default() -> Weak<T> {
Weak::new()
}
@ -753,7 +866,7 @@ impl<T> Default for Weak<T> {
#[stable(feature = "arc_weak", since = "1.4.0")]
impl<T: ?Sized> Drop for Weak<T> {
/// Drops the `Weak<T>`.
/// Drops the `Weak` pointer.
///
/// This will decrement the weak reference count.
///
@ -762,21 +875,22 @@ impl<T: ?Sized> Drop for Weak<T> {
/// ```
/// use std::sync::Arc;
///
/// {
/// let five = Arc::new(5);
/// let weak_five = Arc::downgrade(&five);
/// struct Foo;
///
/// // stuff
///
/// drop(weak_five); // explicit drop
/// impl Drop for Foo {
/// fn drop(&mut self) {
/// println!("dropped!");
/// }
/// }
/// {
/// let five = Arc::new(5);
/// let weak_five = Arc::downgrade(&five);
///
/// // stuff
/// let foo = Arc::new(Foo);
/// let weak_foo = Arc::downgrade(&foo);
/// let other_weak_foo = weak_foo.clone();
///
/// } // implicit drop
/// drop(weak_foo); // Doesn't print anything
/// drop(foo); // Prints "dropped!"
///
/// assert!(other_weak_foo.upgrade().is_none());
/// ```
fn drop(&mut self) {
let ptr = *self.ptr;
@ -798,9 +912,9 @@ impl<T: ?Sized> Drop for Weak<T> {
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized + PartialEq> PartialEq for Arc<T> {
/// Equality for two `Arc<T>`s.
/// Equality for two `Arc`s.
///
/// Two `Arc<T>`s are equal if their inner value are equal.
/// Two `Arc`s are equal if their inner values are equal.
///
/// # Examples
///
@ -809,15 +923,15 @@ impl<T: ?Sized + PartialEq> PartialEq for Arc<T> {
///
/// let five = Arc::new(5);
///
/// five == Arc::new(5);
/// assert!(five == Arc::new(5));
/// ```
fn eq(&self, other: &Arc<T>) -> bool {
*(*self) == *(*other)
}
/// Inequality for two `Arc<T>`s.
/// Inequality for two `Arc`s.
///
/// Two `Arc<T>`s are unequal if their inner value are unequal.
/// Two `Arc`s are unequal if their inner values are unequal.
///
/// # Examples
///
@ -826,7 +940,7 @@ impl<T: ?Sized + PartialEq> PartialEq for Arc<T> {
///
/// let five = Arc::new(5);
///
/// five != Arc::new(5);
/// assert!(five != Arc::new(6));
/// ```
fn ne(&self, other: &Arc<T>) -> bool {
*(*self) != *(*other)
@ -834,7 +948,7 @@ impl<T: ?Sized + PartialEq> PartialEq for Arc<T> {
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized + PartialOrd> PartialOrd for Arc<T> {
/// Partial comparison for two `Arc<T>`s.
/// Partial comparison for two `Arc`s.
///
/// The two are compared by calling `partial_cmp()` on their inner values.
///
@ -842,16 +956,17 @@ impl<T: ?Sized + PartialOrd> PartialOrd for Arc<T> {
///
/// ```
/// use std::sync::Arc;
/// use std::cmp::Ordering;
///
/// let five = Arc::new(5);
///
/// five.partial_cmp(&Arc::new(5));
/// assert_eq!(Some(Ordering::Less), five.partial_cmp(&Arc::new(6)));
/// ```
fn partial_cmp(&self, other: &Arc<T>) -> Option<Ordering> {
(**self).partial_cmp(&**other)
}
/// Less-than comparison for two `Arc<T>`s.
/// Less-than comparison for two `Arc`s.
///
/// The two are compared by calling `<` on their inner values.
///
@ -862,13 +977,13 @@ impl<T: ?Sized + PartialOrd> PartialOrd for Arc<T> {
///
/// let five = Arc::new(5);
///
/// five < Arc::new(5);
/// assert!(five < Arc::new(6));
/// ```
fn lt(&self, other: &Arc<T>) -> bool {
*(*self) < *(*other)
}
/// 'Less-than or equal to' comparison for two `Arc<T>`s.
/// 'Less than or equal to' comparison for two `Arc`s.
///
/// The two are compared by calling `<=` on their inner values.
///
@ -879,13 +994,13 @@ impl<T: ?Sized + PartialOrd> PartialOrd for Arc<T> {
///
/// let five = Arc::new(5);
///
/// five <= Arc::new(5);
/// assert!(five <= Arc::new(5));
/// ```
fn le(&self, other: &Arc<T>) -> bool {
*(*self) <= *(*other)
}
/// Greater-than comparison for two `Arc<T>`s.
/// Greater-than comparison for two `Arc`s.
///
/// The two are compared by calling `>` on their inner values.
///
@ -896,13 +1011,13 @@ impl<T: ?Sized + PartialOrd> PartialOrd for Arc<T> {
///
/// let five = Arc::new(5);
///
/// five > Arc::new(5);
/// assert!(five > Arc::new(4));
/// ```
fn gt(&self, other: &Arc<T>) -> bool {
*(*self) > *(*other)
}
/// 'Greater-than or equal to' comparison for two `Arc<T>`s.
/// 'Greater than or equal to' comparison for two `Arc`s.
///
/// The two are compared by calling `>=` on their inner values.
///
@ -913,7 +1028,7 @@ impl<T: ?Sized + PartialOrd> PartialOrd for Arc<T> {
///
/// let five = Arc::new(5);
///
/// five >= Arc::new(5);
/// assert!(five >= Arc::new(5));
/// ```
fn ge(&self, other: &Arc<T>) -> bool {
*(*self) >= *(*other)
@ -921,6 +1036,20 @@ impl<T: ?Sized + PartialOrd> PartialOrd for Arc<T> {
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized + Ord> Ord for Arc<T> {
/// Comparison for two `Arc`s.
///
/// The two are compared by calling `cmp()` on their inner values.
///
/// # Examples
///
/// ```
/// use std::sync::Arc;
/// use std::cmp::Ordering;
///
/// let five = Arc::new(5);
///
/// assert_eq!(Ordering::Less, five.cmp(&Arc::new(6)));
/// ```
fn cmp(&self, other: &Arc<T>) -> Ordering {
(**self).cmp(&**other)
}
@ -951,7 +1080,16 @@ impl<T: ?Sized> fmt::Pointer for Arc<T> {
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: Default> Default for Arc<T> {
/// Creates a new `Arc<T>`, with the `Default` value for T.
/// Creates a new `Arc<T>`, with the `Default` value for `T`.
///
/// # Examples
///
/// ```
/// use std::sync::Arc;
///
/// let x: Arc<i32> = Default::default();
/// assert_eq!(*x, 0);
/// ```
fn default() -> Arc<T> {
Arc::new(Default::default())
}
@ -1002,6 +1140,7 @@ mod tests {
}
#[test]
#[cfg_attr(target_os = "emscripten", ignore)]
fn manually_share_arc() {
let v = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let arc_v = Arc::new(v);

View File

@ -244,12 +244,14 @@ impl<T: ?Sized> Box<T> {
/// the destructor of `T` and free the allocated memory. Since the
/// way `Box` allocates and releases memory is unspecified, the
/// only valid pointer to pass to this function is the one taken
/// from another `Box` via the `Box::into_raw` function.
/// from another `Box` via the [`Box::into_raw`] function.
///
/// This function is unsafe because improper use may lead to
/// memory problems. For example, a double-free may occur if the
/// function is called twice on the same raw pointer.
///
/// [`Box::into_raw`]: struct.Box.html#method.into_raw
///
/// # Examples
///
/// ```
@ -269,12 +271,14 @@ impl<T: ?Sized> Box<T> {
/// memory previously managed by the `Box`. In particular, the
/// caller should properly destroy `T` and release the memory. The
/// proper way to do so is to convert the raw pointer back into a
/// `Box` with the `Box::from_raw` function.
/// `Box` with the [`Box::from_raw`] function.
///
/// Note: this is an associated function, which means that you have
/// to call it as `Box::into_raw(b)` instead of `b.into_raw()`. This
/// is so that there is no conflict with a method on the inner type.
///
/// [`Box::from_raw`]: struct.Box.html#method.from_raw
///
/// # Examples
///
/// ```

View File

@ -88,7 +88,6 @@
#![feature(staged_api)]
#![feature(unboxed_closures)]
#![feature(unique)]
#![cfg_attr(stage0, feature(unsafe_no_drop_flag))]
#![feature(unsize)]
#![cfg_attr(not(test), feature(fused, fn_traits, placement_new_protocol))]

View File

@ -44,7 +44,6 @@ use core::cmp;
/// `shrink_to_fit`, and `from_box` will actually set RawVec's private capacity
/// field. This allows zero-sized types to not be special-cased by consumers of
/// this type.
#[cfg_attr(stage0, unsafe_no_drop_flag)]
pub struct RawVec<T> {
ptr: Unique<T>,
cap: usize,
@ -58,11 +57,7 @@ impl<T> RawVec<T> {
pub fn new() -> Self {
unsafe {
// !0 is usize::MAX. This branch should be stripped at compile time.
let cap = if mem::size_of::<T>() == 0 {
!0
} else {
0
};
let cap = if mem::size_of::<T>() == 0 { !0 } else { 0 };
// heap::EMPTY doubles as "unallocated" and "zero-sized allocation"
RawVec {
@ -210,11 +205,7 @@ impl<T> RawVec<T> {
let (new_cap, ptr) = if self.cap == 0 {
// skip to 4 because tiny Vec's are dumb; but not if that would cause overflow
let new_cap = if elem_size > (!0) / 8 {
1
} else {
4
};
let new_cap = if elem_size > (!0) / 8 { 1 } else { 4 };
let ptr = heap::allocate(new_cap * elem_size, align);
(new_cap, ptr)
} else {
@ -348,7 +339,7 @@ impl<T> RawVec<T> {
let elem_size = mem::size_of::<T>();
// Nothing we can really do about these checks :(
let required_cap = used_cap.checked_add(needed_extra_cap)
.expect("capacity overflow");
.expect("capacity overflow");
// Cannot overflow, because `cap <= isize::MAX`, and type of `cap` is `usize`.
let double_cap = self.cap * 2;
// `double_cap` guarantees exponential growth.

View File

@ -12,12 +12,12 @@
//! Single-threaded reference-counting pointers.
//!
//! The type [`Rc<T>`][rc] provides shared ownership of a value, allocated
//! in the heap. Invoking [`clone`][clone] on `Rc` produces a new pointer
//! to the same value in the heap. When the last `Rc` pointer to a given
//! value is destroyed, the pointed-to value is also destroyed.
//! The type [`Rc<T>`][rc] provides shared ownership of a value of type `T`,
//! allocated in the heap. Invoking [`clone`][clone] on `Rc` produces a new
//! pointer to the same value in the heap. When the last `Rc` pointer to a
//! given value is destroyed, the pointed-to value is also destroyed.
//!
//! Shared pointers in Rust disallow mutation by default, and `Rc` is no
//! Shared references in Rust disallow mutation by default, and `Rc` is no
//! exception. If you need to mutate through an `Rc`, use [`Cell`][cell] or
//! [`RefCell`][refcell].
//!
@ -44,8 +44,9 @@
//! functions][assoc], called using function-like syntax:
//!
//! ```
//! # use std::rc::Rc;
//! # let my_rc = Rc::new(());
//! use std::rc::Rc;
//! let my_rc = Rc::new(());
//!
//! Rc::downgrade(&my_rc);
//! ```
//!
@ -229,13 +230,14 @@ use core::hash::{Hash, Hasher};
use core::intrinsics::{abort, assume};
use core::marker;
use core::marker::Unsize;
use core::mem::{self, align_of_val, forget, size_of_val, uninitialized};
use core::mem::{self, align_of_val, forget, size_of, size_of_val, uninitialized};
use core::ops::Deref;
use core::ops::CoerceUnsized;
use core::ptr::{self, Shared};
use core::convert::From;
use heap::deallocate;
use raw_vec::RawVec;
struct RcBox<T: ?Sized> {
strong: Cell<usize>,
@ -252,7 +254,6 @@ struct RcBox<T: ?Sized> {
/// that you have to call them as e.g. `Rc::get_mut(&value)` instead of
/// `value.get_mut()`. This avoids conflicts with methods of the inner
/// type `T`.
#[cfg_attr(stage0, unsafe_no_drop_flag)]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Rc<T: ?Sized> {
ptr: Shared<RcBox<T>>,
@ -295,10 +296,13 @@ impl<T> Rc<T> {
/// Returns the contained value, if the `Rc` has exactly one strong reference.
///
/// Otherwise, an `Err` is returned with the same `Rc` that was passed in.
/// Otherwise, an [`Err`][result] is returned with the same `Rc` that was
/// passed in.
///
/// This will succeed even if there are outstanding weak references.
///
/// [result]: ../../std/result/enum.Result.html
///
/// # Examples
///
/// ```
@ -332,7 +336,11 @@ impl<T> Rc<T> {
}
}
/// Checks whether `Rc::try_unwrap` would return `Ok`.
/// Checks whether [`Rc::try_unwrap`][try_unwrap] would return
/// [`Ok`][result].
///
/// [try_unwrap]: struct.Rc.html#method.try_unwrap
/// [result]: ../../std/result/enum.Result.html
///
/// # Examples
///
@ -358,6 +366,31 @@ impl<T> Rc<T> {
}
}
impl Rc<str> {
/// Constructs a new `Rc<str>` from a string slice.
#[doc(hidden)]
#[unstable(feature = "rustc_private",
reason = "for internal use in rustc",
issue = "0")]
pub fn __from_str(value: &str) -> Rc<str> {
unsafe {
// Allocate enough space for `RcBox<str>`.
let aligned_len = 2 + (value.len() + size_of::<usize>() - 1) / size_of::<usize>();
let vec = RawVec::<usize>::with_capacity(aligned_len);
let ptr = vec.ptr();
forget(vec);
// Initialize fields of `RcBox<str>`.
*ptr.offset(0) = 1; // strong: Cell::new(1)
*ptr.offset(1) = 1; // weak: Cell::new(1)
ptr::copy_nonoverlapping(value.as_ptr(), ptr.offset(2) as *mut u8, value.len());
// Combine the allocation address and the string length into a fat pointer to `RcBox`.
let rcbox_ptr: *mut RcBox<str> = mem::transmute([ptr as usize, value.len()]);
assert!(aligned_len * size_of::<usize>() == size_of_val(&*rcbox_ptr));
Rc { ptr: Shared::new(rcbox_ptr) }
}
}
}
impl<T: ?Sized> Rc<T> {
/// Creates a new [`Weak`][weak] pointer to this value.
///
@ -583,8 +616,10 @@ impl<T: ?Sized> Drop for Rc<T> {
/// Drops the `Rc`.
///
/// This will decrement the strong reference count. If the strong reference
/// count reaches zero then the only other references (if any) are `Weak`,
/// so we `drop` the inner value.
/// count reaches zero then the only other references (if any) are
/// [`Weak`][weak], so we `drop` the inner value.
///
/// [weak]: struct.Weak.html
///
/// # Examples
///
@ -873,7 +908,6 @@ impl<T> From<T> for Rc<T> {
///
/// [rc]: struct.Rc.html
/// [downgrade]: struct.Rc.html#method.downgrade
#[cfg_attr(stage0, unsafe_no_drop_flag)]
#[stable(feature = "rc_weak", since = "1.4.0")]
pub struct Weak<T: ?Sized> {
ptr: Shared<RcBox<T>>,

View File

@ -27,6 +27,20 @@ fn main() {
let build_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap());
let src_dir = env::current_dir().unwrap();
// FIXME: This is a hack to support building targets that don't
// support jemalloc alongside hosts that do. The jemalloc build is
// controlled by a feature of the std crate, and if that feature
// changes between targets, it invalidates the fingerprint of
// std's build script (this is a cargo bug); so we must ensure
// that the feature set used by std is the same across all
// targets, which means we have to build the alloc_jemalloc crate
// for targets like emscripten, even if we don't use it.
if target.contains("rumprun") || target.contains("bitrig") || target.contains("openbsd") ||
target.contains("msvc") || target.contains("emscripten") || target.contains("fuchsia") {
println!("cargo:rustc-cfg=dummy_jemalloc");
return;
}
if let Some(jemalloc) = env::var_os("JEMALLOC_OVERRIDE") {
let jemalloc = PathBuf::from(jemalloc);
println!("cargo:rustc-link-search=native={}",
@ -46,16 +60,16 @@ fn main() {
// only msvc returns None for ar so unwrap is okay
let ar = build_helper::cc2ar(compiler.path(), &target).unwrap();
let cflags = compiler.args()
.iter()
.map(|s| s.to_str().unwrap())
.collect::<Vec<_>>()
.join(" ");
.iter()
.map(|s| s.to_str().unwrap())
.collect::<Vec<_>>()
.join(" ");
let mut stack = src_dir.join("../jemalloc")
.read_dir()
.unwrap()
.map(|e| e.unwrap())
.collect::<Vec<_>>();
.read_dir()
.unwrap()
.map(|e| e.unwrap())
.collect::<Vec<_>>();
while let Some(entry) = stack.pop() {
let path = entry.path();
if entry.file_type().unwrap().is_dir() {
@ -137,10 +151,10 @@ fn main() {
run(&mut cmd);
run(Command::new("make")
.current_dir(&build_dir)
.arg("build_lib_static")
.arg("-j")
.arg(env::var("NUM_JOBS").expect("NUM_JOBS was not set")));
.current_dir(&build_dir)
.arg("build_lib_static")
.arg("-j")
.arg(env::var("NUM_JOBS").expect("NUM_JOBS was not set")));
if target.contains("windows") {
println!("cargo:rustc-link-lib=static=jemalloc");

View File

@ -23,124 +23,170 @@
extern crate libc;
use libc::{c_int, c_void, size_t};
pub use imp::*;
// Linkage directives to pull in jemalloc and its dependencies.
//
// On some platforms we need to be sure to link in `pthread` which jemalloc
// depends on, and specifically on android we need to also link to libgcc.
// Currently jemalloc is compiled with gcc which will generate calls to
// intrinsics that are libgcc specific (e.g. those intrinsics aren't present in
// libcompiler-rt), so link that in to get that support.
#[link(name = "jemalloc", kind = "static")]
#[cfg_attr(target_os = "android", link(name = "gcc"))]
#[cfg_attr(all(not(windows),
not(target_os = "android"),
not(target_env = "musl")),
link(name = "pthread"))]
#[cfg(not(cargobuild))]
extern "C" {}
// See comments in build.rs for why we sometimes build a crate that does nothing
#[cfg(not(dummy_jemalloc))]
mod imp {
use libc::{c_int, c_void, size_t};
// Note that the symbols here are prefixed by default on OSX and Windows (we
// don't explicitly request it), and on Android and DragonFly we explicitly
// request it as unprefixing cause segfaults (mismatches in allocators).
extern "C" {
#[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
target_os = "dragonfly", target_os = "windows"),
link_name = "je_mallocx")]
fn mallocx(size: size_t, flags: c_int) -> *mut c_void;
#[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
target_os = "dragonfly", target_os = "windows"),
link_name = "je_rallocx")]
fn rallocx(ptr: *mut c_void, size: size_t, flags: c_int) -> *mut c_void;
#[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
target_os = "dragonfly", target_os = "windows"),
link_name = "je_xallocx")]
fn xallocx(ptr: *mut c_void, size: size_t, extra: size_t, flags: c_int) -> size_t;
#[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
target_os = "dragonfly", target_os = "windows"),
link_name = "je_sdallocx")]
fn sdallocx(ptr: *mut c_void, size: size_t, flags: c_int);
#[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
target_os = "dragonfly", target_os = "windows"),
link_name = "je_nallocx")]
fn nallocx(size: size_t, flags: c_int) -> size_t;
}
// Linkage directives to pull in jemalloc and its dependencies.
//
// On some platforms we need to be sure to link in `pthread` which jemalloc
// depends on, and specifically on android we need to also link to libgcc.
// Currently jemalloc is compiled with gcc which will generate calls to
// intrinsics that are libgcc specific (e.g. those intrinsics aren't present in
// libcompiler-rt), so link that in to get that support.
#[link(name = "jemalloc", kind = "static")]
#[cfg_attr(target_os = "android", link(name = "gcc"))]
#[cfg_attr(all(not(windows),
not(target_os = "android"),
not(target_env = "musl")),
link(name = "pthread"))]
#[cfg(not(cargobuild))]
extern "C" {}
// The minimum alignment guaranteed by the architecture. This value is used to
// add fast paths for low alignment values. In practice, the alignment is a
// constant at the call site and the branch will be optimized out.
#[cfg(all(any(target_arch = "arm",
target_arch = "mips",
target_arch = "powerpc")))]
const MIN_ALIGN: usize = 8;
#[cfg(all(any(target_arch = "x86",
target_arch = "x86_64",
target_arch = "aarch64",
target_arch = "powerpc64",
target_arch = "mips64",
target_arch = "s390x")))]
const MIN_ALIGN: usize = 16;
// Note that the symbols here are prefixed by default on OSX and Windows (we
// don't explicitly request it), and on Android and DragonFly we explicitly
// request it as unprefixing cause segfaults (mismatches in allocators).
extern "C" {
#[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
target_os = "dragonfly", target_os = "windows"),
link_name = "je_mallocx")]
fn mallocx(size: size_t, flags: c_int) -> *mut c_void;
#[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
target_os = "dragonfly", target_os = "windows"),
link_name = "je_rallocx")]
fn rallocx(ptr: *mut c_void, size: size_t, flags: c_int) -> *mut c_void;
#[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
target_os = "dragonfly", target_os = "windows"),
link_name = "je_xallocx")]
fn xallocx(ptr: *mut c_void, size: size_t, extra: size_t, flags: c_int) -> size_t;
#[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
target_os = "dragonfly", target_os = "windows"),
link_name = "je_sdallocx")]
fn sdallocx(ptr: *mut c_void, size: size_t, flags: c_int);
#[cfg_attr(any(target_os = "macos", target_os = "android", target_os = "ios",
target_os = "dragonfly", target_os = "windows"),
link_name = "je_nallocx")]
fn nallocx(size: size_t, flags: c_int) -> size_t;
}
// MALLOCX_ALIGN(a) macro
fn mallocx_align(a: usize) -> c_int {
a.trailing_zeros() as c_int
}
// The minimum alignment guaranteed by the architecture. This value is used to
// add fast paths for low alignment values. In practice, the alignment is a
// constant at the call site and the branch will be optimized out.
#[cfg(all(any(target_arch = "arm",
target_arch = "mips",
target_arch = "powerpc")))]
const MIN_ALIGN: usize = 8;
#[cfg(all(any(target_arch = "x86",
target_arch = "x86_64",
target_arch = "aarch64",
target_arch = "powerpc64",
target_arch = "mips64",
target_arch = "s390x")))]
const MIN_ALIGN: usize = 16;
fn align_to_flags(align: usize) -> c_int {
if align <= MIN_ALIGN {
// MALLOCX_ALIGN(a) macro
fn mallocx_align(a: usize) -> c_int {
a.trailing_zeros() as c_int
}
fn align_to_flags(align: usize) -> c_int {
if align <= MIN_ALIGN {
0
} else {
mallocx_align(align)
}
}
#[no_mangle]
pub extern "C" fn __rust_allocate(size: usize, align: usize) -> *mut u8 {
let flags = align_to_flags(align);
unsafe { mallocx(size as size_t, flags) as *mut u8 }
}
#[no_mangle]
pub extern "C" fn __rust_reallocate(ptr: *mut u8,
_old_size: usize,
size: usize,
align: usize)
-> *mut u8 {
let flags = align_to_flags(align);
unsafe { rallocx(ptr as *mut c_void, size as size_t, flags) as *mut u8 }
}
#[no_mangle]
pub extern "C" fn __rust_reallocate_inplace(ptr: *mut u8,
_old_size: usize,
size: usize,
align: usize)
-> usize {
let flags = align_to_flags(align);
unsafe { xallocx(ptr as *mut c_void, size as size_t, 0, flags) as usize }
}
#[no_mangle]
pub extern "C" fn __rust_deallocate(ptr: *mut u8, old_size: usize, align: usize) {
let flags = align_to_flags(align);
unsafe { sdallocx(ptr as *mut c_void, old_size as size_t, flags) }
}
#[no_mangle]
pub extern "C" fn __rust_usable_size(size: usize, align: usize) -> usize {
let flags = align_to_flags(align);
unsafe { nallocx(size as size_t, flags) as usize }
}
// These symbols are used by jemalloc on android but the really old android
// we're building on doesn't have them defined, so just make sure the symbols
// are available.
#[no_mangle]
#[cfg(target_os = "android")]
pub extern "C" fn pthread_atfork(_prefork: *mut u8,
_postfork_parent: *mut u8,
_postfork_child: *mut u8)
-> i32 {
0
} else {
mallocx_align(align)
}
}
#[no_mangle]
pub extern "C" fn __rust_allocate(size: usize, align: usize) -> *mut u8 {
let flags = align_to_flags(align);
unsafe { mallocx(size as size_t, flags) as *mut u8 }
}
#[cfg(dummy_jemalloc)]
mod imp {
fn bogus() -> ! {
panic!("jemalloc is not implemented for this platform");
}
#[no_mangle]
pub extern "C" fn __rust_reallocate(ptr: *mut u8,
_old_size: usize,
size: usize,
align: usize)
-> *mut u8 {
let flags = align_to_flags(align);
unsafe { rallocx(ptr as *mut c_void, size as size_t, flags) as *mut u8 }
}
#[no_mangle]
pub extern "C" fn __rust_allocate(_size: usize, _align: usize) -> *mut u8 {
bogus()
}
#[no_mangle]
pub extern "C" fn __rust_reallocate_inplace(ptr: *mut u8,
_old_size: usize,
size: usize,
align: usize)
-> usize {
let flags = align_to_flags(align);
unsafe { xallocx(ptr as *mut c_void, size as size_t, 0, flags) as usize }
}
#[no_mangle]
pub extern "C" fn __rust_reallocate(_ptr: *mut u8,
_old_size: usize,
_size: usize,
_align: usize)
-> *mut u8 {
bogus()
}
#[no_mangle]
pub extern "C" fn __rust_deallocate(ptr: *mut u8, old_size: usize, align: usize) {
let flags = align_to_flags(align);
unsafe { sdallocx(ptr as *mut c_void, old_size as size_t, flags) }
}
#[no_mangle]
pub extern "C" fn __rust_reallocate_inplace(_ptr: *mut u8,
_old_size: usize,
_size: usize,
_align: usize)
-> usize {
bogus()
}
#[no_mangle]
pub extern "C" fn __rust_usable_size(size: usize, align: usize) -> usize {
let flags = align_to_flags(align);
unsafe { nallocx(size as size_t, flags) as usize }
}
#[no_mangle]
pub extern "C" fn __rust_deallocate(_ptr: *mut u8, _old_size: usize, _align: usize) {
bogus()
}
// These symbols are used by jemalloc on android but the really old android
// we're building on doesn't have them defined, so just make sure the symbols
// are available.
#[no_mangle]
#[cfg(target_os = "android")]
pub extern "C" fn pthread_atfork(_prefork: *mut u8,
_postfork_parent: *mut u8,
_postfork_child: *mut u8)
-> i32 {
0
#[no_mangle]
pub extern "C" fn __rust_usable_size(_size: usize, _align: usize) -> usize {
bogus()
}
}

View File

@ -29,7 +29,8 @@
target_arch = "mips",
target_arch = "powerpc",
target_arch = "powerpc64",
target_arch = "asmjs")))]
target_arch = "asmjs",
target_arch = "wasm32")))]
const MIN_ALIGN: usize = 8;
#[cfg(all(any(target_arch = "x86_64",
target_arch = "aarch64",
@ -165,6 +166,7 @@ mod imp {
fn HeapAlloc(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T) -> LPVOID;
fn HeapReAlloc(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID, dwBytes: SIZE_T) -> LPVOID;
fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID) -> BOOL;
fn GetLastError() -> DWORD;
}
#[repr(C)]
@ -220,11 +222,7 @@ mod imp {
HEAP_REALLOC_IN_PLACE_ONLY,
ptr as LPVOID,
size as SIZE_T) as *mut u8;
if new.is_null() {
old_size
} else {
size
}
if new.is_null() { old_size } else { size }
} else {
old_size
}
@ -233,11 +231,11 @@ mod imp {
pub unsafe fn deallocate(ptr: *mut u8, _old_size: usize, align: usize) {
if align <= MIN_ALIGN {
let err = HeapFree(GetProcessHeap(), 0, ptr as LPVOID);
debug_assert!(err != 0);
debug_assert!(err != 0, "Failed to free heap memory: {}", GetLastError());
} else {
let header = get_header(ptr);
let err = HeapFree(GetProcessHeap(), 0, header.0 as LPVOID);
debug_assert!(err != 0);
debug_assert!(err != 0, "Failed to free heap memory: {}", GetLastError());
}
}

View File

@ -46,6 +46,7 @@ use std::intrinsics;
use std::marker::{PhantomData, Send};
use std::mem;
use std::ptr;
use std::slice;
use alloc::heap;
use alloc::raw_vec::RawVec;
@ -133,7 +134,7 @@ impl<T> TypedArena<T> {
#[inline]
pub fn alloc(&self, object: T) -> &mut T {
if self.ptr == self.end {
self.grow()
self.grow(1)
}
unsafe {
@ -154,24 +155,58 @@ impl<T> TypedArena<T> {
}
}
/// Allocates a slice of objects that are copy into the `TypedArena`, returning a mutable
/// reference to it. Will panic if passed a zero-sized types.
///
/// Panics:
/// - Zero-sized types
/// - Zero-length slices
#[inline]
pub fn alloc_slice(&self, slice: &[T]) -> &mut [T]
where T: Copy {
assert!(mem::size_of::<T>() != 0);
assert!(slice.len() != 0);
let available_capacity_bytes = self.end.get() as usize - self.ptr.get() as usize;
let at_least_bytes = slice.len() * mem::size_of::<T>();
if available_capacity_bytes < at_least_bytes {
self.grow(slice.len());
}
unsafe {
let start_ptr = self.ptr.get();
let arena_slice = slice::from_raw_parts_mut(start_ptr, slice.len());
self.ptr.set(start_ptr.offset(arena_slice.len() as isize));
arena_slice.copy_from_slice(slice);
arena_slice
}
}
/// Grows the arena.
#[inline(never)]
#[cold]
fn grow(&self) {
fn grow(&self, n: usize) {
unsafe {
let mut chunks = self.chunks.borrow_mut();
let (chunk, new_capacity);
let (chunk, mut new_capacity);
if let Some(last_chunk) = chunks.last_mut() {
if last_chunk.storage.double_in_place() {
let used_bytes = self.ptr.get() as usize - last_chunk.start() as usize;
let currently_used_cap = used_bytes / mem::size_of::<T>();
if last_chunk.storage.reserve_in_place(currently_used_cap, n) {
self.end.set(last_chunk.end());
return;
} else {
let prev_capacity = last_chunk.storage.cap();
new_capacity = prev_capacity.checked_mul(2).unwrap();
loop {
new_capacity = prev_capacity.checked_mul(2).unwrap();
if new_capacity >= currently_used_cap + n {
break;
}
}
}
} else {
let elem_size = cmp::max(1, mem::size_of::<T>());
new_capacity = cmp::max(1, PAGE / elem_size);
new_capacity = cmp::max(n, PAGE / elem_size);
}
chunk = TypedArenaChunk::<T>::new(new_capacity);
self.ptr.set(chunk.start());
@ -302,9 +337,8 @@ mod tests {
let arena = Wrap(TypedArena::new());
let result = arena.alloc_outer(|| {
Outer { inner: arena.alloc_inner(|| Inner { value: 10 }) }
});
let result =
arena.alloc_outer(|| Outer { inner: arena.alloc_inner(|| Inner { value: 10 }) });
assert_eq!(result.inner.value, 10);
}

View File

@ -1033,7 +1033,7 @@ pub struct Drain<'a, T: 'a> {
iter: vec::Drain<'a, T>,
}
#[stable(feature = "rust1", since = "1.0.0")]
#[stable(feature = "drain", since = "1.6.0")]
impl<'a, T: 'a> Iterator for Drain<'a, T> {
type Item = T;
@ -1048,7 +1048,7 @@ impl<'a, T: 'a> Iterator for Drain<'a, T> {
}
}
#[stable(feature = "rust1", since = "1.0.0")]
#[stable(feature = "drain", since = "1.6.0")]
impl<'a, T: 'a> DoubleEndedIterator for Drain<'a, T> {
#[inline]
fn next_back(&mut self) -> Option<T> {
@ -1056,7 +1056,7 @@ impl<'a, T: 'a> DoubleEndedIterator for Drain<'a, T> {
}
}
#[stable(feature = "rust1", since = "1.0.0")]
#[stable(feature = "drain", since = "1.6.0")]
impl<'a, T: 'a> ExactSizeIterator for Drain<'a, T> {}
#[unstable(feature = "fused", issue = "35602")]

View File

@ -14,9 +14,10 @@
use core::cmp::Ordering;
use core::hash::{Hash, Hasher};
use core::ops::Deref;
use core::ops::{Add, AddAssign, Deref};
use fmt;
use string::String;
use self::Cow::*;
@ -86,16 +87,29 @@ impl<T> ToOwned for T where T: Clone {
/// ```
/// use std::borrow::Cow;
///
/// # #[allow(dead_code)]
/// fn abs_all(input: &mut Cow<[i32]>) {
/// for i in 0..input.len() {
/// let v = input[i];
/// if v < 0 {
/// // clones into a vector the first time (if not already owned)
/// // Clones into a vector if not already owned.
/// input.to_mut()[i] = -v;
/// }
/// }
/// }
///
/// // No clone occurs because `input` doesn't need to be mutated.
/// let slice = [0, 1, 2];
/// let mut input = Cow::from(&slice[..]);
/// abs_all(&mut input);
///
/// // Clone occurs because `input` needs to be mutated.
/// let slice = [-1, 0, 1];
/// let mut input = Cow::from(&slice[..]);
/// abs_all(&mut input);
///
/// // No clone occurs because `input` is already owned.
/// let mut input = Cow::from(vec![-1, 0, 1]);
/// abs_all(&mut input);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub enum Cow<'a, B: ?Sized + 'a>
@ -146,7 +160,10 @@ impl<'a, B: ?Sized> Cow<'a, B> where B: ToOwned {
match *self {
Borrowed(borrowed) => {
*self = Owned(borrowed.to_owned());
self.to_mut()
match *self {
Borrowed(..) => unreachable!(),
Owned(ref mut owned) => owned,
}
}
Owned(ref mut owned) => owned,
}
@ -270,3 +287,61 @@ impl<'a, T: ?Sized + ToOwned> AsRef<T> for Cow<'a, T> {
self
}
}
#[stable(feature = "cow_add", since = "1.14.0")]
impl<'a> Add<&'a str> for Cow<'a, str> {
type Output = Cow<'a, str>;
#[inline]
fn add(mut self, rhs: &'a str) -> Self::Output {
self += rhs;
self
}
}
#[stable(feature = "cow_add", since = "1.14.0")]
impl<'a> Add<Cow<'a, str>> for Cow<'a, str> {
type Output = Cow<'a, str>;
#[inline]
fn add(mut self, rhs: Cow<'a, str>) -> Self::Output {
self += rhs;
self
}
}
#[stable(feature = "cow_add", since = "1.14.0")]
impl<'a> AddAssign<&'a str> for Cow<'a, str> {
fn add_assign(&mut self, rhs: &'a str) {
if self.is_empty() {
*self = Cow::Borrowed(rhs)
} else if rhs.is_empty() {
return;
} else {
if let Cow::Borrowed(lhs) = *self {
let mut s = String::with_capacity(lhs.len() + rhs.len());
s.push_str(lhs);
*self = Cow::Owned(s);
}
self.to_mut().push_str(rhs);
}
}
}
#[stable(feature = "cow_add", since = "1.14.0")]
impl<'a> AddAssign<Cow<'a, str>> for Cow<'a, str> {
fn add_assign(&mut self, rhs: Cow<'a, str>) {
if self.is_empty() {
*self = rhs
} else if rhs.is_empty() {
return;
} else {
if let Cow::Borrowed(lhs) = *self {
let mut s = String::with_capacity(lhs.len() + rhs.len());
s.push_str(lhs);
*self = Cow::Owned(s);
}
self.to_mut().push_str(&rhs);
}
}
}

View File

@ -136,6 +136,7 @@ pub struct BTreeMap<K, V> {
length: usize,
}
#[stable(feature = "btree_drop", since = "1.7.0")]
impl<K, V> Drop for BTreeMap<K, V> {
#[unsafe_destructor_blind_to_params]
fn drop(&mut self) {
@ -146,6 +147,7 @@ impl<K, V> Drop for BTreeMap<K, V> {
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<K: Clone, V: Clone> Clone for BTreeMap<K, V> {
fn clone(&self) -> BTreeMap<K, V> {
fn clone_subtree<K: Clone, V: Clone>(node: node::NodeRef<marker::Immut,
@ -1125,6 +1127,7 @@ impl<K: Ord, V> BTreeMap<K, V> {
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, K: 'a, V: 'a> IntoIterator for &'a BTreeMap<K, V> {
type Item = (&'a K, &'a V);
type IntoIter = Iter<'a, K, V>;
@ -1134,6 +1137,7 @@ impl<'a, K: 'a, V: 'a> IntoIterator for &'a BTreeMap<K, V> {
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, K: 'a, V: 'a> Iterator for Iter<'a, K, V> {
type Item = (&'a K, &'a V);
@ -1154,6 +1158,7 @@ impl<'a, K: 'a, V: 'a> Iterator for Iter<'a, K, V> {
#[unstable(feature = "fused", issue = "35602")]
impl<'a, K, V> FusedIterator for Iter<'a, K, V> {}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, K: 'a, V: 'a> DoubleEndedIterator for Iter<'a, K, V> {
fn next_back(&mut self) -> Option<(&'a K, &'a V)> {
if self.length == 0 {
@ -1165,12 +1170,14 @@ impl<'a, K: 'a, V: 'a> DoubleEndedIterator for Iter<'a, K, V> {
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, K: 'a, V: 'a> ExactSizeIterator for Iter<'a, K, V> {
fn len(&self) -> usize {
self.length
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, K, V> Clone for Iter<'a, K, V> {
fn clone(&self) -> Iter<'a, K, V> {
Iter {
@ -1180,6 +1187,7 @@ impl<'a, K, V> Clone for Iter<'a, K, V> {
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, K: 'a, V: 'a> IntoIterator for &'a mut BTreeMap<K, V> {
type Item = (&'a K, &'a mut V);
type IntoIter = IterMut<'a, K, V>;
@ -1189,6 +1197,7 @@ impl<'a, K: 'a, V: 'a> IntoIterator for &'a mut BTreeMap<K, V> {
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, K: 'a, V: 'a> Iterator for IterMut<'a, K, V> {
type Item = (&'a K, &'a mut V);
@ -1206,6 +1215,7 @@ impl<'a, K: 'a, V: 'a> Iterator for IterMut<'a, K, V> {
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, K: 'a, V: 'a> DoubleEndedIterator for IterMut<'a, K, V> {
fn next_back(&mut self) -> Option<(&'a K, &'a mut V)> {
if self.length == 0 {
@ -1217,6 +1227,7 @@ impl<'a, K: 'a, V: 'a> DoubleEndedIterator for IterMut<'a, K, V> {
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, K: 'a, V: 'a> ExactSizeIterator for IterMut<'a, K, V> {
fn len(&self) -> usize {
self.length
@ -1226,6 +1237,7 @@ impl<'a, K: 'a, V: 'a> ExactSizeIterator for IterMut<'a, K, V> {
#[unstable(feature = "fused", issue = "35602")]
impl<'a, K, V> FusedIterator for IterMut<'a, K, V> {}
#[stable(feature = "rust1", since = "1.0.0")]
impl<K, V> IntoIterator for BTreeMap<K, V> {
type Item = (K, V);
type IntoIter = IntoIter<K, V>;
@ -1244,6 +1256,7 @@ impl<K, V> IntoIterator for BTreeMap<K, V> {
}
}
#[stable(feature = "btree_drop", since = "1.7.0")]
impl<K, V> Drop for IntoIter<K, V> {
fn drop(&mut self) {
for _ in &mut *self {
@ -1260,6 +1273,7 @@ impl<K, V> Drop for IntoIter<K, V> {
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<K, V> Iterator for IntoIter<K, V> {
type Item = (K, V);
@ -1304,6 +1318,7 @@ impl<K, V> Iterator for IntoIter<K, V> {
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<K, V> DoubleEndedIterator for IntoIter<K, V> {
fn next_back(&mut self) -> Option<(K, V)> {
if self.length == 0 {
@ -1342,6 +1357,7 @@ impl<K, V> DoubleEndedIterator for IntoIter<K, V> {
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<K, V> ExactSizeIterator for IntoIter<K, V> {
fn len(&self) -> usize {
self.length
@ -1351,6 +1367,7 @@ impl<K, V> ExactSizeIterator for IntoIter<K, V> {
#[unstable(feature = "fused", issue = "35602")]
impl<K, V> FusedIterator for IntoIter<K, V> {}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, K, V> Iterator for Keys<'a, K, V> {
type Item = &'a K;
@ -1363,12 +1380,14 @@ impl<'a, K, V> Iterator for Keys<'a, K, V> {
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, K, V> DoubleEndedIterator for Keys<'a, K, V> {
fn next_back(&mut self) -> Option<&'a K> {
self.inner.next_back().map(|(k, _)| k)
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, K, V> ExactSizeIterator for Keys<'a, K, V> {
fn len(&self) -> usize {
self.inner.len()
@ -1378,12 +1397,14 @@ impl<'a, K, V> ExactSizeIterator for Keys<'a, K, V> {
#[unstable(feature = "fused", issue = "35602")]
impl<'a, K, V> FusedIterator for Keys<'a, K, V> {}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, K, V> Clone for Keys<'a, K, V> {
fn clone(&self) -> Keys<'a, K, V> {
Keys { inner: self.inner.clone() }
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, K, V> Iterator for Values<'a, K, V> {
type Item = &'a V;
@ -1396,12 +1417,14 @@ impl<'a, K, V> Iterator for Values<'a, K, V> {
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, K, V> DoubleEndedIterator for Values<'a, K, V> {
fn next_back(&mut self) -> Option<&'a V> {
self.inner.next_back().map(|(_, v)| v)
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, K, V> ExactSizeIterator for Values<'a, K, V> {
fn len(&self) -> usize {
self.inner.len()
@ -1411,6 +1434,7 @@ impl<'a, K, V> ExactSizeIterator for Values<'a, K, V> {
#[unstable(feature = "fused", issue = "35602")]
impl<'a, K, V> FusedIterator for Values<'a, K, V> {}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, K, V> Clone for Values<'a, K, V> {
fn clone(&self) -> Values<'a, K, V> {
Values { inner: self.inner.clone() }
@ -1635,6 +1659,7 @@ impl<'a, K, V> RangeMut<'a, K, V> {
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<K: Ord, V> FromIterator<(K, V)> for BTreeMap<K, V> {
fn from_iter<T: IntoIterator<Item = (K, V)>>(iter: T) -> BTreeMap<K, V> {
let mut map = BTreeMap::new();
@ -1643,6 +1668,7 @@ impl<K: Ord, V> FromIterator<(K, V)> for BTreeMap<K, V> {
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<K: Ord, V> Extend<(K, V)> for BTreeMap<K, V> {
#[inline]
fn extend<T: IntoIterator<Item = (K, V)>>(&mut self, iter: T) {
@ -1652,12 +1678,14 @@ impl<K: Ord, V> Extend<(K, V)> for BTreeMap<K, V> {
}
}
#[stable(feature = "extend_ref", since = "1.2.0")]
impl<'a, K: Ord + Copy, V: Copy> Extend<(&'a K, &'a V)> for BTreeMap<K, V> {
fn extend<I: IntoIterator<Item = (&'a K, &'a V)>>(&mut self, iter: I) {
self.extend(iter.into_iter().map(|(&key, &value)| (key, value)));
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<K: Hash, V: Hash> Hash for BTreeMap<K, V> {
fn hash<H: Hasher>(&self, state: &mut H) {
for elt in self {
@ -1666,6 +1694,7 @@ impl<K: Hash, V: Hash> Hash for BTreeMap<K, V> {
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<K: Ord, V> Default for BTreeMap<K, V> {
/// Creates an empty `BTreeMap<K, V>`.
fn default() -> BTreeMap<K, V> {
@ -1673,14 +1702,17 @@ impl<K: Ord, V> Default for BTreeMap<K, V> {
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<K: PartialEq, V: PartialEq> PartialEq for BTreeMap<K, V> {
fn eq(&self, other: &BTreeMap<K, V>) -> bool {
self.len() == other.len() && self.iter().zip(other).all(|(a, b)| a == b)
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<K: Eq, V: Eq> Eq for BTreeMap<K, V> {}
#[stable(feature = "rust1", since = "1.0.0")]
impl<K: PartialOrd, V: PartialOrd> PartialOrd for BTreeMap<K, V> {
#[inline]
fn partial_cmp(&self, other: &BTreeMap<K, V>) -> Option<Ordering> {
@ -1688,6 +1720,7 @@ impl<K: PartialOrd, V: PartialOrd> PartialOrd for BTreeMap<K, V> {
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<K: Ord, V: Ord> Ord for BTreeMap<K, V> {
#[inline]
fn cmp(&self, other: &BTreeMap<K, V>) -> Ordering {
@ -1695,12 +1728,14 @@ impl<K: Ord, V: Ord> Ord for BTreeMap<K, V> {
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<K: Debug, V: Debug> Debug for BTreeMap<K, V> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_map().entries(self.iter()).finish()
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, K: Ord, Q: ?Sized, V> Index<&'a Q> for BTreeMap<K, V>
where K: Borrow<Q>,
Q: Ord

View File

@ -779,6 +779,7 @@ impl<T: Debug> Debug for BTreeSet<T> {
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T> Clone for Iter<'a, T> {
fn clone(&self) -> Iter<'a, T> {
Iter { iter: self.iter.clone() }
@ -864,6 +865,7 @@ fn cmp_opt<T: Ord>(x: Option<&T>, y: Option<&T>, short: Ordering, long: Ordering
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T> Clone for Difference<'a, T> {
fn clone(&self) -> Difference<'a, T> {
Difference {
@ -901,6 +903,7 @@ impl<'a, T: Ord> Iterator for Difference<'a, T> {
#[unstable(feature = "fused", issue = "35602")]
impl<'a, T: Ord> FusedIterator for Difference<'a, T> {}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T> Clone for SymmetricDifference<'a, T> {
fn clone(&self) -> SymmetricDifference<'a, T> {
SymmetricDifference {
@ -934,6 +937,7 @@ impl<'a, T: Ord> Iterator for SymmetricDifference<'a, T> {
#[unstable(feature = "fused", issue = "35602")]
impl<'a, T: Ord> FusedIterator for SymmetricDifference<'a, T> {}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T> Clone for Intersection<'a, T> {
fn clone(&self) -> Intersection<'a, T> {
Intersection {
@ -977,6 +981,7 @@ impl<'a, T: Ord> Iterator for Intersection<'a, T> {
#[unstable(feature = "fused", issue = "35602")]
impl<'a, T: Ord> FusedIterator for Intersection<'a, T> {}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T> Clone for Union<'a, T> {
fn clone(&self) -> Union<'a, T> {
Union {

View File

@ -48,7 +48,6 @@ impl<E> Clone for EnumSet<E> {
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<E: CLike + fmt::Debug> fmt::Debug for EnumSet<E> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_set().entries(self).finish()
@ -277,7 +276,6 @@ impl<E: CLike> FromIterator<E> for EnumSet<E> {
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, E> IntoIterator for &'a EnumSet<E> where E: CLike
{
type Item = E;
@ -296,7 +294,6 @@ impl<E: CLike> Extend<E> for EnumSet<E> {
}
}
#[stable(feature = "extend_ref", since = "1.2.0")]
impl<'a, E: 'a + CLike + Copy> Extend<&'a E> for EnumSet<E> {
fn extend<I: IntoIterator<Item = &'a E>>(&mut self, iter: I) {
self.extend(iter.into_iter().cloned());

View File

@ -261,8 +261,8 @@
//! This and `writeln` are two macros which are used to emit the format string
//! to a specified stream. This is used to prevent intermediate allocations of
//! format strings and instead directly write the output. Under the hood, this
//! function is actually invoking the `write` function defined in this module.
//! Example usage is:
//! function is actually invoking the `write_fmt` function defined on the
//! `std::io::Write` trait. Example usage is:
//!
//! ```
//! # #![allow(unused_must_use)]
@ -327,7 +327,7 @@
//! format := '{' [ argument ] [ ':' format_spec ] '}'
//! argument := integer | identifier
//!
//! format_spec := [[fill]align][sign]['#'][0][width]['.' precision][type]
//! format_spec := [[fill]align][sign]['#']['0'][width]['.' precision][type]
//! fill := character
//! align := '<' | '^' | '>'
//! sign := '+' | '-'

View File

@ -50,9 +50,9 @@
#![feature(specialization)]
#![feature(staged_api)]
#![feature(step_by)]
#![feature(trusted_len)]
#![feature(unicode)]
#![feature(unique)]
#![cfg_attr(stage0, feature(unsafe_no_drop_flag))]
#![cfg_attr(test, feature(rand, test))]
#![no_std]

View File

@ -1294,6 +1294,7 @@ mod tests {
}
#[test]
#[cfg_attr(target_os = "emscripten", ignore)]
fn test_send() {
let n = list_from(&[1, 2, 3]);
thread::spawn(move || {

View File

@ -68,7 +68,9 @@ macro_rules! vec {
}
/// Use the syntax described in `std::fmt` to create a value of type `String`.
/// See `std::fmt` for more information.
/// See [`std::fmt`][fmt] for more information.
///
/// [fmt]: ../std/fmt/index.html
///
/// # Examples
///

View File

@ -36,7 +36,7 @@
//!
//! ## Structs
//!
//! There are several structs that are useful for slices, such as `Iter`, which
//! There are several structs that are useful for slices, such as [`Iter`], which
//! represents iteration over a slice.
//!
//! ## Trait Implementations
@ -44,9 +44,9 @@
//! There are several implementations of common traits for slices. Some examples
//! include:
//!
//! * `Clone`
//! * `Eq`, `Ord` - for slices whose element type are `Eq` or `Ord`.
//! * `Hash` - for slices whose element type is `Hash`
//! * [`Clone`]
//! * [`Eq`], [`Ord`] - for slices whose element type are [`Eq`] or [`Ord`].
//! * [`Hash`] - for slices whose element type is [`Hash`].
//!
//! ## Iteration
//!
@ -73,12 +73,24 @@
//! the element type of the slice is `i32`, the element type of the iterator is
//! `&mut i32`.
//!
//! * `.iter()` and `.iter_mut()` are the explicit methods to return the default
//! * [`.iter()`] and [`.iter_mut()`] are the explicit methods to return the default
//! iterators.
//! * Further methods that return iterators are `.split()`, `.splitn()`,
//! `.chunks()`, `.windows()` and more.
//! * Further methods that return iterators are [`.split()`], [`.splitn()`],
//! [`.chunks()`], [`.windows()`] and more.
//!
//! *[See also the slice primitive type](../../std/primitive.slice.html).*
//!
//! [`Clone`]: ../../std/clone/trait.Clone.html
//! [`Eq`]: ../../std/cmp/trait.Eq.html
//! [`Ord`]: ../../std/cmp/trait.Ord.html
//! [`Iter`]: struct.Iter.html
//! [`Hash`]: ../../std/hash/trait.Hash.html
//! [`.iter()`]: ../../std/primitive.slice.html#method.iter
//! [`.iter_mut()`]: ../../std/primitive.slice.html#method.iter_mut
//! [`.split()`]: ../../std/primitive.slice.html#method.split
//! [`.splitn()`]: ../../std/primitive.slice.html#method.splitn
//! [`.chunks()`]: ../../std/primitive.slice.html#method.chunks
//! [`.windows()`]: ../../std/primitive.slice.html#method.windows
#![stable(feature = "rust1", since = "1.0.0")]
// Many of the usings in this module are only used in the test configuration.
@ -168,7 +180,7 @@ impl<T> [T] {
core_slice::SliceExt::len(self)
}
/// Returns true if the slice has a length of 0
/// Returns true if the slice has a length of 0.
///
/// # Example
///
@ -402,7 +414,7 @@ impl<T> [T] {
core_slice::SliceExt::get_unchecked_mut(self, index)
}
/// Returns an raw pointer to the slice's buffer
/// Returns an raw pointer to the slice's buffer.
///
/// The caller must ensure that the slice outlives the pointer this
/// function returns, or else it will end up pointing to garbage.
@ -468,7 +480,7 @@ impl<T> [T] {
///
/// # Examples
///
/// ```rust
/// ```
/// let mut v = ["a", "b", "c", "d"];
/// v.swap(1, 3);
/// assert!(v == ["a", "d", "c", "b"]);
@ -483,7 +495,7 @@ impl<T> [T] {
///
/// # Example
///
/// ```rust
/// ```
/// let mut v = [1, 2, 3];
/// v.reverse();
/// assert!(v == [3, 2, 1]);
@ -567,9 +579,9 @@ impl<T> [T] {
}
/// Returns an iterator over `size` elements of the slice at a
/// time. The chunks are slices and do not overlap. If `size` does not divide the
/// length of the slice, then the last chunk will not have length
/// `size`.
/// time. The chunks are slices and do not overlap. If `size` does
/// not divide the length of the slice, then the last chunk will
/// not have length `size`.
///
/// # Panics
///
@ -656,7 +668,7 @@ impl<T> [T] {
///
/// # Examples
///
/// ```rust
/// ```
/// let mut v = [1, 2, 3, 4, 5, 6];
///
/// // scoped to restrict the lifetime of the borrows
@ -754,7 +766,7 @@ impl<T> [T] {
}
/// Returns an iterator over subslices separated by elements that match
/// `pred`, limited to returning at most `n` items. The matched element is
/// `pred`, limited to returning at most `n` items. The matched element is
/// not contained in the subslices.
///
/// The last element returned, if any, will contain the remainder of the
@ -781,7 +793,7 @@ impl<T> [T] {
}
/// Returns an iterator over subslices separated by elements that match
/// `pred`, limited to returning at most `n` items. The matched element is
/// `pred`, limited to returning at most `n` items. The matched element is
/// not contained in the subslices.
///
/// The last element returned, if any, will contain the remainder of the
@ -835,7 +847,7 @@ impl<T> [T] {
/// Returns an iterator over subslices separated by elements that match
/// `pred` limited to returning at most `n` items. This starts at the end of
/// the slice and works backwards. The matched element is not contained in
/// the slice and works backwards. The matched element is not contained in
/// the subslices.
///
/// The last element returned, if any, will contain the remainder of the
@ -922,9 +934,9 @@ impl<T> [T] {
///
/// Looks up a series of four elements. The first is found, with a
/// uniquely determined position; the second and third are not
/// found; the fourth could match any position in `[1,4]`.
/// found; the fourth could match any position in `[1, 4]`.
///
/// ```rust
/// ```
/// let s = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55];
///
/// assert_eq!(s.binary_search(&13), Ok(9));
@ -956,9 +968,9 @@ impl<T> [T] {
///
/// Looks up a series of four elements. The first is found, with a
/// uniquely determined position; the second and third are not
/// found; the fourth could match any position in `[1,4]`.
/// found; the fourth could match any position in `[1, 4]`.
///
/// ```rust
/// ```
/// let s = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55];
///
/// let seek = 13;
@ -982,21 +994,23 @@ impl<T> [T] {
/// Binary search a sorted slice with a key extraction function.
///
/// Assumes that the slice is sorted by the key, for instance with
/// `sort_by_key` using the same key extraction function.
/// [`sort_by_key`] using the same key extraction function.
///
/// If a matching value is found then returns `Ok`, containing the
/// index for the matched element; if no match is found then `Err`
/// is returned, containing the index where a matching element could
/// be inserted while maintaining sorted order.
///
/// [`sort_by_key`]: #method.sort_by_key
///
/// # Examples
///
/// Looks up a series of four elements in a slice of pairs sorted by
/// their second elements. The first is found, with a uniquely
/// determined position; the second and third are not found; the
/// fourth could match any position in `[1,4]`.
/// fourth could match any position in `[1, 4]`.
///
/// ```rust
/// ```
/// let s = [(0, 0), (2, 1), (4, 1), (5, 1), (3, 1),
/// (1, 2), (2, 3), (4, 5), (5, 8), (3, 13),
/// (1, 21), (2, 34), (4, 55)];
@ -1023,7 +1037,7 @@ impl<T> [T] {
///
/// # Examples
///
/// ```rust
/// ```
/// let mut v = [-5, 4, 1, -3, 2];
///
/// v.sort();
@ -1045,7 +1059,7 @@ impl<T> [T] {
///
/// # Examples
///
/// ```rust
/// ```
/// let mut v = [-5i32, 4, 1, -3, 2];
///
/// v.sort_by_key(|k| k.abs());
@ -1067,7 +1081,7 @@ impl<T> [T] {
///
/// # Examples
///
/// ```rust
/// ```
/// let mut v = [5, 4, 1, 3, 2];
/// v.sort_by(|a, b| a.cmp(b));
/// assert!(v == [1, 2, 3, 4, 5]);
@ -1094,7 +1108,7 @@ impl<T> [T] {
///
/// # Example
///
/// ```rust
/// ```
/// let mut dst = [0, 0, 0];
/// let src = [1, 2, 3];
///
@ -1116,7 +1130,7 @@ impl<T> [T] {
///
/// # Example
///
/// ```rust
/// ```
/// let mut dst = [0, 0, 0];
/// let src = [1, 2, 3];
///
@ -1156,7 +1170,7 @@ impl<T> [T] {
/// let x = s.into_vec();
/// // `s` cannot be used anymore because it has been converted into `x`.
///
/// assert_eq!(x, vec!(10, 40, 30));
/// assert_eq!(x, vec![10, 40, 30]);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]

View File

@ -122,7 +122,7 @@ pub struct EncodeUtf16<'a> {
encoder: Utf16Encoder<Chars<'a>>,
}
#[stable(feature = "rust1", since = "1.0.0")]
#[stable(feature = "encode_utf16", since = "1.8.0")]
impl<'a> Iterator for EncodeUtf16<'a> {
type Item = u16;
@ -697,7 +697,7 @@ impl str {
///
/// Basic usage:
///
/// ```rust
/// ```
/// let bananas = "bananas";
///
/// assert!(bananas.ends_with("anas"));
@ -900,7 +900,7 @@ impl str {
///
/// It does _not_ give you:
///
/// ```rust,ignore
/// ```,ignore
/// assert_eq!(d, &["a", "b", "c"]);
/// ```
///
@ -1053,10 +1053,10 @@ impl str {
}
/// An iterator over substrings of the given string slice, separated by a
/// pattern, restricted to returning at most `count` items.
/// pattern, restricted to returning at most `n` items.
///
/// The last element returned, if any, will contain the remainder of the
/// string slice.
/// If `n` substrings are returned, the last substring (the `n`th substring)
/// will contain the remainder of the string.
///
/// The pattern can be a `&str`, [`char`], or a closure that determines the
/// split.
@ -1098,16 +1098,16 @@ impl str {
/// assert_eq!(v, ["abc", "defXghi"]);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn splitn<'a, P: Pattern<'a>>(&'a self, count: usize, pat: P) -> SplitN<'a, P> {
core_str::StrExt::splitn(self, count, pat)
pub fn splitn<'a, P: Pattern<'a>>(&'a self, n: usize, pat: P) -> SplitN<'a, P> {
core_str::StrExt::splitn(self, n, pat)
}
/// An iterator over substrings of this string slice, separated by a
/// pattern, starting from the end of the string, restricted to returning
/// at most `count` items.
/// at most `n` items.
///
/// The last element returned, if any, will contain the remainder of the
/// string slice.
/// If `n` substrings are returned, the last substring (the `n`th substring)
/// will contain the remainder of the string.
///
/// The pattern can be a `&str`, [`char`], or a closure that
/// determines the split.
@ -1145,10 +1145,10 @@ impl str {
/// assert_eq!(v, ["ghi", "abc1def"]);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn rsplitn<'a, P: Pattern<'a>>(&'a self, count: usize, pat: P) -> RSplitN<'a, P>
pub fn rsplitn<'a, P: Pattern<'a>>(&'a self, n: usize, pat: P) -> RSplitN<'a, P>
where P::Searcher: ReverseSearcher<'a>
{
core_str::StrExt::rsplitn(self, count, pat)
core_str::StrExt::rsplitn(self, n, pat)
}
/// An iterator over the matches of a pattern within the given string
@ -1789,4 +1789,24 @@ impl str {
String::from_utf8_unchecked(slice.into_vec())
}
}
/// Create a [`String`] by repeating a string `n` times.
///
/// [`String`]: string/struct.String.html
///
/// # Examples
///
/// Basic usage:
///
/// ```
/// #![feature(repeat_str)]
///
/// assert_eq!("abc".repeat(4), String::from("abcabcabcabc"));
/// ```
#[unstable(feature = "repeat_str", issue = "37079")]
pub fn repeat(&self, n: usize) -> String {
let mut s = String::with_capacity(self.len() * n);
s.extend((0..n).map(|_| self));
s
}
}

View File

@ -14,24 +14,25 @@
//! [`ToString`]s, and several error types that may result from working with
//! [`String`]s.
//!
//! [`String`]: struct.String.html
//! [`ToString`]: trait.ToString.html
//!
//! # Examples
//!
//! There are multiple ways to create a new `String` from a string literal:
//! There are multiple ways to create a new [`String`] from a string literal:
//!
//! ```rust
//! ```
//! let s = "Hello".to_string();
//!
//! let s = String::from("world");
//! let s: String = "also this".into();
//! ```
//!
//! You can create a new `String` from an existing one by concatenating with
//! You can create a new [`String`] from an existing one by concatenating with
//! `+`:
//!
//! ```rust
//! [`String`]: struct.String.html
//!
//! ```
//! let s = "Hello".to_string();
//!
//! let message = s + " world!";
@ -40,7 +41,7 @@
//! If you have a vector of valid UTF-8 bytes, you can make a `String` out of
//! it. You can do the reverse too.
//!
//! ```rust
//! ```
//! let sparkle_heart = vec![240, 159, 146, 150];
//!
//! // We know these bytes are valid, so we'll use `unwrap()`.
@ -134,10 +135,10 @@ use boxed::Box;
/// Indexing is intended to be a constant-time operation, but UTF-8 encoding
/// does not allow us to do this. Furthermore, it's not clear what sort of
/// thing the index should return: a byte, a codepoint, or a grapheme cluster.
/// The [`as_bytes()`] and [`chars()`] methods return iterators over the first
/// The [`bytes()`] and [`chars()`] methods return iterators over the first
/// two, respectively.
///
/// [`as_bytes()`]: #method.as_bytes
/// [`bytes()`]: #method.bytes
/// [`chars()`]: #method.chars
///
/// # Deref
@ -975,7 +976,7 @@ impl String {
pub fn push(&mut self, ch: char) {
match ch.len_utf8() {
1 => self.vec.push(ch as u8),
_ => self.vec.extend_from_slice(ch.encode_utf8().as_slice()),
_ => self.vec.extend_from_slice(ch.encode_utf8(&mut [0;4]).as_bytes()),
}
}
@ -1131,10 +1132,11 @@ impl String {
let len = self.len();
assert!(idx <= len);
assert!(self.is_char_boundary(idx));
let bits = ch.encode_utf8();
let mut bits = [0; 4];
let bits = ch.encode_utf8(&mut bits).as_bytes();
unsafe {
self.insert_bytes(idx, bits.as_slice());
self.insert_bytes(idx, bits);
}
}
@ -1858,6 +1860,13 @@ impl<'a> From<&'a str> for String {
}
}
#[stable(feature = "string_from_cow_str", since = "1.14.0")]
impl<'a> From<Cow<'a, str>> for String {
fn from(s: Cow<'a, str>) -> String {
s.into_owned()
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a> From<&'a str> for Cow<'a, str> {
#[inline]
@ -1895,10 +1904,10 @@ impl<'a> FromIterator<String> for Cow<'a, str> {
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl Into<Vec<u8>> for String {
fn into(self) -> Vec<u8> {
self.into_bytes()
#[stable(feature = "from_string_for_vec_u8", since = "1.14.0")]
impl From<String> for Vec<u8> {
fn from(string : String) -> Vec<u8> {
string.into_bytes()
}
}

View File

@ -16,13 +16,13 @@
//!
//! # Examples
//!
//! You can explicitly create a `Vec<T>` with `new()`:
//! You can explicitly create a [`Vec<T>`] with [`new()`]:
//!
//! ```
//! let v: Vec<i32> = Vec::new();
//! ```
//!
//! ...or by using the `vec!` macro:
//! ...or by using the [`vec!`] macro:
//!
//! ```
//! let v: Vec<i32> = vec![];
@ -32,7 +32,7 @@
//! let v = vec![0; 10]; // ten zeroes
//! ```
//!
//! You can `push` values onto the end of a vector (which will grow the vector
//! You can [`push`] values onto the end of a vector (which will grow the vector
//! as needed):
//!
//! ```
@ -49,13 +49,20 @@
//! let two = v.pop();
//! ```
//!
//! Vectors also support indexing (through the `Index` and `IndexMut` traits):
//! Vectors also support indexing (through the [`Index`] and [`IndexMut`] traits):
//!
//! ```
//! let mut v = vec![1, 2, 3];
//! let three = v[2];
//! v[1] = v[1] + 5;
//! ```
//!
//! [`Vec<T>`]: ../../std/vec/struct.Vec.html
//! [`new()`]: ../../std/vec/struct.Vec.html#method.new
//! [`push`]: ../../std/vec/struct.Vec.html#method.push
//! [`Index`]: ../../std/ops/trait.Index.html
//! [`IndexMut`]: ../../std/ops/trait.IndexMut.html
//! [`vec!`]: ../../std/macro.vec.html
#![stable(feature = "rust1", since = "1.0.0")]
@ -68,7 +75,7 @@ use core::cmp::Ordering;
use core::fmt;
use core::hash::{self, Hash};
use core::intrinsics::{arith_offset, assume};
use core::iter::{FromIterator, FusedIterator};
use core::iter::{FromIterator, FusedIterator, TrustedLen};
use core::mem;
use core::ops::{Index, IndexMut};
use core::ops;
@ -76,10 +83,9 @@ use core::ptr;
use core::ptr::Shared;
use core::slice;
use super::SpecExtend;
use super::range::RangeArgument;
/// A contiguous growable array type, written `Vec<T>` but pronounced 'vector.'
/// A contiguous growable array type, written `Vec<T>` but pronounced 'vector'.
///
/// # Examples
///
@ -105,7 +111,7 @@ use super::range::RangeArgument;
/// assert_eq!(vec, [7, 1, 2, 3]);
/// ```
///
/// The `vec!` macro is provided to make initialization more convenient:
/// The [`vec!`] macro is provided to make initialization more convenient:
///
/// ```
/// let mut vec = vec![1, 2, 3];
@ -137,19 +143,19 @@ use super::range::RangeArgument;
///
/// # Indexing
///
/// The Vec type allows to access values by index, because it implements the
/// `Index` trait. An example will be more explicit:
/// The `Vec` type allows to access values by index, because it implements the
/// [`Index`] trait. An example will be more explicit:
///
/// ```
/// let v = vec!(0, 2, 4, 6);
/// let v = vec![0, 2, 4, 6];
/// println!("{}", v[1]); // it will display '2'
/// ```
///
/// However be careful: if you try to access an index which isn't in the Vec,
/// However be careful: if you try to access an index which isn't in the `Vec`,
/// your software will panic! You cannot do this:
///
/// ```ignore
/// let v = vec!(0, 2, 4, 6);
/// let v = vec![0, 2, 4, 6];
/// println!("{}", v[6]); // it will panic!
/// ```
///
@ -158,15 +164,15 @@ use super::range::RangeArgument;
///
/// # Slicing
///
/// A Vec can be mutable. Slices, on the other hand, are read-only objects.
/// To get a slice, use "&". Example:
/// A `Vec` can be mutable. Slices, on the other hand, are read-only objects.
/// To get a slice, use `&`. Example:
///
/// ```
/// fn read_slice(slice: &[usize]) {
/// // ...
/// }
///
/// let v = vec!(0, 1);
/// let v = vec![0, 1];
/// read_slice(&v);
///
/// // ... and that's all!
@ -175,8 +181,8 @@ use super::range::RangeArgument;
/// ```
///
/// In Rust, it's more common to pass slices as arguments rather than vectors
/// when you just want to provide a read access. The same goes for String and
/// &str.
/// when you just want to provide a read access. The same goes for [`String`] and
/// [`&str`].
///
/// # Capacity and reallocation
///
@ -191,84 +197,100 @@ use super::range::RangeArgument;
/// with space for 10 more elements. Pushing 10 or fewer elements onto the
/// vector will not change its capacity or cause reallocation to occur. However,
/// if the vector's length is increased to 11, it will have to reallocate, which
/// can be slow. For this reason, it is recommended to use `Vec::with_capacity`
/// can be slow. For this reason, it is recommended to use [`Vec::with_capacity`]
/// whenever possible to specify how big the vector is expected to get.
///
/// # Guarantees
///
/// Due to its incredibly fundamental nature, Vec makes a lot of guarantees
/// Due to its incredibly fundamental nature, `Vec` makes a lot of guarantees
/// about its design. This ensures that it's as low-overhead as possible in
/// the general case, and can be correctly manipulated in primitive ways
/// by unsafe code. Note that these guarantees refer to an unqualified `Vec<T>`.
/// If additional type parameters are added (e.g. to support custom allocators),
/// overriding their defaults may change the behavior.
///
/// Most fundamentally, Vec is and always will be a (pointer, capacity, length)
/// Most fundamentally, `Vec` is and always will be a (pointer, capacity, length)
/// triplet. No more, no less. The order of these fields is completely
/// unspecified, and you should use the appropriate methods to modify these.
/// The pointer will never be null, so this type is null-pointer-optimized.
///
/// However, the pointer may not actually point to allocated memory. In particular,
/// if you construct a Vec with capacity 0 via `Vec::new()`, `vec![]`,
/// `Vec::with_capacity(0)`, or by calling `shrink_to_fit()` on an empty Vec, it
/// will not allocate memory. Similarly, if you store zero-sized types inside
/// a Vec, it will not allocate space for them. *Note that in this case the
/// Vec may not report a `capacity()` of 0*. Vec will allocate if and only
/// if `mem::size_of::<T>() * capacity() > 0`. In general, Vec's allocation
/// if you construct a `Vec` with capacity 0 via [`Vec::new()`], [`vec![]`][`vec!`],
/// [`Vec::with_capacity(0)`][`Vec::with_capacity`], or by calling [`shrink_to_fit()`]
/// on an empty Vec, it will not allocate memory. Similarly, if you store zero-sized
/// types inside a `Vec`, it will not allocate space for them. *Note that in this case
/// the `Vec` may not report a [`capacity()`] of 0*. `Vec` will allocate if and only
/// if [`mem::size_of::<T>()`]` * capacity() > 0`. In general, `Vec`'s allocation
/// details are subtle enough that it is strongly recommended that you only
/// free memory allocated by a Vec by creating a new Vec and dropping it.
/// free memory allocated by a `Vec` by creating a new `Vec` and dropping it.
///
/// If a Vec *has* allocated memory, then the memory it points to is on the heap
/// If a `Vec` *has* allocated memory, then the memory it points to is on the heap
/// (as defined by the allocator Rust is configured to use by default), and its
/// pointer points to `len()` initialized elements in order (what you would see
/// if you coerced it to a slice), followed by `capacity() - len()` logically
/// uninitialized elements.
/// pointer points to [`len()`] initialized elements in order (what you would see
/// if you coerced it to a slice), followed by [`capacity()`]` - `[`len()`]
/// logically uninitialized elements.
///
/// Vec will never perform a "small optimization" where elements are actually
/// `Vec` will never perform a "small optimization" where elements are actually
/// stored on the stack for two reasons:
///
/// * It would make it more difficult for unsafe code to correctly manipulate
/// a Vec. The contents of a Vec wouldn't have a stable address if it were
/// only moved, and it would be more difficult to determine if a Vec had
/// a `Vec`. The contents of a `Vec` wouldn't have a stable address if it were
/// only moved, and it would be more difficult to determine if a `Vec` had
/// actually allocated memory.
///
/// * It would penalize the general case, incurring an additional branch
/// on every access.
///
/// Vec will never automatically shrink itself, even if completely empty. This
/// ensures no unnecessary allocations or deallocations occur. Emptying a Vec
/// and then filling it back up to the same `len()` should incur no calls to
/// the allocator. If you wish to free up unused memory, use `shrink_to_fit`.
/// `Vec` will never automatically shrink itself, even if completely empty. This
/// ensures no unnecessary allocations or deallocations occur. Emptying a `Vec`
/// and then filling it back up to the same [`len()`] should incur no calls to
/// the allocator. If you wish to free up unused memory, use
/// [`shrink_to_fit`][`shrink_to_fit()`].
///
/// `push` and `insert` will never (re)allocate if the reported capacity is
/// sufficient. `push` and `insert` *will* (re)allocate if `len() == capacity()`.
/// That is, the reported capacity is completely accurate, and can be relied on.
/// It can even be used to manually free the memory allocated by a Vec if
/// desired. Bulk insertion methods *may* reallocate, even when not necessary.
/// [`push`] and [`insert`] will never (re)allocate if the reported capacity is
/// sufficient. [`push`] and [`insert`] *will* (re)allocate if
/// [`len()`]` == `[`capacity()`]. That is, the reported capacity is completely
/// accurate, and can be relied on. It can even be used to manually free the memory
/// allocated by a `Vec` if desired. Bulk insertion methods *may* reallocate, even
/// when not necessary.
///
/// Vec does not guarantee any particular growth strategy when reallocating
/// when full, nor when `reserve` is called. The current strategy is basic
/// `Vec` does not guarantee any particular growth strategy when reallocating
/// when full, nor when [`reserve`] is called. The current strategy is basic
/// and it may prove desirable to use a non-constant growth factor. Whatever
/// strategy is used will of course guarantee `O(1)` amortized `push`.
/// strategy is used will of course guarantee `O(1)` amortized [`push`].
///
/// `vec![x; n]`, `vec![a, b, c, d]`, and `Vec::with_capacity(n)`, will all
/// produce a Vec with exactly the requested capacity. If `len() == capacity()`,
/// (as is the case for the `vec!` macro), then a `Vec<T>` can be converted
/// to and from a `Box<[T]>` without reallocating or moving the elements.
/// `vec![x; n]`, `vec![a, b, c, d]`, and
/// [`Vec::with_capacity(n)`][`Vec::with_capacity`], will all produce a `Vec`
/// with exactly the requested capacity. If [`len()`]` == `[`capacity()`],
/// (as is the case for the [`vec!`] macro), then a `Vec<T>` can be converted to
/// and from a [`Box<[T]>`][owned slice] without reallocating or moving the elements.
///
/// Vec will not specifically overwrite any data that is removed from it,
/// `Vec` will not specifically overwrite any data that is removed from it,
/// but also won't specifically preserve it. Its uninitialized memory is
/// scratch space that it may use however it wants. It will generally just do
/// whatever is most efficient or otherwise easy to implement. Do not rely on
/// removed data to be erased for security purposes. Even if you drop a Vec, its
/// buffer may simply be reused by another Vec. Even if you zero a Vec's memory
/// removed data to be erased for security purposes. Even if you drop a `Vec`, its
/// buffer may simply be reused by another `Vec`. Even if you zero a `Vec`'s memory
/// first, that may not actually happen because the optimizer does not consider
/// this a side-effect that must be preserved.
///
/// Vec does not currently guarantee the order in which elements are dropped
/// `Vec` does not currently guarantee the order in which elements are dropped
/// (the order has changed in the past, and may change again).
///
#[cfg_attr(stage0, unsafe_no_drop_flag)]
/// [`vec!`]: ../../std/macro.vec.html
/// [`Index`]: ../../std/ops/trait.Index.html
/// [`String`]: ../../std/string/struct.String.html
/// [`&str`]: ../../std/primitive.str.html
/// [`Vec::with_capacity`]: ../../std/vec/struct.Vec.html#method.with_capacity
/// [`Vec::new()`]: ../../std/vec/struct.Vec.html#method.new
/// [`shrink_to_fit()`]: ../../std/vec/struct.Vec.html#method.shrink_to_fit
/// [`capacity()`]: ../../std/vec/struct.Vec.html#method.capacity
/// [`mem::size_of::<T>()`]: ../../std/mem/fn.size_of.html
/// [`len()`]: ../../std/vec/struct.Vec.html#method.len
/// [`push`]: ../../std/vec/struct.Vec.html#method.push
/// [`insert`]: ../../std/vec/struct.Vec.html#method.insert
/// [`reserve`]: ../../std/vec/struct.Vec.html#method.reserve
/// [owned slice]: ../../std/boxed/struct.Box.html
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Vec<T> {
buf: RawVec<T>,
@ -305,9 +327,10 @@ impl<T> Vec<T> {
/// reallocating. If `capacity` is 0, the vector will not allocate.
///
/// It is important to note that this function does not specify the *length*
/// of the returned vector, but only the *capacity*. (For an explanation of
/// the difference between length and capacity, see the main `Vec<T>` docs
/// above, 'Capacity and reallocation'.)
/// of the returned vector, but only the *capacity*. For an explanation of
/// the difference between length and capacity, see *[Capacity and reallocation]*.
///
/// [Capacity and reallocation]: #capacity-and-reallocation
///
/// # Examples
///
@ -341,7 +364,7 @@ impl<T> Vec<T> {
/// This is highly unsafe, due to the number of invariants that aren't
/// checked:
///
/// * `ptr` needs to have been previously allocated via `String`/`Vec<T>`
/// * `ptr` needs to have been previously allocated via [`String`]/`Vec<T>`
/// (at least, it's highly likely to be incorrect if it wasn't).
/// * `length` needs to be less than or equal to `capacity`.
/// * `capacity` needs to be the capacity that the pointer was allocated with.
@ -355,6 +378,8 @@ impl<T> Vec<T> {
/// that nothing else uses the pointer after calling this
/// function.
///
/// [`String`]: ../../std/string/struct.String.html
///
/// # Examples
///
/// ```
@ -471,11 +496,15 @@ impl<T> Vec<T> {
self.buf.shrink_to_fit(self.len);
}
/// Converts the vector into Box<[T]>.
/// Converts the vector into [`Box<[T]>`][owned slice].
///
/// Note that this will drop any excess capacity. Calling this and
/// converting back to a vector with `into_vec()` is equivalent to calling
/// `shrink_to_fit()`.
/// converting back to a vector with [`into_vec()`] is equivalent to calling
/// [`shrink_to_fit()`].
///
/// [owned slice]: ../../std/boxed/struct.Box.html
/// [`into_vec()`]: ../../std/primitive.slice.html#method.into_vec
/// [`shrink_to_fit()`]: #method.shrink_to_fit
///
/// # Examples
///
@ -674,7 +703,7 @@ impl<T> Vec<T> {
///
/// # Panics
///
/// Panics if `index` is greater than the vector's length.
/// Panics if `index` is out of bounds.
///
/// # Examples
///
@ -749,7 +778,7 @@ impl<T> Vec<T> {
/// Retains only the elements specified by the predicate.
///
/// In other words, remove all elements `e` such that `f(&e)` returns false.
/// In other words, remove all elements `e` such that `f(&e)` returns `false`.
/// This method operates in place and preserves the order of the retained
/// elements.
///
@ -782,6 +811,130 @@ impl<T> Vec<T> {
}
}
/// Removes consecutive elements in the vector that resolve to the same key.
///
/// If the vector is sorted, this removes all duplicates.
///
/// # Examples
///
/// ```
/// #![feature(dedup_by)]
///
/// let mut vec = vec![10, 20, 21, 30, 20];
///
/// vec.dedup_by_key(|i| *i / 10);
///
/// assert_eq!(vec, [10, 20, 30, 20]);
/// ```
#[unstable(feature = "dedup_by", reason = "recently added", issue = "37087")]
#[inline]
pub fn dedup_by_key<F, K>(&mut self, mut key: F) where F: FnMut(&mut T) -> K, K: PartialEq {
self.dedup_by(|a, b| key(a) == key(b))
}
/// Removes consecutive elements in the vector that resolve to the same key.
///
/// If the vector is sorted, this removes all duplicates.
///
/// # Examples
///
/// ```
/// #![feature(dedup_by)]
/// use std::ascii::AsciiExt;
///
/// let mut vec = vec!["foo", "bar", "Bar", "baz", "bar"];
///
/// vec.dedup_by(|a, b| a.eq_ignore_ascii_case(b));
///
/// assert_eq!(vec, ["foo", "bar", "baz", "bar"]);
/// ```
#[unstable(feature = "dedup_by", reason = "recently added", issue = "37087")]
pub fn dedup_by<F>(&mut self, mut same_bucket: F) where F: FnMut(&mut T, &mut T) -> bool {
unsafe {
// Although we have a mutable reference to `self`, we cannot make
// *arbitrary* changes. The `same_bucket` calls could panic, so we
// must ensure that the vector is in a valid state at all time.
//
// The way that we handle this is by using swaps; we iterate
// over all the elements, swapping as we go so that at the end
// the elements we wish to keep are in the front, and those we
// wish to reject are at the back. We can then truncate the
// vector. This operation is still O(n).
//
// Example: We start in this state, where `r` represents "next
// read" and `w` represents "next_write`.
//
// r
// +---+---+---+---+---+---+
// | 0 | 1 | 1 | 2 | 3 | 3 |
// +---+---+---+---+---+---+
// w
//
// Comparing self[r] against self[w-1], this is not a duplicate, so
// we swap self[r] and self[w] (no effect as r==w) and then increment both
// r and w, leaving us with:
//
// r
// +---+---+---+---+---+---+
// | 0 | 1 | 1 | 2 | 3 | 3 |
// +---+---+---+---+---+---+
// w
//
// Comparing self[r] against self[w-1], this value is a duplicate,
// so we increment `r` but leave everything else unchanged:
//
// r
// +---+---+---+---+---+---+
// | 0 | 1 | 1 | 2 | 3 | 3 |
// +---+---+---+---+---+---+
// w
//
// Comparing self[r] against self[w-1], this is not a duplicate,
// so swap self[r] and self[w] and advance r and w:
//
// r
// +---+---+---+---+---+---+
// | 0 | 1 | 2 | 1 | 3 | 3 |
// +---+---+---+---+---+---+
// w
//
// Not a duplicate, repeat:
//
// r
// +---+---+---+---+---+---+
// | 0 | 1 | 2 | 3 | 1 | 3 |
// +---+---+---+---+---+---+
// w
//
// Duplicate, advance r. End of vec. Truncate to w.
let ln = self.len();
if ln <= 1 {
return;
}
// Avoid bounds checks by using raw pointers.
let p = self.as_mut_ptr();
let mut r: usize = 1;
let mut w: usize = 1;
while r < ln {
let p_r = p.offset(r as isize);
let p_wm1 = p.offset((w - 1) as isize);
if !same_bucket(&mut *p_r, &mut *p_wm1) {
if r != w {
let p_w = p_wm1.offset(1);
mem::swap(&mut *p_r, &mut *p_w);
}
w += 1;
}
r += 1;
}
self.truncate(w);
}
}
/// Appends an element to the back of a collection.
///
/// # Panics
@ -810,9 +963,11 @@ impl<T> Vec<T> {
}
}
/// Removes the last element from a vector and returns it, or `None` if it
/// Removes the last element from a vector and returns it, or [`None`] if it
/// is empty.
///
/// [`None`]: ../../std/option/enum.Option.html#variant.None
///
/// # Examples
///
/// ```
@ -1089,26 +1244,7 @@ impl<T: Clone> Vec<T> {
/// ```
#[stable(feature = "vec_extend_from_slice", since = "1.6.0")]
pub fn extend_from_slice(&mut self, other: &[T]) {
self.reserve(other.len());
// Unsafe code so this can be optimised to a memcpy (or something
// similarly fast) when T is Copy. LLVM is easily confused, so any
// extra operations during the loop can prevent this optimisation.
unsafe {
let len = self.len();
let ptr = self.get_unchecked_mut(len) as *mut T;
// Use SetLenOnDrop to work around bug where compiler
// may not realize the store through `ptr` trough self.set_len()
// don't alias.
let mut local_len = SetLenOnDrop::new(&mut self.len);
for i in 0..other.len() {
ptr::write(ptr.offset(i as isize), other.get_unchecked(i).clone());
local_len.increment_len(1);
}
// len set by scope guard
}
self.extend(other.iter().cloned())
}
}
@ -1156,90 +1292,9 @@ impl<T: PartialEq> Vec<T> {
/// assert_eq!(vec, [1, 2, 3, 2]);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn dedup(&mut self) {
unsafe {
// Although we have a mutable reference to `self`, we cannot make
// *arbitrary* changes. The `PartialEq` comparisons could panic, so we
// must ensure that the vector is in a valid state at all time.
//
// The way that we handle this is by using swaps; we iterate
// over all the elements, swapping as we go so that at the end
// the elements we wish to keep are in the front, and those we
// wish to reject are at the back. We can then truncate the
// vector. This operation is still O(n).
//
// Example: We start in this state, where `r` represents "next
// read" and `w` represents "next_write`.
//
// r
// +---+---+---+---+---+---+
// | 0 | 1 | 1 | 2 | 3 | 3 |
// +---+---+---+---+---+---+
// w
//
// Comparing self[r] against self[w-1], this is not a duplicate, so
// we swap self[r] and self[w] (no effect as r==w) and then increment both
// r and w, leaving us with:
//
// r
// +---+---+---+---+---+---+
// | 0 | 1 | 1 | 2 | 3 | 3 |
// +---+---+---+---+---+---+
// w
//
// Comparing self[r] against self[w-1], this value is a duplicate,
// so we increment `r` but leave everything else unchanged:
//
// r
// +---+---+---+---+---+---+
// | 0 | 1 | 1 | 2 | 3 | 3 |
// +---+---+---+---+---+---+
// w
//
// Comparing self[r] against self[w-1], this is not a duplicate,
// so swap self[r] and self[w] and advance r and w:
//
// r
// +---+---+---+---+---+---+
// | 0 | 1 | 2 | 1 | 3 | 3 |
// +---+---+---+---+---+---+
// w
//
// Not a duplicate, repeat:
//
// r
// +---+---+---+---+---+---+
// | 0 | 1 | 2 | 3 | 1 | 3 |
// +---+---+---+---+---+---+
// w
//
// Duplicate, advance r. End of vec. Truncate to w.
let ln = self.len();
if ln <= 1 {
return;
}
// Avoid bounds checks by using raw pointers.
let p = self.as_mut_ptr();
let mut r: usize = 1;
let mut w: usize = 1;
while r < ln {
let p_r = p.offset(r as isize);
let p_wm1 = p.offset((w - 1) as isize);
if *p_r != *p_wm1 {
if r != w {
let p_w = p_wm1.offset(1);
mem::swap(&mut *p_r, &mut *p_w);
}
w += 1;
}
r += 1;
}
self.truncate(w);
}
self.dedup_by(|a, b| a == b)
}
}
@ -1531,19 +1586,25 @@ impl<'a, T> IntoIterator for &'a mut Vec<T> {
impl<T> Extend<T> for Vec<T> {
#[inline]
fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
<Self as SpecExtend<I>>::spec_extend(self, iter);
}
}
impl<I: IntoIterator> SpecExtend<I> for Vec<I::Item> {
default fn spec_extend(&mut self, iter: I) {
self.extend_desugared(iter.into_iter())
}
}
impl<T> SpecExtend<Vec<T>> for Vec<T> {
fn spec_extend(&mut self, ref mut other: Vec<T>) {
self.append(other);
trait IsTrustedLen : Iterator {
fn trusted_len(&self) -> Option<usize> { None }
}
impl<I> IsTrustedLen for I where I: Iterator { }
impl<I> IsTrustedLen for I where I: TrustedLen
{
fn trusted_len(&self) -> Option<usize> {
let (low, high) = self.size_hint();
if let Some(high_value) = high {
debug_assert_eq!(low, high_value,
"TrustedLen iterator's size hint is not exact: {:?}",
(low, high));
}
high
}
}
@ -1554,16 +1615,30 @@ impl<T> Vec<T> {
// for item in iterator {
// self.push(item);
// }
while let Some(element) = iterator.next() {
let len = self.len();
if len == self.capacity() {
let (lower, _) = iterator.size_hint();
self.reserve(lower.saturating_add(1));
}
if let Some(additional) = iterator.trusted_len() {
self.reserve(additional);
unsafe {
ptr::write(self.get_unchecked_mut(len), element);
// NB can't overflow since we would have had to alloc the address space
self.set_len(len + 1);
let mut ptr = self.as_mut_ptr().offset(self.len() as isize);
let mut local_len = SetLenOnDrop::new(&mut self.len);
for element in iterator {
ptr::write(ptr, element);
ptr = ptr.offset(1);
// NB can't overflow since we would have had to alloc the address space
local_len.increment_len(1);
}
}
} else {
while let Some(element) = iterator.next() {
let len = self.len();
if len == self.capacity() {
let (lower, _) = iterator.size_hint();
self.reserve(lower.saturating_add(1));
}
unsafe {
ptr::write(self.get_unchecked_mut(len), element);
// NB can't overflow since we would have had to alloc the address space
self.set_len(len + 1);
}
}
}
}
@ -1572,7 +1647,7 @@ impl<T> Vec<T> {
#[stable(feature = "extend_ref", since = "1.2.0")]
impl<'a, T: 'a + Copy> Extend<&'a T> for Vec<T> {
fn extend<I: IntoIterator<Item = &'a T>>(&mut self, iter: I) {
self.extend(iter.into_iter().cloned());
self.extend(iter.into_iter().map(|&x| x))
}
}
@ -1705,6 +1780,13 @@ impl<'a, T: Clone> From<&'a [T]> for Vec<T> {
}
}
#[stable(feature = "vec_from_cow_slice", since = "1.14.0")]
impl<'a, T> From<Cow<'a, [T]>> for Vec<T> where [T]: ToOwned<Owned=Vec<T>> {
fn from(s: Cow<'a, [T]>) -> Vec<T> {
s.into_owned()
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a> From<&'a str> for Vec<u8> {
fn from(s: &'a str) -> Vec<u8> {
@ -1756,7 +1838,7 @@ pub struct IntoIter<T> {
end: *const T,
}
#[stable(feature = "vec_intoiter_debug", since = "")]
#[stable(feature = "vec_intoiter_debug", since = "1.13.0")]
impl<T: fmt::Debug> fmt::Debug for IntoIter<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_tuple("IntoIter")
@ -1770,7 +1852,7 @@ impl<T> IntoIter<T> {
///
/// # Examples
///
/// ```rust
/// ```
/// # #![feature(vec_into_iter_as_slice)]
/// let vec = vec!['a', 'b', 'c'];
/// let mut into_iter = vec.into_iter();
@ -1789,7 +1871,7 @@ impl<T> IntoIter<T> {
///
/// # Examples
///
/// ```rust
/// ```
/// # #![feature(vec_into_iter_as_slice)]
/// let vec = vec!['a', 'b', 'c'];
/// let mut into_iter = vec.into_iter();
@ -1889,6 +1971,9 @@ impl<T> ExactSizeIterator for IntoIter<T> {}
#[unstable(feature = "fused", issue = "35602")]
impl<T> FusedIterator for IntoIter<T> {}
#[unstable(feature = "trusted_len", issue = "37572")]
unsafe impl<T> TrustedLen for IntoIter<T> {}
#[stable(feature = "vec_into_iter_clone", since = "1.8.0")]
impl<T: Clone> Clone for IntoIter<T> {
fn clone(&self) -> IntoIter<T> {
@ -1930,7 +2015,7 @@ unsafe impl<'a, T: Sync> Sync for Drain<'a, T> {}
#[stable(feature = "drain", since = "1.6.0")]
unsafe impl<'a, T: Send> Send for Drain<'a, T> {}
#[stable(feature = "rust1", since = "1.0.0")]
#[stable(feature = "drain", since = "1.6.0")]
impl<'a, T> Iterator for Drain<'a, T> {
type Item = T;
@ -1944,7 +2029,7 @@ impl<'a, T> Iterator for Drain<'a, T> {
}
}
#[stable(feature = "rust1", since = "1.0.0")]
#[stable(feature = "drain", since = "1.6.0")]
impl<'a, T> DoubleEndedIterator for Drain<'a, T> {
#[inline]
fn next_back(&mut self) -> Option<T> {
@ -1952,7 +2037,7 @@ impl<'a, T> DoubleEndedIterator for Drain<'a, T> {
}
}
#[stable(feature = "rust1", since = "1.0.0")]
#[stable(feature = "drain", since = "1.6.0")]
impl<'a, T> Drop for Drain<'a, T> {
fn drop(&mut self) {
// exhaust self first
@ -1974,7 +2059,7 @@ impl<'a, T> Drop for Drain<'a, T> {
}
#[stable(feature = "rust1", since = "1.0.0")]
#[stable(feature = "drain", since = "1.6.0")]
impl<'a, T> ExactSizeIterator for Drain<'a, T> {}
#[unstable(feature = "fused", issue = "35602")]

View File

@ -743,16 +743,8 @@ impl<T> VecDeque<T> {
#[stable(feature = "deque_extras_15", since = "1.5.0")]
pub fn as_slices(&self) -> (&[T], &[T]) {
unsafe {
let contiguous = self.is_contiguous();
let buf = self.buffer_as_slice();
if contiguous {
let (empty, buf) = buf.split_at(0);
(&buf[self.tail..self.head], empty)
} else {
let (mid, right) = buf.split_at(self.tail);
let (left, _) = mid.split_at(self.head);
(right, left)
}
RingSlices::ring_slices(buf, self.head, self.tail)
}
}
@ -780,20 +772,10 @@ impl<T> VecDeque<T> {
#[stable(feature = "deque_extras_15", since = "1.5.0")]
pub fn as_mut_slices(&mut self) -> (&mut [T], &mut [T]) {
unsafe {
let contiguous = self.is_contiguous();
let head = self.head;
let tail = self.tail;
let buf = self.buffer_as_mut_slice();
if contiguous {
let (empty, buf) = buf.split_at_mut(0);
(&mut buf[tail..head], empty)
} else {
let (mid, right) = buf.split_at_mut(tail);
let (left, _) = mid.split_at_mut(head);
(right, left)
}
RingSlices::ring_slices(buf, head, tail)
}
}
@ -1829,6 +1811,42 @@ fn wrap_index(index: usize, size: usize) -> usize {
index & (size - 1)
}
/// Returns the two slices that cover the VecDeque's valid range
trait RingSlices : Sized {
fn slice(self, from: usize, to: usize) -> Self;
fn split_at(self, i: usize) -> (Self, Self);
fn ring_slices(buf: Self, head: usize, tail: usize) -> (Self, Self) {
let contiguous = tail <= head;
if contiguous {
let (empty, buf) = buf.split_at(0);
(buf.slice(tail, head), empty)
} else {
let (mid, right) = buf.split_at(tail);
let (left, _) = mid.split_at(head);
(right, left)
}
}
}
impl<'a, T> RingSlices for &'a [T] {
fn slice(self, from: usize, to: usize) -> Self {
&self[from..to]
}
fn split_at(self, i: usize) -> (Self, Self) {
(*self).split_at(i)
}
}
impl<'a, T> RingSlices for &'a mut [T] {
fn slice(self, from: usize, to: usize) -> Self {
&mut self[from..to]
}
fn split_at(self, i: usize) -> (Self, Self) {
(*self).split_at_mut(i)
}
}
/// Calculate the number of elements left to be read in the buffer
#[inline]
fn count(tail: usize, head: usize, size: usize) -> usize {
@ -1875,6 +1893,14 @@ impl<'a, T> Iterator for Iter<'a, T> {
let len = count(self.tail, self.head, self.ring.len());
(len, Some(len))
}
fn fold<Acc, F>(self, mut accum: Acc, mut f: F) -> Acc
where F: FnMut(Acc, Self::Item) -> Acc,
{
let (front, back) = RingSlices::ring_slices(self.ring, self.head, self.tail);
accum = front.iter().fold(accum, &mut f);
back.iter().fold(accum, &mut f)
}
}
#[stable(feature = "rust1", since = "1.0.0")]
@ -1927,6 +1953,14 @@ impl<'a, T> Iterator for IterMut<'a, T> {
let len = count(self.tail, self.head, self.ring.len());
(len, Some(len))
}
fn fold<Acc, F>(self, mut accum: Acc, mut f: F) -> Acc
where F: FnMut(Acc, Self::Item) -> Acc,
{
let (front, back) = RingSlices::ring_slices(self.ring, self.head, self.tail);
accum = front.iter_mut().fold(accum, &mut f);
back.iter_mut().fold(accum, &mut f)
}
}
#[stable(feature = "rust1", since = "1.0.0")]
@ -2002,7 +2036,7 @@ unsafe impl<'a, T: Sync> Sync for Drain<'a, T> {}
#[stable(feature = "drain", since = "1.6.0")]
unsafe impl<'a, T: Send> Send for Drain<'a, T> {}
#[stable(feature = "rust1", since = "1.0.0")]
#[stable(feature = "drain", since = "1.6.0")]
impl<'a, T: 'a> Drop for Drain<'a, T> {
fn drop(&mut self) {
for _ in self.by_ref() {}
@ -2051,7 +2085,7 @@ impl<'a, T: 'a> Drop for Drain<'a, T> {
}
}
#[stable(feature = "rust1", since = "1.0.0")]
#[stable(feature = "drain", since = "1.6.0")]
impl<'a, T: 'a> Iterator for Drain<'a, T> {
type Item = T;
@ -2066,7 +2100,7 @@ impl<'a, T: 'a> Iterator for Drain<'a, T> {
}
}
#[stable(feature = "rust1", since = "1.0.0")]
#[stable(feature = "drain", since = "1.6.0")]
impl<'a, T: 'a> DoubleEndedIterator for Drain<'a, T> {
#[inline]
fn next_back(&mut self) -> Option<T> {
@ -2074,7 +2108,7 @@ impl<'a, T: 'a> DoubleEndedIterator for Drain<'a, T> {
}
}
#[stable(feature = "rust1", since = "1.0.0")]
#[stable(feature = "drain", since = "1.6.0")]
impl<'a, T: 'a> ExactSizeIterator for Drain<'a, T> {}
#[unstable(feature = "fused", issue = "35602")]

View File

@ -299,5 +299,7 @@ fn test_extend_specialization() {
#[allow(dead_code)]
fn assert_covariance() {
fn drain<'new>(d: Drain<'static, &'static str>) -> Drain<'new, &'new str> { d }
fn drain<'new>(d: Drain<'static, &'static str>) -> Drain<'new, &'new str> {
d
}
}

View File

@ -533,9 +533,7 @@ create_append_test!(test_append_1700, 1700);
fn rand_data(len: usize) -> Vec<(u32, u32)> {
let mut rng = DeterministicRng::new();
Vec::from_iter(
(0..len).map(|_| (rng.next(), rng.next()))
)
Vec::from_iter((0..len).map(|_| (rng.next(), rng.next())))
}
#[test]

View File

@ -25,7 +25,7 @@ impl DeterministicRng {
x: 0x193a6754,
y: 0xa8a7d469,
z: 0x97830e05,
w: 0x113ba7bb
w: 0x113ba7bb,
}
}

View File

@ -15,45 +15,51 @@ use super::DeterministicRng;
#[test]
fn test_clone_eq() {
let mut m = BTreeSet::new();
let mut m = BTreeSet::new();
m.insert(1);
m.insert(2);
m.insert(1);
m.insert(2);
assert!(m.clone() == m);
assert!(m.clone() == m);
}
#[test]
fn test_hash() {
let mut x = BTreeSet::new();
let mut y = BTreeSet::new();
let mut x = BTreeSet::new();
let mut y = BTreeSet::new();
x.insert(1);
x.insert(2);
x.insert(3);
x.insert(1);
x.insert(2);
x.insert(3);
y.insert(3);
y.insert(2);
y.insert(1);
y.insert(3);
y.insert(2);
y.insert(1);
assert!(::hash(&x) == ::hash(&y));
assert!(::hash(&x) == ::hash(&y));
}
fn check<F>(a: &[i32], b: &[i32], expected: &[i32], f: F) where
F: FnOnce(&BTreeSet<i32>, &BTreeSet<i32>, &mut FnMut(&i32) -> bool) -> bool,
fn check<F>(a: &[i32], b: &[i32], expected: &[i32], f: F)
where F: FnOnce(&BTreeSet<i32>, &BTreeSet<i32>, &mut FnMut(&i32) -> bool) -> bool
{
let mut set_a = BTreeSet::new();
let mut set_b = BTreeSet::new();
for x in a { assert!(set_a.insert(*x)) }
for y in b { assert!(set_b.insert(*y)) }
for x in a {
assert!(set_a.insert(*x))
}
for y in b {
assert!(set_b.insert(*y))
}
let mut i = 0;
f(&set_a, &set_b, &mut |&x| {
assert_eq!(x, expected[i]);
i += 1;
true
});
f(&set_a,
&set_b,
&mut |&x| {
assert_eq!(x, expected[i]);
i += 1;
true
});
assert_eq!(i, expected.len());
}
@ -82,9 +88,7 @@ fn test_difference() {
check_difference(&[], &[], &[]);
check_difference(&[1, 12], &[], &[1, 12]);
check_difference(&[], &[1, 2, 3, 9], &[]);
check_difference(&[1, 3, 5, 9, 11],
&[3, 9],
&[1, 5, 11]);
check_difference(&[1, 3, 5, 9, 11], &[3, 9], &[1, 5, 11]);
check_difference(&[-5, 11, 22, 33, 40, 42],
&[-12, -5, 14, 23, 34, 38, 39, 50],
&[11, 22, 33, 40, 42]);
@ -245,10 +249,18 @@ fn test_recovery() {
fn test_variance() {
use std::collections::btree_set::{IntoIter, Iter, Range};
fn set<'new>(v: BTreeSet<&'static str>) -> BTreeSet<&'new str> { v }
fn iter<'a, 'new>(v: Iter<'a, &'static str>) -> Iter<'a, &'new str> { v }
fn into_iter<'new>(v: IntoIter<&'static str>) -> IntoIter<&'new str> { v }
fn range<'a, 'new>(v: Range<'a, &'static str>) -> Range<'a, &'new str> { v }
fn set<'new>(v: BTreeSet<&'static str>) -> BTreeSet<&'new str> {
v
}
fn iter<'a, 'new>(v: Iter<'a, &'static str>) -> Iter<'a, &'new str> {
v
}
fn into_iter<'new>(v: IntoIter<&'static str>) -> IntoIter<&'new str> {
v
}
fn range<'a, 'new>(v: Range<'a, &'static str>) -> Range<'a, &'new str> {
v
}
}
#[test]
@ -277,9 +289,7 @@ fn test_append() {
fn rand_data(len: usize) -> Vec<u32> {
let mut rng = DeterministicRng::new();
Vec::from_iter(
(0..len).map(|_| rng.next())
)
Vec::from_iter((0..len).map(|_| rng.next()))
}
#[test]

View File

@ -0,0 +1,141 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::borrow::Cow;
// check that Cow<'a, str> implements addition
#[test]
fn check_cow_add_cow() {
let borrowed1 = Cow::Borrowed("Hello, ");
let borrowed2 = Cow::Borrowed("World!");
let borrow_empty = Cow::Borrowed("");
let owned1: Cow<str> = Cow::Owned(String::from("Hi, "));
let owned2: Cow<str> = Cow::Owned(String::from("Rustaceans!"));
let owned_empty: Cow<str> = Cow::Owned(String::new());
assert_eq!("Hello, World!", borrowed1.clone() + borrowed2.clone());
assert_eq!("Hello, Rustaceans!", borrowed1.clone() + owned2.clone());
assert_eq!("Hi, World!", owned1.clone() + borrowed2.clone());
assert_eq!("Hi, Rustaceans!", owned1.clone() + owned2.clone());
if let Cow::Owned(_) = borrowed1.clone() + borrow_empty.clone() {
panic!("Adding empty strings to a borrow should note allocate");
}
if let Cow::Owned(_) = borrow_empty.clone() + borrowed1.clone() {
panic!("Adding empty strings to a borrow should note allocate");
}
if let Cow::Owned(_) = borrowed1.clone() + owned_empty.clone() {
panic!("Adding empty strings to a borrow should note allocate");
}
if let Cow::Owned(_) = owned_empty.clone() + borrowed1.clone() {
panic!("Adding empty strings to a borrow should note allocate");
}
}
#[test]
fn check_cow_add_str() {
let borrowed = Cow::Borrowed("Hello, ");
let borrow_empty = Cow::Borrowed("");
let owned: Cow<str> = Cow::Owned(String::from("Hi, "));
let owned_empty: Cow<str> = Cow::Owned(String::new());
assert_eq!("Hello, World!", borrowed.clone() + "World!");
assert_eq!("Hi, World!", owned.clone() + "World!");
if let Cow::Owned(_) = borrowed.clone() + "" {
panic!("Adding empty strings to a borrow should note allocate");
}
if let Cow::Owned(_) = borrow_empty.clone() + "Hello, " {
panic!("Adding empty strings to a borrow should note allocate");
}
if let Cow::Owned(_) = owned_empty.clone() + "Hello, " {
panic!("Adding empty strings to a borrow should note allocate");
}
}
#[test]
fn check_cow_add_assign_cow() {
let mut borrowed1 = Cow::Borrowed("Hello, ");
let borrowed2 = Cow::Borrowed("World!");
let borrow_empty = Cow::Borrowed("");
let mut owned1: Cow<str> = Cow::Owned(String::from("Hi, "));
let owned2: Cow<str> = Cow::Owned(String::from("Rustaceans!"));
let owned_empty: Cow<str> = Cow::Owned(String::new());
let mut s = borrowed1.clone();
s += borrow_empty.clone();
assert_eq!("Hello, ", s);
if let Cow::Owned(_) = s {
panic!("Adding empty strings to a borrow should note allocate");
}
let mut s = borrow_empty.clone();
s += borrowed1.clone();
assert_eq!("Hello, ", s);
if let Cow::Owned(_) = s {
panic!("Adding empty strings to a borrow should note allocate");
}
let mut s = borrowed1.clone();
s += owned_empty.clone();
assert_eq!("Hello, ", s);
if let Cow::Owned(_) = s {
panic!("Adding empty strings to a borrow should note allocate");
}
let mut s = owned_empty.clone();
s += borrowed1.clone();
assert_eq!("Hello, ", s);
if let Cow::Owned(_) = s {
panic!("Adding empty strings to a borrow should note allocate");
}
owned1 += borrowed2;
borrowed1 += owned2;
assert_eq!("Hi, World!", owned1);
assert_eq!("Hello, Rustaceans!", borrowed1);
}
#[test]
fn check_cow_add_assign_str() {
let mut borrowed = Cow::Borrowed("Hello, ");
let borrow_empty = Cow::Borrowed("");
let mut owned: Cow<str> = Cow::Owned(String::from("Hi, "));
let owned_empty: Cow<str> = Cow::Owned(String::new());
let mut s = borrowed.clone();
s += "";
assert_eq!("Hello, ", s);
if let Cow::Owned(_) = s {
panic!("Adding empty strings to a borrow should note allocate");
}
let mut s = borrow_empty.clone();
s += "World!";
assert_eq!("World!", s);
if let Cow::Owned(_) = s {
panic!("Adding empty strings to a borrow should note allocate");
}
let mut s = owned_empty.clone();
s += "World!";
assert_eq!("World!", s);
if let Cow::Owned(_) = s {
panic!("Adding empty strings to a borrow should note allocate");
}
owned += "World!";
borrowed += "World!";
assert_eq!("Hi, World!", owned);
assert_eq!("Hello, World!", borrowed);
}

View File

@ -16,9 +16,11 @@
#![feature(collections)]
#![feature(collections_bound)]
#![feature(const_fn)]
#![feature(dedup_by)]
#![feature(enumset)]
#![feature(pattern)]
#![feature(rand)]
#![feature(repeat_str)]
#![feature(step_by)]
#![feature(str_escape)]
#![feature(str_replacen)]
@ -34,10 +36,13 @@ extern crate rustc_unicode;
use std::hash::{Hash, Hasher};
use std::collections::hash_map::DefaultHasher;
#[cfg(test)] #[macro_use] mod bench;
#[cfg(test)]
#[macro_use]
mod bench;
mod binary_heap;
mod btree;
mod cow_str;
mod enum_set;
mod fmt;
mod linked_list;

View File

@ -315,47 +315,6 @@ fn test_clear() {
// If the unsafe block didn't drop things properly, we blow up here.
}
#[test]
fn test_dedup() {
fn case(a: Vec<i32>, b: Vec<i32>) {
let mut v = a;
v.dedup();
assert_eq!(v, b);
}
case(vec![], vec![]);
case(vec![1], vec![1]);
case(vec![1, 1], vec![1]);
case(vec![1, 2, 3], vec![1, 2, 3]);
case(vec![1, 1, 2, 3], vec![1, 2, 3]);
case(vec![1, 2, 2, 3], vec![1, 2, 3]);
case(vec![1, 2, 3, 3], vec![1, 2, 3]);
case(vec![1, 1, 2, 2, 2, 3, 3], vec![1, 2, 3]);
}
#[test]
fn test_dedup_unique() {
let mut v0: Vec<Box<_>> = vec![box 1, box 1, box 2, box 3];
v0.dedup();
let mut v1: Vec<Box<_>> = vec![box 1, box 2, box 2, box 3];
v1.dedup();
let mut v2: Vec<Box<_>> = vec![box 1, box 2, box 3, box 3];
v2.dedup();
// If the boxed pointers were leaked or otherwise misused, valgrind
// and/or rt should raise errors.
}
#[test]
fn test_dedup_shared() {
let mut v0: Vec<Box<_>> = vec![box 1, box 1, box 2, box 3];
v0.dedup();
let mut v1: Vec<Box<_>> = vec![box 1, box 2, box 2, box 3];
v1.dedup();
let mut v2: Vec<Box<_>> = vec![box 1, box 2, box 3, box 3];
v2.dedup();
// If the pointers were leaked or otherwise misused, valgrind and/or
// rt should raise errors.
}
#[test]
fn test_retain() {
let mut v = vec![1, 2, 3, 4, 5];
@ -461,12 +420,12 @@ fn test_sort_stability() {
// number this element is, i.e. the second elements
// will occur in sorted order.
let mut v: Vec<_> = (0..len)
.map(|_| {
let n = thread_rng().gen::<usize>() % 10;
counts[n] += 1;
(n, counts[n])
})
.collect();
.map(|_| {
let n = thread_rng().gen::<usize>() % 10;
counts[n] += 1;
(n, counts[n])
})
.collect();
// only sort on the first element, so an unstable sort
// may mix up the counts.
@ -1116,6 +1075,7 @@ fn test_box_slice_clone() {
}
#[test]
#[cfg_attr(target_os = "emscripten", ignore)]
fn test_box_slice_clone_panics() {
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
@ -1156,13 +1116,13 @@ fn test_box_slice_clone_panics() {
};
spawn(move || {
// When xs is dropped, +5.
let xs = vec![canary.clone(), canary.clone(), canary.clone(), panic, canary]
.into_boxed_slice();
// When xs is dropped, +5.
let xs = vec![canary.clone(), canary.clone(), canary.clone(), panic, canary]
.into_boxed_slice();
// When panic is cloned, +3.
xs.clone();
})
// When panic is cloned, +3.
xs.clone();
})
.join()
.unwrap_err();
@ -1414,8 +1374,8 @@ mod bench {
let mut rng = thread_rng();
b.iter(|| {
let mut v = rng.gen_iter::<BigSortable>()
.take(5)
.collect::<Vec<BigSortable>>();
.take(5)
.collect::<Vec<BigSortable>>();
v.sort();
});
b.bytes = 5 * mem::size_of::<BigSortable>() as u64;
@ -1426,8 +1386,8 @@ mod bench {
let mut rng = thread_rng();
b.iter(|| {
let mut v = rng.gen_iter::<BigSortable>()
.take(100)
.collect::<Vec<BigSortable>>();
.take(100)
.collect::<Vec<BigSortable>>();
v.sort();
});
b.bytes = 100 * mem::size_of::<BigSortable>() as u64;
@ -1438,8 +1398,8 @@ mod bench {
let mut rng = thread_rng();
b.iter(|| {
let mut v = rng.gen_iter::<BigSortable>()
.take(10000)
.collect::<Vec<BigSortable>>();
.take(10000)
.collect::<Vec<BigSortable>>();
v.sort();
});
b.bytes = 10000 * mem::size_of::<BigSortable>() as u64;

View File

@ -786,9 +786,9 @@ fn test_rev_iterator() {
#[test]
fn test_chars_decoding() {
let mut bytes = [0; 4];
for c in (0..0x110000).filter_map(::std::char::from_u32) {
let bytes = c.encode_utf8();
let s = ::std::str::from_utf8(bytes.as_slice()).unwrap();
let s = c.encode_utf8(&mut bytes);
if Some(c) != s.chars().next() {
panic!("character {:x}={} does not decode correctly", c as u32, c);
}
@ -797,9 +797,9 @@ fn test_chars_decoding() {
#[test]
fn test_chars_rev_decoding() {
let mut bytes = [0; 4];
for c in (0..0x110000).filter_map(::std::char::from_u32) {
let bytes = c.encode_utf8();
let s = ::std::str::from_utf8(bytes.as_slice()).unwrap();
let s = c.encode_utf8(&mut bytes);
if Some(c) != s.chars().rev().next() {
panic!("character {:x}={} does not decode correctly", c as u32, c);
}
@ -1286,6 +1286,13 @@ fn test_cow_from() {
}
}
#[test]
fn test_repeat() {
assert_eq!("".repeat(3), "");
assert_eq!("abc".repeat(0), "");
assert_eq!("α".repeat(3), "ααα");
}
mod pattern {
use std::str::pattern::Pattern;
use std::str::pattern::{Searcher, ReverseSearcher};

View File

@ -35,6 +35,12 @@ fn test_from_str() {
assert_eq!(owned.as_ref().map(|s| &**s), Some("string"));
}
#[test]
fn test_from_cow_str() {
assert_eq!(String::from(Cow::Borrowed("string")), "string");
assert_eq!(String::from(Cow::Owned(String::from("string"))), "string");
}
#[test]
fn test_unsized_to_string() {
let s: &str = "abc";

View File

@ -8,6 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::ascii::AsciiExt;
use std::borrow::Cow;
use std::iter::{FromIterator, repeat};
use std::mem::size_of;
@ -213,6 +214,60 @@ fn test_retain() {
assert_eq!(vec, [2, 4]);
}
#[test]
fn test_dedup() {
fn case(a: Vec<i32>, b: Vec<i32>) {
let mut v = a;
v.dedup();
assert_eq!(v, b);
}
case(vec![], vec![]);
case(vec![1], vec![1]);
case(vec![1, 1], vec![1]);
case(vec![1, 2, 3], vec![1, 2, 3]);
case(vec![1, 1, 2, 3], vec![1, 2, 3]);
case(vec![1, 2, 2, 3], vec![1, 2, 3]);
case(vec![1, 2, 3, 3], vec![1, 2, 3]);
case(vec![1, 1, 2, 2, 2, 3, 3], vec![1, 2, 3]);
}
#[test]
fn test_dedup_by_key() {
fn case(a: Vec<i32>, b: Vec<i32>) {
let mut v = a;
v.dedup_by_key(|i| *i / 10);
assert_eq!(v, b);
}
case(vec![], vec![]);
case(vec![10], vec![10]);
case(vec![10, 11], vec![10]);
case(vec![10, 20, 30], vec![10, 20, 30]);
case(vec![10, 11, 20, 30], vec![10, 20, 30]);
case(vec![10, 20, 21, 30], vec![10, 20, 30]);
case(vec![10, 20, 30, 31], vec![10, 20, 30]);
case(vec![10, 11, 20, 21, 22, 30, 31], vec![10, 20, 30]);
}
#[test]
fn test_dedup_by() {
let mut vec = vec!["foo", "bar", "Bar", "baz", "bar"];
vec.dedup_by(|a, b| a.eq_ignore_ascii_case(b));
assert_eq!(vec, ["foo", "bar", "baz", "bar"]);
}
#[test]
fn test_dedup_unique() {
let mut v0: Vec<Box<_>> = vec![box 1, box 1, box 2, box 3];
v0.dedup();
let mut v1: Vec<Box<_>> = vec![box 1, box 2, box 2, box 3];
v1.dedup();
let mut v2: Vec<Box<_>> = vec![box 1, box 2, box 3, box 3];
v2.dedup();
// If the boxed pointers were leaked or otherwise misused, valgrind
// and/or rt should raise errors.
}
#[test]
fn zero_sized_values() {
let mut v = Vec::new();
@ -271,22 +326,22 @@ fn test_zip_unzip() {
#[test]
fn test_vec_truncate_drop() {
static mut drops: u32 = 0;
static mut DROPS: u32 = 0;
struct Elem(i32);
impl Drop for Elem {
fn drop(&mut self) {
unsafe {
drops += 1;
DROPS += 1;
}
}
}
let mut v = vec![Elem(1), Elem(2), Elem(3), Elem(4), Elem(5)];
assert_eq!(unsafe { drops }, 0);
assert_eq!(unsafe { DROPS }, 0);
v.truncate(3);
assert_eq!(unsafe { drops }, 2);
assert_eq!(unsafe { DROPS }, 2);
v.truncate(0);
assert_eq!(unsafe { drops }, 5);
assert_eq!(unsafe { DROPS }, 5);
}
#[test]
@ -542,10 +597,22 @@ fn test_cow_from() {
}
}
#[test]
fn test_from_cow() {
let borrowed: &[_] = &["borrowed", "(slice)"];
let owned = vec!["owned", "(vec)"];
assert_eq!(Vec::from(Cow::Borrowed(borrowed)), vec!["borrowed", "(slice)"]);
assert_eq!(Vec::from(Cow::Owned(owned)), vec!["owned", "(vec)"]);
}
#[allow(dead_code)]
fn assert_covariance() {
fn drain<'new>(d: Drain<'static, &'static str>) -> Drain<'new, &'new str> { d }
fn into_iter<'new>(i: IntoIter<&'static str>) -> IntoIter<&'new str> { i }
fn drain<'new>(d: Drain<'static, &'static str>) -> Drain<'new, &'new str> {
d
}
fn into_iter<'new>(i: IntoIter<&'static str>) -> IntoIter<&'new str> {
i
}
}
#[bench]

View File

@ -686,21 +686,21 @@ fn test_show() {
assert_eq!(format!("{:?}", ringbuf), "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]");
let ringbuf: VecDeque<_> = vec!["just", "one", "test", "more"]
.iter()
.cloned()
.collect();
.iter()
.cloned()
.collect();
assert_eq!(format!("{:?}", ringbuf),
"[\"just\", \"one\", \"test\", \"more\"]");
}
#[test]
fn test_drop() {
static mut drops: i32 = 0;
static mut DROPS: i32 = 0;
struct Elem;
impl Drop for Elem {
fn drop(&mut self) {
unsafe {
drops += 1;
DROPS += 1;
}
}
}
@ -712,17 +712,17 @@ fn test_drop() {
ring.push_front(Elem);
drop(ring);
assert_eq!(unsafe { drops }, 4);
assert_eq!(unsafe { DROPS }, 4);
}
#[test]
fn test_drop_with_pop() {
static mut drops: i32 = 0;
static mut DROPS: i32 = 0;
struct Elem;
impl Drop for Elem {
fn drop(&mut self) {
unsafe {
drops += 1;
DROPS += 1;
}
}
}
@ -735,20 +735,20 @@ fn test_drop_with_pop() {
drop(ring.pop_back());
drop(ring.pop_front());
assert_eq!(unsafe { drops }, 2);
assert_eq!(unsafe { DROPS }, 2);
drop(ring);
assert_eq!(unsafe { drops }, 4);
assert_eq!(unsafe { DROPS }, 4);
}
#[test]
fn test_drop_clear() {
static mut drops: i32 = 0;
static mut DROPS: i32 = 0;
struct Elem;
impl Drop for Elem {
fn drop(&mut self) {
unsafe {
drops += 1;
DROPS += 1;
}
}
}
@ -759,10 +759,10 @@ fn test_drop_clear() {
ring.push_back(Elem);
ring.push_front(Elem);
ring.clear();
assert_eq!(unsafe { drops }, 4);
assert_eq!(unsafe { DROPS }, 4);
drop(ring);
assert_eq!(unsafe { drops }, 4);
assert_eq!(unsafe { DROPS }, 4);
}
#[test]
@ -1003,5 +1003,7 @@ fn test_contains() {
#[allow(dead_code)]
fn assert_covariance() {
fn drain<'new>(d: Drain<'static, &'static str>) -> Drain<'new, &'new str> { d }
fn drain<'new>(d: Drain<'static, &'static str>) -> Drain<'new, &'new str> {
d
}
}

View File

@ -73,6 +73,12 @@ impl Sources {
fn main() {
let target = env::var("TARGET").expect("TARGET was not set");
// Emscripten's runtime includes all the builtins
if target.contains("emscripten") {
return;
}
let cfg = &mut gcc::Config::new();
if target.contains("msvc") {

View File

@ -8,9 +8,9 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![cfg_attr(not(stage0), feature(compiler_builtins))]
#![feature(compiler_builtins)]
#![no_std]
#![cfg_attr(not(stage0), compiler_builtins)]
#![compiler_builtins]
#![unstable(feature = "compiler_builtins_lib",
reason = "internal implementation detail of rustc right now",
issue = "0")]

View File

@ -351,12 +351,10 @@ impl TypeId {
/// # Examples
///
/// ```
/// #![feature(get_type_id)]
///
/// use std::any::{Any, TypeId};
///
/// fn is_string(s: &Any) -> bool {
/// TypeId::of::<String>() == s.get_type_id()
/// fn is_string<T: ?Sized + Any>(_s: &T) -> bool {
/// TypeId::of::<String>() == TypeId::of::<T>()
/// }
///
/// fn main() {

View File

@ -93,6 +93,7 @@ macro_rules! __impl_slice_eq2 {
macro_rules! array_impls {
($($N:expr)+) => {
$(
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> AsRef<[T]> for [T; $N] {
#[inline]
fn as_ref(&self) -> &[T] {
@ -100,6 +101,7 @@ macro_rules! array_impls {
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> AsMut<[T]> for [T; $N] {
#[inline]
fn as_mut(&mut self) -> &mut [T] {

View File

@ -18,6 +18,7 @@
use char_private::is_printable;
use convert::TryFrom;
use fmt;
use slice;
use iter::FusedIterator;
use mem::transmute;
@ -327,9 +328,9 @@ pub trait CharExt {
#[stable(feature = "core", since = "1.6.0")]
fn len_utf16(self) -> usize;
#[unstable(feature = "unicode", issue = "27784")]
fn encode_utf8(self) -> EncodeUtf8;
fn encode_utf8(self, dst: &mut [u8]) -> &mut str;
#[unstable(feature = "unicode", issue = "27784")]
fn encode_utf16(self) -> EncodeUtf16;
fn encode_utf16(self, dst: &mut [u16]) -> &mut [u16];
}
#[stable(feature = "core", since = "1.6.0")]
@ -419,47 +420,59 @@ impl CharExt for char {
}
#[inline]
fn encode_utf8(self) -> EncodeUtf8 {
fn encode_utf8(self, dst: &mut [u8]) -> &mut str {
let code = self as u32;
let mut buf = [0; 4];
let pos = if code < MAX_ONE_B {
buf[3] = code as u8;
3
} else if code < MAX_TWO_B {
buf[2] = (code >> 6 & 0x1F) as u8 | TAG_TWO_B;
buf[3] = (code & 0x3F) as u8 | TAG_CONT;
2
} else if code < MAX_THREE_B {
buf[1] = (code >> 12 & 0x0F) as u8 | TAG_THREE_B;
buf[2] = (code >> 6 & 0x3F) as u8 | TAG_CONT;
buf[3] = (code & 0x3F) as u8 | TAG_CONT;
1
} else {
buf[0] = (code >> 18 & 0x07) as u8 | TAG_FOUR_B;
buf[1] = (code >> 12 & 0x3F) as u8 | TAG_CONT;
buf[2] = (code >> 6 & 0x3F) as u8 | TAG_CONT;
buf[3] = (code & 0x3F) as u8 | TAG_CONT;
0
};
EncodeUtf8 { buf: buf, pos: pos }
unsafe {
let len =
if code < MAX_ONE_B && !dst.is_empty() {
*dst.get_unchecked_mut(0) = code as u8;
1
} else if code < MAX_TWO_B && dst.len() >= 2 {
*dst.get_unchecked_mut(0) = (code >> 6 & 0x1F) as u8 | TAG_TWO_B;
*dst.get_unchecked_mut(1) = (code & 0x3F) as u8 | TAG_CONT;
2
} else if code < MAX_THREE_B && dst.len() >= 3 {
*dst.get_unchecked_mut(0) = (code >> 12 & 0x0F) as u8 | TAG_THREE_B;
*dst.get_unchecked_mut(1) = (code >> 6 & 0x3F) as u8 | TAG_CONT;
*dst.get_unchecked_mut(2) = (code & 0x3F) as u8 | TAG_CONT;
3
} else if dst.len() >= 4 {
*dst.get_unchecked_mut(0) = (code >> 18 & 0x07) as u8 | TAG_FOUR_B;
*dst.get_unchecked_mut(1) = (code >> 12 & 0x3F) as u8 | TAG_CONT;
*dst.get_unchecked_mut(2) = (code >> 6 & 0x3F) as u8 | TAG_CONT;
*dst.get_unchecked_mut(3) = (code & 0x3F) as u8 | TAG_CONT;
4
} else {
panic!("encode_utf8: need {} bytes to encode U+{:X}, but the buffer has {}",
from_u32_unchecked(code).len_utf8(),
code,
dst.len())
};
transmute(slice::from_raw_parts_mut(dst.as_mut_ptr(), len))
}
}
#[inline]
fn encode_utf16(self) -> EncodeUtf16 {
let mut buf = [0; 2];
fn encode_utf16(self, dst: &mut [u16]) -> &mut [u16] {
let mut code = self as u32;
let pos = if (code & 0xFFFF) == code {
// The BMP falls through (assuming non-surrogate, as it should)
buf[1] = code as u16;
1
} else {
// Supplementary planes break into surrogates.
code -= 0x1_0000;
buf[0] = 0xD800 | ((code >> 10) as u16);
buf[1] = 0xDC00 | ((code as u16) & 0x3FF);
0
};
EncodeUtf16 { buf: buf, pos: pos }
unsafe {
if (code & 0xFFFF) == code && !dst.is_empty() {
// The BMP falls through (assuming non-surrogate, as it should)
*dst.get_unchecked_mut(0) = code as u16;
slice::from_raw_parts_mut(dst.as_mut_ptr(), 1)
} else if dst.len() >= 2 {
// Supplementary planes break into surrogates.
code -= 0x1_0000;
*dst.get_unchecked_mut(0) = 0xD800 | ((code >> 10) as u16);
*dst.get_unchecked_mut(1) = 0xDC00 | ((code as u16) & 0x3FF);
slice::from_raw_parts_mut(dst.as_mut_ptr(), 2)
} else {
panic!("encode_utf16: need {} units to encode U+{:X}, but the buffer has {}",
from_u32_unchecked(code).len_utf16(),
code,
dst.len())
}
}
}
}
@ -702,88 +715,7 @@ impl ExactSizeIterator for EscapeDebug { }
#[unstable(feature = "fused", issue = "35602")]
impl FusedIterator for EscapeDebug {}
/// An iterator over `u8` entries represending the UTF-8 encoding of a `char`
/// value.
///
/// Constructed via the `.encode_utf8()` method on `char`.
#[unstable(feature = "unicode", issue = "27784")]
#[derive(Debug)]
pub struct EncodeUtf8 {
buf: [u8; 4],
pos: usize,
}
impl EncodeUtf8 {
/// Returns the remaining bytes of this iterator as a slice.
#[unstable(feature = "unicode", issue = "27784")]
pub fn as_slice(&self) -> &[u8] {
&self.buf[self.pos..]
}
}
#[unstable(feature = "unicode", issue = "27784")]
impl Iterator for EncodeUtf8 {
type Item = u8;
fn next(&mut self) -> Option<u8> {
if self.pos == self.buf.len() {
None
} else {
let ret = Some(self.buf[self.pos]);
self.pos += 1;
ret
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.as_slice().iter().size_hint()
}
}
#[unstable(feature = "fused", issue = "35602")]
impl FusedIterator for EncodeUtf8 {}
/// An iterator over `u16` entries represending the UTF-16 encoding of a `char`
/// value.
///
/// Constructed via the `.encode_utf16()` method on `char`.
#[unstable(feature = "unicode", issue = "27784")]
#[derive(Debug)]
pub struct EncodeUtf16 {
buf: [u16; 2],
pos: usize,
}
impl EncodeUtf16 {
/// Returns the remaining bytes of this iterator as a slice.
#[unstable(feature = "unicode", issue = "27784")]
pub fn as_slice(&self) -> &[u16] {
&self.buf[self.pos..]
}
}
#[unstable(feature = "unicode", issue = "27784")]
impl Iterator for EncodeUtf16 {
type Item = u16;
fn next(&mut self) -> Option<u16> {
if self.pos == self.buf.len() {
None
} else {
let ret = Some(self.buf[self.pos]);
self.pos += 1;
ret
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.as_slice().iter().size_hint()
}
}
#[unstable(feature = "fused", issue = "35602")]
impl FusedIterator for EncodeUtf16 {}
/// An iterator over an iterator of bytes of the characters the bytes represent
/// as UTF-8

View File

@ -129,13 +129,6 @@ pub struct AssertParamIsClone<T: Clone + ?Sized> { _field: ::marker::PhantomData
reason = "deriving hack, should not be public",
issue = "0")]
pub struct AssertParamIsCopy<T: Copy + ?Sized> { _field: ::marker::PhantomData<T> }
#[cfg(stage0)]
#[doc(hidden)]
#[inline(always)]
#[unstable(feature = "derive_clone_copy",
reason = "deriving hack, should not be public",
issue = "0")]
pub fn assert_receiver_is_clone<T: Clone + ?Sized>(_: &T) {}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T: ?Sized> Clone for &'a T {

View File

@ -10,10 +10,13 @@
//! Functionality for ordering and comparison.
//!
//! This module defines both `PartialOrd` and `PartialEq` traits which are used
//! This module defines both [`PartialOrd`] and [`PartialEq`] traits which are used
//! by the compiler to implement comparison operators. Rust programs may
//! implement `PartialOrd` to overload the `<`, `<=`, `>`, and `>=` operators,
//! and may implement `PartialEq` to overload the `==` and `!=` operators.
//! implement [`PartialOrd`] to overload the `<`, `<=`, `>`, and `>=` operators,
//! and may implement [`PartialEq`] to overload the `==` and `!=` operators.
//!
//! [`PartialOrd`]: trait.PartialOrd.html
//! [`PartialEq`]: trait.PartialEq.html
//!
//! # Examples
//!
@ -245,6 +248,80 @@ impl Ordering {
Greater => Less,
}
}
/// Chains two orderings.
///
/// Returns `self` when it's not `Equal`. Otherwise returns `other`.
/// # Examples
///
/// ```
/// #![feature(ordering_chaining)]
///
/// use std::cmp::Ordering;
///
/// let result = Ordering::Equal.then(Ordering::Less);
/// assert_eq!(result, Ordering::Less);
///
/// let result = Ordering::Less.then(Ordering::Equal);
/// assert_eq!(result, Ordering::Less);
///
/// let result = Ordering::Less.then(Ordering::Greater);
/// assert_eq!(result, Ordering::Less);
///
/// let result = Ordering::Equal.then(Ordering::Equal);
/// assert_eq!(result, Ordering::Equal);
///
/// let x: (i64, i64, i64) = (1, 2, 7);
/// let y: (i64, i64, i64) = (1, 5, 3);
/// let result = x.0.cmp(&y.0).then(x.1.cmp(&y.1)).then(x.2.cmp(&y.2));
///
/// assert_eq!(result, Ordering::Less);
/// ```
#[unstable(feature = "ordering_chaining", issue = "37053")]
pub fn then(self, other: Ordering) -> Ordering {
match self {
Equal => other,
_ => self,
}
}
/// Chains the ordering with the given function.
///
/// Returns `self` when it's not `Equal`. Otherwise calls `f` and returns
/// the result.
///
/// # Examples
///
/// ```
/// #![feature(ordering_chaining)]
///
/// use std::cmp::Ordering;
///
/// let result = Ordering::Equal.then_with(|| Ordering::Less);
/// assert_eq!(result, Ordering::Less);
///
/// let result = Ordering::Less.then_with(|| Ordering::Equal);
/// assert_eq!(result, Ordering::Less);
///
/// let result = Ordering::Less.then_with(|| Ordering::Greater);
/// assert_eq!(result, Ordering::Less);
///
/// let result = Ordering::Equal.then_with(|| Ordering::Equal);
/// assert_eq!(result, Ordering::Equal);
///
/// let x: (i64, i64, i64) = (1, 2, 7);
/// let y: (i64, i64, i64) = (1, 5, 3);
/// let result = x.0.cmp(&y.0).then_with(|| x.1.cmp(&y.1)).then_with(|| x.2.cmp(&y.2));
///
/// assert_eq!(result, Ordering::Less);
/// ```
#[unstable(feature = "ordering_chaining", issue = "37053")]
pub fn then_with<F: FnOnce() -> Ordering>(self, f: F) -> Ordering {
match self {
Equal => f(),
_ => self,
}
}
}
/// Trait for types that form a [total order](https://en.wikipedia.org/wiki/Total_order).
@ -703,24 +780,24 @@ mod impls {
ord_impl! { char usize u8 u16 u32 u64 isize i8 i16 i32 i64 }
#[unstable(feature = "never_type", issue = "35121")]
#[unstable(feature = "never_type_impls", issue = "35121")]
impl PartialEq for ! {
fn eq(&self, _: &!) -> bool {
*self
}
}
#[unstable(feature = "never_type", issue = "35121")]
#[unstable(feature = "never_type_impls", issue = "35121")]
impl Eq for ! {}
#[unstable(feature = "never_type", issue = "35121")]
#[unstable(feature = "never_type_impls", issue = "35121")]
impl PartialOrd for ! {
fn partial_cmp(&self, _: &!) -> Option<Ordering> {
*self
}
}
#[unstable(feature = "never_type", issue = "35121")]
#[unstable(feature = "never_type_impls", issue = "35121")]
impl Ord for ! {
fn cmp(&self, _: &!) -> Ordering {
*self

View File

@ -145,7 +145,7 @@ pub trait AsMut<T: ?Sized> {
///
/// # Generic Impls
///
/// - `[From<T>][From] for U` implies `Into<U> for T`
/// - [`From<T>`][From]` for U` implies `Into<U> for T`
/// - [`into()`] is reflexive, which means that `Into<T> for T` is implemented
///
/// [`TryInto`]: trait.TryInto.html
@ -178,14 +178,14 @@ pub trait Into<T>: Sized {
/// ```
/// # Generic impls
///
/// - `From<T> for U` implies `[Into<U>] for T`
/// - `From<T> for U` implies [`Into<U>`]` for T`
/// - [`from()`] is reflexive, which means that `From<T> for T` is implemented
///
/// [`TryFrom`]: trait.TryFrom.html
/// [`Option<T>`]: ../../std/option/enum.Option.html
/// [`Result<T, E>`]: ../../std/result/enum.Result.html
/// [`String`]: ../../std/string/struct.String.html
/// [Into<U>]: trait.Into.html
/// [`Into<U>`]: trait.Into.html
/// [`from()`]: trait.From.html#tymethod.from
#[stable(feature = "rust1", since = "1.0.0")]
pub trait From<T>: Sized {

View File

@ -97,9 +97,7 @@ pub trait Write {
/// This function will return an instance of `Error` on error.
#[stable(feature = "fmt_write_char", since = "1.1.0")]
fn write_char(&mut self, c: char) -> Result {
self.write_str(unsafe {
str::from_utf8_unchecked(c.encode_utf8().as_slice())
})
self.write_str(c.encode_utf8(&mut [0; 4]))
}
/// Glue for usage of the `write!` macro with implementors of this trait.
@ -796,7 +794,7 @@ pub trait UpperExp {
/// assert_eq!(output, "Hello world!");
/// ```
///
/// Please note that using [`write!`][write_macro] might be preferrable. Example:
/// Please note that using [`write!`] might be preferrable. Example:
///
/// ```
/// use std::fmt::Write;
@ -807,7 +805,7 @@ pub trait UpperExp {
/// assert_eq!(output, "Hello world!");
/// ```
///
/// [write_macro]: ../../std/macro.write!.html
/// [`write!`]: ../../std/macro.write.html
#[stable(feature = "rust1", since = "1.0.0")]
pub fn write(output: &mut Write, args: Arguments) -> Result {
let mut formatter = Formatter {
@ -924,9 +922,7 @@ impl<'a> Formatter<'a> {
// Writes the sign if it exists, and then the prefix if it was requested
let write_prefix = |f: &mut Formatter| {
if let Some(c) = sign {
f.buf.write_str(unsafe {
str::from_utf8_unchecked(c.encode_utf8().as_slice())
})?;
f.buf.write_str(c.encode_utf8(&mut [0; 4]))?;
}
if prefixed { f.buf.write_str(prefix) }
else { Ok(()) }
@ -1032,10 +1028,8 @@ impl<'a> Formatter<'a> {
rt::v1::Alignment::Center => (padding / 2, (padding + 1) / 2),
};
let fill = self.fill.encode_utf8();
let fill = unsafe {
str::from_utf8_unchecked(fill.as_slice())
};
let mut fill = [0; 4];
let fill = self.fill.encode_utf8(&mut fill);
for _ in 0..pre_pad {
self.buf.write_str(fill)?;
@ -1362,14 +1356,14 @@ macro_rules! fmt_refs {
fmt_refs! { Debug, Display, Octal, Binary, LowerHex, UpperHex, LowerExp, UpperExp }
#[unstable(feature = "never_type", issue = "35121")]
#[unstable(feature = "never_type_impls", issue = "35121")]
impl Debug for ! {
fn fmt(&self, _: &mut Formatter) -> Result {
*self
}
}
#[unstable(feature = "never_type", issue = "35121")]
#[unstable(feature = "never_type_impls", issue = "35121")]
impl Display for ! {
fn fmt(&self, _: &mut Formatter) -> Result {
*self
@ -1435,9 +1429,7 @@ impl Display for char {
if f.width.is_none() && f.precision.is_none() {
f.write_char(*self)
} else {
f.pad(unsafe {
str::from_utf8_unchecked(self.encode_utf8().as_slice())
})
f.pad(self.encode_utf8(&mut [0; 4]))
}
}
}
@ -1574,11 +1566,11 @@ floating! { f64 }
// Implementation of Display/Debug for various core types
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> Debug for *const T {
impl<T: ?Sized> Debug for *const T {
fn fmt(&self, f: &mut Formatter) -> Result { Pointer::fmt(self, f) }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> Debug for *mut T {
impl<T: ?Sized> Debug for *mut T {
fn fmt(&self, f: &mut Formatter) -> Result { Pointer::fmt(self, f) }
}

View File

@ -38,7 +38,9 @@
//! ```
//!
//! If you need more control over how a value is hashed, you need to implement
//! the `Hash` trait:
//! the [`Hash`] trait:
//!
//! [`Hash`]: trait.Hash.html
//!
//! ```rust
//! use std::hash::{Hash, Hasher, SipHasher};
@ -90,7 +92,7 @@ mod sip;
/// The `H` type parameter is an abstract hash state that is used by the `Hash`
/// to compute the hash.
///
/// If you are also implementing `Eq`, there is an additional property that
/// If you are also implementing [`Eq`], there is an additional property that
/// is important:
///
/// ```text
@ -98,13 +100,13 @@ mod sip;
/// ```
///
/// In other words, if two keys are equal, their hashes should also be equal.
/// `HashMap` and `HashSet` both rely on this behavior.
/// [`HashMap`] and [`HashSet`] both rely on this behavior.
///
/// ## Derivable
///
/// This trait can be used with `#[derive]` if all fields implement `Hash`.
/// When `derive`d, the resulting hash will be the combination of the values
/// from calling `.hash()` on each field.
/// from calling [`.hash()`] on each field.
///
/// ## How can I implement `Hash`?
///
@ -127,6 +129,11 @@ mod sip;
/// }
/// }
/// ```
///
/// [`Eq`]: ../../std/cmp/trait.Eq.html
/// [`HashMap`]: ../../std/collections/struct.HashMap.html
/// [`HashSet`]: ../../std/collections/struct.HashSet.html
/// [`.hash()`]: #tymethod.hash
#[stable(feature = "rust1", since = "1.0.0")]
pub trait Hash {
/// Feeds this value into the state given, updating the hasher as necessary.
@ -151,35 +158,35 @@ pub trait Hasher {
#[stable(feature = "rust1", since = "1.0.0")]
fn finish(&self) -> u64;
/// Writes some data into this `Hasher`
/// Writes some data into this `Hasher`.
#[stable(feature = "rust1", since = "1.0.0")]
fn write(&mut self, bytes: &[u8]);
/// Write a single `u8` into this hasher
/// Write a single `u8` into this hasher.
#[inline]
#[stable(feature = "hasher_write", since = "1.3.0")]
fn write_u8(&mut self, i: u8) {
self.write(&[i])
}
/// Write a single `u16` into this hasher.
/// Writes a single `u16` into this hasher.
#[inline]
#[stable(feature = "hasher_write", since = "1.3.0")]
fn write_u16(&mut self, i: u16) {
self.write(&unsafe { mem::transmute::<_, [u8; 2]>(i) })
}
/// Write a single `u32` into this hasher.
/// Writes a single `u32` into this hasher.
#[inline]
#[stable(feature = "hasher_write", since = "1.3.0")]
fn write_u32(&mut self, i: u32) {
self.write(&unsafe { mem::transmute::<_, [u8; 4]>(i) })
}
/// Write a single `u64` into this hasher.
/// Writes a single `u64` into this hasher.
#[inline]
#[stable(feature = "hasher_write", since = "1.3.0")]
fn write_u64(&mut self, i: u64) {
self.write(&unsafe { mem::transmute::<_, [u8; 8]>(i) })
}
/// Write a single `usize` into this hasher.
/// Writes a single `usize` into this hasher.
#[inline]
#[stable(feature = "hasher_write", since = "1.3.0")]
fn write_usize(&mut self, i: usize) {
@ -189,31 +196,31 @@ pub trait Hasher {
self.write(bytes);
}
/// Write a single `i8` into this hasher.
/// Writes a single `i8` into this hasher.
#[inline]
#[stable(feature = "hasher_write", since = "1.3.0")]
fn write_i8(&mut self, i: i8) {
self.write_u8(i as u8)
}
/// Write a single `i16` into this hasher.
/// Writes a single `i16` into this hasher.
#[inline]
#[stable(feature = "hasher_write", since = "1.3.0")]
fn write_i16(&mut self, i: i16) {
self.write_u16(i as u16)
}
/// Write a single `i32` into this hasher.
/// Writes a single `i32` into this hasher.
#[inline]
#[stable(feature = "hasher_write", since = "1.3.0")]
fn write_i32(&mut self, i: i32) {
self.write_u32(i as u32)
}
/// Write a single `i64` into this hasher.
/// Writes a single `i64` into this hasher.
#[inline]
#[stable(feature = "hasher_write", since = "1.3.0")]
fn write_i64(&mut self, i: i64) {
self.write_u64(i as u64)
}
/// Write a single `isize` into this hasher.
/// Writes a single `isize` into this hasher.
#[inline]
#[stable(feature = "hasher_write", since = "1.3.0")]
fn write_isize(&mut self, i: isize) {

View File

@ -14,12 +14,18 @@
use marker::PhantomData;
use ptr;
use cmp;
use mem;
/// An implementation of SipHash 1-3.
///
/// This is currently the default hashing function used by standard library
/// (eg. `collections::HashMap` uses it by default).
///
/// See: https://131002.net/siphash/
#[unstable(feature = "sip_hash_13", issue = "34767")]
#[rustc_deprecated(since = "1.13.0", reason = "use `DefaultHasher` instead")]
#[rustc_deprecated(since = "1.13.0",
reason = "use `std::collections::hash_map::DefaultHasher` instead")]
#[derive(Debug, Clone, Default)]
pub struct SipHasher13 {
hasher: Hasher<Sip13Rounds>,
@ -29,7 +35,8 @@ pub struct SipHasher13 {
///
/// See: https://131002.net/siphash/
#[unstable(feature = "sip_hash_13", issue = "34767")]
#[rustc_deprecated(since = "1.13.0", reason = "use `DefaultHasher` instead")]
#[rustc_deprecated(since = "1.13.0",
reason = "use `std::collections::hash_map::DefaultHasher` instead")]
#[derive(Debug, Clone, Default)]
pub struct SipHasher24 {
hasher: Hasher<Sip24Rounds>,
@ -39,9 +46,6 @@ pub struct SipHasher24 {
///
/// See: https://131002.net/siphash/
///
/// This is currently the default hashing function used by standard library
/// (eg. `collections::HashMap` uses it by default).
///
/// SipHash is a general-purpose hashing function: it runs at a good
/// speed (competitive with Spooky and City) and permits strong _keyed_
/// hashing. This lets you key your hashtables from a strong RNG, such as
@ -51,7 +55,8 @@ pub struct SipHasher24 {
/// it is not intended for cryptographic purposes. As such, all
/// cryptographic uses of this implementation are _strongly discouraged_.
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_deprecated(since = "1.13.0", reason = "use `DefaultHasher` instead")]
#[rustc_deprecated(since = "1.13.0",
reason = "use `std::collections::hash_map::DefaultHasher` instead")]
#[derive(Debug, Clone, Default)]
pub struct SipHasher(SipHasher24);
@ -78,70 +83,68 @@ struct State {
v3: u64,
}
// sadly, these macro definitions can't appear later,
// because they're needed in the following defs;
// this design could be improved.
macro_rules! u8to64_le {
($buf:expr, $i:expr) =>
($buf[0+$i] as u64 |
($buf[1+$i] as u64) << 8 |
($buf[2+$i] as u64) << 16 |
($buf[3+$i] as u64) << 24 |
($buf[4+$i] as u64) << 32 |
($buf[5+$i] as u64) << 40 |
($buf[6+$i] as u64) << 48 |
($buf[7+$i] as u64) << 56);
($buf:expr, $i:expr, $len:expr) =>
({
let mut t = 0;
let mut out = 0;
while t < $len {
out |= ($buf[t+$i] as u64) << t*8;
t += 1;
}
out
});
}
/// Load a full u64 word from a byte stream, in LE order. Use
/// `copy_nonoverlapping` to let the compiler generate the most efficient way
/// to load u64 from a possibly unaligned address.
///
/// Unsafe because: unchecked indexing at i..i+8
#[inline]
unsafe fn load_u64_le(buf: &[u8], i: usize) -> u64 {
debug_assert!(i + 8 <= buf.len());
let mut data = 0u64;
ptr::copy_nonoverlapping(buf.get_unchecked(i), &mut data as *mut _ as *mut u8, 8);
data.to_le()
}
macro_rules! rotl {
($x:expr, $b:expr) =>
(($x << $b) | ($x >> (64_i32.wrapping_sub($b))))
}
macro_rules! compress {
($state:expr) => ({
compress!($state.v0, $state.v1, $state.v2, $state.v3)
});
($v0:expr, $v1:expr, $v2:expr, $v3:expr) =>
({
$v0 = $v0.wrapping_add($v1); $v1 = rotl!($v1, 13); $v1 ^= $v0;
$v0 = rotl!($v0, 32);
$v2 = $v2.wrapping_add($v3); $v3 = rotl!($v3, 16); $v3 ^= $v2;
$v0 = $v0.wrapping_add($v3); $v3 = rotl!($v3, 21); $v3 ^= $v0;
$v2 = $v2.wrapping_add($v1); $v1 = rotl!($v1, 17); $v1 ^= $v2;
$v2 = rotl!($v2, 32);
$v0 = $v0.wrapping_add($v1); $v1 = $v1.rotate_left(13); $v1 ^= $v0;
$v0 = $v0.rotate_left(32);
$v2 = $v2.wrapping_add($v3); $v3 = $v3.rotate_left(16); $v3 ^= $v2;
$v0 = $v0.wrapping_add($v3); $v3 = $v3.rotate_left(21); $v3 ^= $v0;
$v2 = $v2.wrapping_add($v1); $v1 = $v1.rotate_left(17); $v1 ^= $v2;
$v2 = $v2.rotate_left(32);
});
}
/// Load an integer of the desired type from a byte stream, in LE order. Uses
/// `copy_nonoverlapping` to let the compiler generate the most efficient way
/// to load it from a possibly unaligned address.
///
/// Unsafe because: unchecked indexing at i..i+size_of(int_ty)
macro_rules! load_int_le {
($buf:expr, $i:expr, $int_ty:ident) =>
({
debug_assert!($i + mem::size_of::<$int_ty>() <= $buf.len());
let mut data = 0 as $int_ty;
ptr::copy_nonoverlapping($buf.get_unchecked($i),
&mut data as *mut _ as *mut u8,
mem::size_of::<$int_ty>());
data.to_le()
});
}
/// Load an u64 using up to 7 bytes of a byte slice.
///
/// Unsafe because: unchecked indexing at start..start+len
#[inline]
unsafe fn u8to64_le(buf: &[u8], start: usize, len: usize) -> u64 {
debug_assert!(len < 8);
let mut i = 0; // current byte index (from LSB) in the output u64
let mut out = 0;
if i + 3 < len {
out = load_int_le!(buf, start + i, u32) as u64;
i += 4;
}
if i + 1 < len {
out |= (load_int_le!(buf, start + i, u16) as u64) << (i * 8);
i += 2
}
if i < len {
out |= (*buf.get_unchecked(start + i) as u64) << (i * 8);
i += 1;
}
debug_assert_eq!(i, len);
out
}
impl SipHasher {
/// Creates a new `SipHasher` with the two initial keys set to 0.
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_deprecated(since = "1.13.0", reason = "use `DefaultHasher` instead")]
#[rustc_deprecated(since = "1.13.0",
reason = "use `std::collections::hash_map::DefaultHasher` instead")]
pub fn new() -> SipHasher {
SipHasher::new_with_keys(0, 0)
}
@ -149,7 +152,8 @@ impl SipHasher {
/// Creates a `SipHasher` that is keyed off the provided keys.
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_deprecated(since = "1.13.0", reason = "use `DefaultHasher` instead")]
#[rustc_deprecated(since = "1.13.0",
reason = "use `std::collections::hash_map::DefaultHasher` instead")]
pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher {
SipHasher(SipHasher24::new_with_keys(key0, key1))
}
@ -159,7 +163,8 @@ impl SipHasher13 {
/// Creates a new `SipHasher13` with the two initial keys set to 0.
#[inline]
#[unstable(feature = "sip_hash_13", issue = "34767")]
#[rustc_deprecated(since = "1.13.0", reason = "use `DefaultHasher` instead")]
#[rustc_deprecated(since = "1.13.0",
reason = "use `std::collections::hash_map::DefaultHasher` instead")]
pub fn new() -> SipHasher13 {
SipHasher13::new_with_keys(0, 0)
}
@ -167,7 +172,8 @@ impl SipHasher13 {
/// Creates a `SipHasher13` that is keyed off the provided keys.
#[inline]
#[unstable(feature = "sip_hash_13", issue = "34767")]
#[rustc_deprecated(since = "1.13.0", reason = "use `DefaultHasher` instead")]
#[rustc_deprecated(since = "1.13.0",
reason = "use `std::collections::hash_map::DefaultHasher` instead")]
pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher13 {
SipHasher13 {
hasher: Hasher::new_with_keys(key0, key1)
@ -179,7 +185,8 @@ impl SipHasher24 {
/// Creates a new `SipHasher24` with the two initial keys set to 0.
#[inline]
#[unstable(feature = "sip_hash_13", issue = "34767")]
#[rustc_deprecated(since = "1.13.0", reason = "use `DefaultHasher` instead")]
#[rustc_deprecated(since = "1.13.0",
reason = "use `std::collections::hash_map::DefaultHasher` instead")]
pub fn new() -> SipHasher24 {
SipHasher24::new_with_keys(0, 0)
}
@ -187,7 +194,8 @@ impl SipHasher24 {
/// Creates a `SipHasher24` that is keyed off the provided keys.
#[inline]
#[unstable(feature = "sip_hash_13", issue = "34767")]
#[rustc_deprecated(since = "1.13.0", reason = "use `DefaultHasher` instead")]
#[rustc_deprecated(since = "1.13.0",
reason = "use `std::collections::hash_map::DefaultHasher` instead")]
pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher24 {
SipHasher24 {
hasher: Hasher::new_with_keys(key0, key1)
@ -225,6 +233,37 @@ impl<S: Sip> Hasher<S> {
self.state.v3 = self.k1 ^ 0x7465646279746573;
self.ntail = 0;
}
// Specialized write function that is only valid for buffers with len <= 8.
// It's used to force inlining of write_u8 and write_usize, those would normally be inlined
// except for composite types (that includes slices and str hashing because of delimiter).
// Without this extra push the compiler is very reluctant to inline delimiter writes,
// degrading performance substantially for the most common use cases.
#[inline(always)]
fn short_write(&mut self, msg: &[u8]) {
debug_assert!(msg.len() <= 8);
let length = msg.len();
self.length += length;
let needed = 8 - self.ntail;
let fill = cmp::min(length, needed);
if fill == 8 {
self.tail = unsafe { load_int_le!(msg, 0, u64) };
} else {
self.tail |= unsafe { u8to64_le(msg, 0, fill) } << (8 * self.ntail);
if length < needed {
self.ntail += length;
return;
}
}
self.state.v3 ^= self.tail;
S::c_rounds(&mut self.state);
self.state.v0 ^= self.tail;
// Buffered tail is now flushed, process new input.
self.ntail = length - needed;
self.tail = unsafe { u8to64_le(msg, needed, self.ntail) };
}
}
#[stable(feature = "rust1", since = "1.0.0")]
@ -267,6 +306,21 @@ impl super::Hasher for SipHasher24 {
}
impl<S: Sip> super::Hasher for Hasher<S> {
// see short_write comment for explanation
#[inline]
fn write_usize(&mut self, i: usize) {
let bytes = unsafe {
::slice::from_raw_parts(&i as *const usize as *const u8, mem::size_of::<usize>())
};
self.short_write(bytes);
}
// see short_write comment for explanation
#[inline]
fn write_u8(&mut self, i: u8) {
self.short_write(&[i]);
}
#[inline]
fn write(&mut self, msg: &[u8]) {
let length = msg.len();
@ -276,19 +330,16 @@ impl<S: Sip> super::Hasher for Hasher<S> {
if self.ntail != 0 {
needed = 8 - self.ntail;
self.tail |= unsafe { u8to64_le(msg, 0, cmp::min(length, needed)) } << 8 * self.ntail;
if length < needed {
self.tail |= u8to64_le!(msg, 0, length) << 8 * self.ntail;
self.ntail += length;
return
} else {
self.state.v3 ^= self.tail;
S::c_rounds(&mut self.state);
self.state.v0 ^= self.tail;
self.ntail = 0;
}
let m = self.tail | u8to64_le!(msg, 0, needed) << 8 * self.ntail;
self.state.v3 ^= m;
S::c_rounds(&mut self.state);
self.state.v0 ^= m;
self.ntail = 0;
}
// Buffered tail is now flushed, process new input.
@ -297,7 +348,7 @@ impl<S: Sip> super::Hasher for Hasher<S> {
let mut i = needed;
while i < len - left {
let mi = unsafe { load_u64_le(msg, i) };
let mi = unsafe { load_int_le!(msg, i, u64) };
self.state.v3 ^= mi;
S::c_rounds(&mut self.state);
@ -306,7 +357,7 @@ impl<S: Sip> super::Hasher for Hasher<S> {
i += 8;
}
self.tail = u8to64_le!(msg, i, left);
self.tail = unsafe { u8to64_le(msg, i, left) };
self.ntail = left;
}

View File

@ -0,0 +1,62 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// implements the unary operator "op &T"
// based on "op T" where T is expected to be `Copy`able
macro_rules! forward_ref_unop {
(impl $imp:ident, $method:ident for $t:ty) => {
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a> $imp for &'a $t {
type Output = <$t as $imp>::Output;
#[inline]
fn $method(self) -> <$t as $imp>::Output {
$imp::$method(*self)
}
}
}
}
// implements binary operators "&T op U", "T op &U", "&T op &U"
// based on "T op U" where T and U are expected to be `Copy`able
macro_rules! forward_ref_binop {
(impl $imp:ident, $method:ident for $t:ty, $u:ty) => {
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a> $imp<$u> for &'a $t {
type Output = <$t as $imp<$u>>::Output;
#[inline]
fn $method(self, other: $u) -> <$t as $imp<$u>>::Output {
$imp::$method(*self, other)
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a> $imp<&'a $u> for $t {
type Output = <$t as $imp<$u>>::Output;
#[inline]
fn $method(self, other: &'a $u) -> <$t as $imp<$u>>::Output {
$imp::$method(self, *other)
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, 'b> $imp<&'a $u> for &'b $t {
type Output = <$t as $imp<$u>>::Output;
#[inline]
fn $method(self, other: &'a $u) -> <$t as $imp<$u>>::Output {
$imp::$method(*self, *other)
}
}
}
}

View File

@ -194,14 +194,12 @@ extern "rust-intrinsic" {
/// own, or if it does not enable any significant optimizations.
pub fn assume(b: bool);
#[cfg(not(stage0))]
/// Hints to the compiler that branch condition is likely to be true.
/// Returns the value passed to it.
///
/// Any use other than with `if` statements will probably not have an effect.
pub fn likely(b: bool) -> bool;
#[cfg(not(stage0))]
/// Hints to the compiler that branch condition is likely to be false.
/// Returns the value passed to it.
///
@ -596,6 +594,19 @@ extern "rust-intrinsic" {
/// Invokes memset on the specified pointer, setting `count * size_of::<T>()`
/// bytes of memory starting at `dst` to `val`.
///
/// # Examples
///
/// ```
/// use std::ptr;
///
/// let mut vec = vec![0; 4];
/// unsafe {
/// let vec_ptr = vec.as_mut_ptr();
/// ptr::write_bytes(vec_ptr, b'a', 2);
/// }
/// assert_eq!(vec, [b'a', b'a', 0, 0]);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn write_bytes<T>(dst: *mut T, val: u8, count: usize);

Some files were not shown because too many files have changed in this diff Show More