mirror of
https://git.proxmox.com/git/rustc
synced 2026-01-15 04:41:06 +00:00
Imported Upstream version 1.1.0+dfsg1
This commit is contained in:
parent
bd371182c2
commit
d9579d0f11
@ -735,8 +735,8 @@ Rob Arnold <robarnold@cs.cmu.edu>
|
||||
Rob Hoelz <rob@hoelz.ro>
|
||||
Robert Buonpastore <robert.buonpastore@gmail.com>
|
||||
Robert Clipsham <robert@octarineparrot.com>
|
||||
Robert Foss <dev@robertfoss.se>
|
||||
Robert Gawdzik <rgawdzik@hotmail.com>
|
||||
Robert Foss <dev@robertfoss.se>
|
||||
Robert Irelan <rirelan@gmail.com>
|
||||
Robert Knight <robertknight@gmail.com>
|
||||
Robert Millar <robert.millar@cantab.net>
|
||||
|
||||
@ -76,7 +76,7 @@
|
||||
#
|
||||
# * `CFG_ENABLE_VALGRIND=1` - Run tests under valgrind
|
||||
# * `VALGRIND_COMPILE=1` - Run the compiler itself under valgrind
|
||||
# (may require `CFG_ENABLE_VALGRIND`)
|
||||
# (requires `CFG_ENABLE_VALGRIND`)
|
||||
#
|
||||
# * `NO_REBUILD=1` - Don't rebootstrap when testing std
|
||||
# (and possibly other crates)
|
||||
|
||||
@ -87,9 +87,11 @@ fetch snapshots, and an OS that can execute the available snapshot binaries.
|
||||
|
||||
Snapshot binaries are currently built and tested on several platforms:
|
||||
|
||||
* Windows (7, 8, Server 2008 R2), x86 and x86-64 (64-bit support added in Rust 0.12.0)
|
||||
* Linux (2.6.18 or later, various distributions), x86 and x86-64
|
||||
* OSX 10.7 (Lion) or greater, x86 and x86-64
|
||||
| Platform \ Architecture | x86 | x86_64 |
|
||||
|--------------------------------|-----|--------|
|
||||
| Windows (7, 8, Server 2008 R2) | ✓ | ✓ |
|
||||
| Linux (2.6.18 or later) | ✓ | ✓ |
|
||||
| OSX (10.7 Lion or later) | ✓ | ✓ |
|
||||
|
||||
You may find that other platforms work, but these are our officially
|
||||
supported build environments that are most likely to work.
|
||||
|
||||
113
RELEASES.md
113
RELEASES.md
@ -1,3 +1,116 @@
|
||||
Version 1.1.0 (June 2015)
|
||||
=========================
|
||||
|
||||
* ~850 changes, numerous bugfixes
|
||||
|
||||
Highlights
|
||||
----------
|
||||
|
||||
* The [`std::fs` module has been expanded][fs-expand] to expand the set of
|
||||
functionality exposed:
|
||||
* `DirEntry` now supports optimizations like `file_type` and `metadata` which
|
||||
don't incur a syscall on some platforms.
|
||||
* A `symlink_metadata` function has been added.
|
||||
* The `fs::Metadata` structure now lowers to its OS counterpart, providing
|
||||
access to all underlying information.
|
||||
* The compiler contains extended explanations of many errors. When it
|
||||
emits such an error it also suggests using the `--explain` flag to
|
||||
read the extended explanations, which are also [cataloged on the web
|
||||
site][err].
|
||||
* Thanks to multiple [improvements][sk] to [type checking][pre], as
|
||||
well as other work, the time to bootstrap the compiler decreased by
|
||||
32%.
|
||||
|
||||
Libraries
|
||||
---------
|
||||
|
||||
* The `str::split_whitespace` method splits a string on unicode
|
||||
whitespace boundaries.
|
||||
* On both Windows and Unix, new extension traits provide conversion of
|
||||
I/O types to and from the underlying system handles. On Unix, these
|
||||
traits are [`FrowRawFd`] and [`AsRawFd`], on Windows `FromRawHandle`
|
||||
and `AsRawHandle`. These are implemented for `File`, `TcpStream`,
|
||||
`TcpListener`, and `UpdSocket`. Further implementations for
|
||||
`std::process` will be stabilized later.
|
||||
* On Unix, [`std::os::unix::symlink`] creates symlinks. On
|
||||
Windows, symlinks can be created with
|
||||
`std::os::windows::symlink_dir` and
|
||||
`std::os::windows::symlink_file`.
|
||||
* The `mpsc::Receiver` type can now be converted into an iterator with
|
||||
`into_iter` on the [`IntoIterator`] trait.
|
||||
* `Ipv4Addr` can be created from `u32` with the `From<u32>`
|
||||
implementation of the [`From`] trait.
|
||||
* The `Debug` implementation for `RangeFull` [creates output that is
|
||||
more consistent with other implementations][rf].
|
||||
* [`Debug` is implemented for `File`][file].
|
||||
* The `Default` implementation for `Arc` [no longer requires `Sync +
|
||||
Send`][arc].
|
||||
* [The `Iterator` methods `count`, `nth`, and `last` have been
|
||||
overridden for slices to have O(1) performance instead of O(n)][si].
|
||||
* Incorrect handling of paths on Windows has been improved in both the
|
||||
compiler and the standard library.
|
||||
* [`AtomicPtr` gained a `Default` implementation][ap].
|
||||
* In accordance with Rust's policy on arithmetic overflow `abs` now
|
||||
[panics on overflow when debug assertions are enabled][abs].
|
||||
* The [`Cloned`] iterator, which was accidentally left unstable for
|
||||
1.0 [has been stabilized][c].
|
||||
* The [`Incoming`] iterator, which iterates over incoming TCP
|
||||
connections, and which was accidentally unnamable in 1.0, [is now
|
||||
properly exported][inc].
|
||||
* [`BinaryHeap`] no longer corrupts itself [when functions called by
|
||||
`sift_up` or `sift_down` panic][bh].
|
||||
* The [`split_off`] method of `LinkedList` [no longer corrupts
|
||||
the list in certain scenarios][ll].
|
||||
|
||||
Misc
|
||||
----
|
||||
|
||||
* Type checking performance [has improved notably][sk] with
|
||||
[multiple improvements][pre].
|
||||
* The compiler [suggests code changes][ch] for more errors.
|
||||
* rustc and it's build system have experimental support for [building
|
||||
toolchains against MUSL][m] instead of glibc on Linux.
|
||||
* The compiler defines the `target_env` cfg value, which is used for
|
||||
distinguishing toolchains that are otherwise for the same
|
||||
platform. Presently this is set to `gnu` for common GNU Linux
|
||||
targets and for MinGW targets, and `musl` for MUSL Linux targets.
|
||||
* The [`cargo rustc`][crc] command invokes a build with custom flags
|
||||
to rustc.
|
||||
* [Android executables are always position independent][pie].
|
||||
* [The `drop_with_repr_extern` lint warns about mixing `repr(C)`
|
||||
with `Drop`][drop].
|
||||
|
||||
[`split_whitespace`]: http://doc.rust-lang.org/nightly/std/primitive.str.html#method.split_whitespace
|
||||
[`Iterator::cloned`]: http://doc.rust-lang.org/nightly/core/iter/trait.Iterator.html#method.cloned
|
||||
[`FromRawFd`]: http://doc.rust-lang.org/nightly/std/os/unix/io/trait.FromRawFd.html
|
||||
[`AsRawFd`]: http://doc.rust-lang.org/nightly/std/os/unix/io/trait.AsRawFd.html
|
||||
[`std::os::unix::symlink`]: http://doc.rust-lang.org/nightly/std/os/unix/fs/fn.symlink.html
|
||||
[`IntoIterator`]: http://doc.rust-lang.org/nightly/std/iter/trait.IntoIterator.html
|
||||
[`From`]: http://doc.rust-lang.org/nightly/std/convert/trait.From.html
|
||||
[rf]: https://github.com/rust-lang/rust/pull/24491
|
||||
[err]: http://doc.rust-lang.org/error-index.html
|
||||
[sk]: https://github.com/rust-lang/rust/pull/24615
|
||||
[pre]: https://github.com/rust-lang/rust/pull/25323
|
||||
[file]: https://github.com/rust-lang/rust/pull/24598
|
||||
[ch]: https://github.com/rust-lang/rust/pull/24683
|
||||
[arc]: https://github.com/rust-lang/rust/pull/24695
|
||||
[si]: https://github.com/rust-lang/rust/pull/24701
|
||||
[ap]: https://github.com/rust-lang/rust/pull/24834
|
||||
[m]: https://github.com/rust-lang/rust/pull/24777
|
||||
[fs]: https://github.com/rust-lang/rfcs/blob/master/text/1044-io-fs-2.1.md
|
||||
[crc]: https://github.com/rust-lang/cargo/pull/1568
|
||||
[pie]: https://github.com/rust-lang/rust/pull/24953
|
||||
[abs]: https://github.com/rust-lang/rust/pull/25441
|
||||
[c]: https://github.com/rust-lang/rust/pull/25496
|
||||
[`Cloned`]: http://doc.rust-lang.org/nightly/std/iter/struct.Cloned.html
|
||||
[`Incoming`]: http://doc.rust-lang.org/nightly/std/net/struct.Incoming.html
|
||||
[inc]: https://github.com/rust-lang/rust/pull/25522
|
||||
[bh]: https://github.com/rust-lang/rust/pull/25856
|
||||
[`BinaryHeap`]: http://doc.rust-lang.org/nightly/std/collections/struct.BinaryHeap.html
|
||||
[ll]: https://github.com/rust-lang/rust/pull/26022
|
||||
[`split_off`]: http://doc.rust-lang.org/nightly/collections/linked_list/struct.LinkedList.html#method.split_off
|
||||
[drop]: https://github.com/rust-lang/rust/pull/24935
|
||||
|
||||
Version 1.0.0 (May 2015)
|
||||
========================
|
||||
|
||||
|
||||
75
configure
vendored
75
configure
vendored
@ -19,6 +19,11 @@ err() {
|
||||
exit 1
|
||||
}
|
||||
|
||||
run() {
|
||||
msg "$@"
|
||||
"$@"
|
||||
}
|
||||
|
||||
need_ok() {
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
@ -36,8 +41,7 @@ need_cmd() {
|
||||
make_dir() {
|
||||
if [ ! -d $1 ]
|
||||
then
|
||||
msg "mkdir -p $1"
|
||||
mkdir -p $1
|
||||
run mkdir -p $1
|
||||
fi
|
||||
}
|
||||
|
||||
@ -46,8 +50,7 @@ copy_if_changed() {
|
||||
then
|
||||
msg "leaving $2 unchanged"
|
||||
else
|
||||
msg "cp $1 $2"
|
||||
cp -f $1 $2
|
||||
run cp -f $1 $2
|
||||
chmod u-w $2 # make copied artifact read-only
|
||||
fi
|
||||
}
|
||||
@ -57,8 +60,7 @@ move_if_changed() {
|
||||
then
|
||||
msg "leaving $2 unchanged"
|
||||
else
|
||||
msg "mv $1 $2"
|
||||
mv -f $1 $2
|
||||
run mv -f $1 $2
|
||||
chmod u-w $2 # make moved artifact read-only
|
||||
fi
|
||||
}
|
||||
@ -104,8 +106,8 @@ probe() {
|
||||
T=$(command -v $P 2>&1)
|
||||
if [ $? -eq 0 ]
|
||||
then
|
||||
VER0=$($P --version 2>/dev/null | head -1 \
|
||||
| sed -e 's/[^0-9]*\([vV]\?[0-9.]\+[^ ]*\).*/\1/' )
|
||||
VER0=$($P --version 2>/dev/null \
|
||||
| grep -o '[vV]\?[0-9][0-9.][a-z0-9.-]*' | head -1 )
|
||||
if [ $? -eq 0 -a "x${VER0}" != "x" ]
|
||||
then
|
||||
VER="($VER0)"
|
||||
@ -337,6 +339,15 @@ to_gnu_triple() {
|
||||
esac
|
||||
}
|
||||
|
||||
# Prints the absolute path of a directory to stdout
|
||||
abs_path() {
|
||||
local _path="$1"
|
||||
# Unset CDPATH because it causes havok: it makes the destination unpredictable
|
||||
# and triggers 'cd' to print the path to stdout. Route `cd`'s output to /dev/null
|
||||
# for good measure.
|
||||
(unset CDPATH && cd "$_path" > /dev/null && pwd)
|
||||
}
|
||||
|
||||
msg "looking for configure programs"
|
||||
need_cmd cmp
|
||||
need_cmd mkdir
|
||||
@ -509,7 +520,7 @@ fi
|
||||
|
||||
DEFAULT_BUILD="${CFG_CPUTYPE}-${CFG_OSTYPE}"
|
||||
|
||||
CFG_SRC_DIR="$(cd $(dirname $0) && pwd)/"
|
||||
CFG_SRC_DIR="$(abs_path $(dirname $0))/"
|
||||
CFG_BUILD_DIR="$(pwd)/"
|
||||
CFG_SELF="$0"
|
||||
CFG_CONFIGURE_ARGS="$@"
|
||||
@ -535,13 +546,14 @@ fi
|
||||
BOOL_OPTIONS=""
|
||||
VAL_OPTIONS=""
|
||||
|
||||
opt debug 0 "debug mode"
|
||||
opt debug 0 "debug mode; disables optimization unless \`--enable-optimize\` given"
|
||||
opt valgrind 0 "run tests with valgrind (memcheck by default)"
|
||||
opt helgrind 0 "run tests with helgrind instead of memcheck"
|
||||
opt valgrind-rpass 1 "run rpass-valgrind tests with valgrind"
|
||||
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 libcpp 1 "build with 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"
|
||||
@ -574,12 +586,14 @@ 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 "/opt/ndk_standalone" "Android NDK standalone path"
|
||||
valopt release-channel "dev" "the name of the release channel to build"
|
||||
valopt musl-root "/usr/local" "MUSL root installation directory"
|
||||
|
||||
# Many of these are saved below during the "writing configuration" step
|
||||
# (others are conditionally saved).
|
||||
opt_nosave manage-submodules 1 "let the build manage the git submodules"
|
||||
opt_nosave clang 0 "prefer clang to gcc for building the runtime"
|
||||
opt_nosave jemalloc 1 "build liballoc with jemalloc"
|
||||
opt elf-tls 1 "elf thread local storage on platforms where supported"
|
||||
|
||||
valopt_nosave prefix "/usr/local" "set installation prefix"
|
||||
valopt_nosave local-rust-root "/usr/local" "set prefix for local rust binary"
|
||||
@ -650,9 +664,10 @@ if [ -n "$CFG_ENABLE_DEBUG" ]; then
|
||||
CFG_DISABLE_OPTIMIZE=1
|
||||
CFG_DISABLE_OPTIMIZE_CXX=1
|
||||
fi
|
||||
CFG_ENABLE_LLVM_ASSERTIONS=1
|
||||
CFG_ENABLE_DEBUG_ASSERTIONS=1
|
||||
CFG_ENABLE_DEBUG_JEMALLOC=1
|
||||
CFG_ENABLE_DEBUGINFO=1
|
||||
CFG_ENABLE_LLVM_ASSERTIONS=1
|
||||
fi
|
||||
|
||||
# OK, now write the debugging options
|
||||
@ -697,6 +712,20 @@ else
|
||||
probe_need CFG_GIT git
|
||||
fi
|
||||
|
||||
# Use `md5sum` on GNU platforms, or `md5 -q` on BSD
|
||||
probe CFG_MD5 md5
|
||||
probe CFG_MD5SUM md5sum
|
||||
if [ -n "$CFG_MD5" ]
|
||||
then
|
||||
CFG_HASH_COMMAND="$CFG_MD5 -q | head -c 8"
|
||||
elif [ -n "$CFG_MD5SUM" ]
|
||||
then
|
||||
CFG_HASH_COMMAND="$CFG_MD5SUM | head -c 8"
|
||||
else
|
||||
err 'could not find one of: md5 md5sum'
|
||||
fi
|
||||
putvar CFG_HASH_COMMAND
|
||||
|
||||
probe CFG_CLANG clang++
|
||||
probe CFG_CCACHE ccache
|
||||
probe CFG_GCC gcc
|
||||
@ -721,6 +750,20 @@ then
|
||||
probe CFG_JAVAC javac
|
||||
fi
|
||||
|
||||
# the valgrind rpass tests will fail if you don't have a valgrind, but they're
|
||||
# only disabled if you opt out.
|
||||
if [ -z "$CFG_VALGRIND" ]
|
||||
then
|
||||
# If the user has explicitly asked for valgrind tests, then fail
|
||||
if [ -n "$CFG_ENABLE_VALGRIND" ] && [ -n "$CFG_ENABLE_VALGRIND_PROVIDED" ]
|
||||
then
|
||||
err "No valgrind present, but valgrind tests explicitly requested"
|
||||
else
|
||||
CFG_DISABLE_VALGRIND_RPASS=1
|
||||
putvar CFG_DISABLE_VALGRIND_RPASS
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ ! -z "$CFG_GDB" ]
|
||||
then
|
||||
# Store GDB's version
|
||||
@ -832,7 +875,7 @@ then
|
||||
CFG_OSX_GCC_VERSION=$("$CFG_GCC" --version 2>&1 | grep "Apple LLVM version")
|
||||
if [ $? -eq 0 ]
|
||||
then
|
||||
step_msg "on OS X 10.9, forcing use of clang"
|
||||
step_msg "on OS X >=10.9, forcing use of clang"
|
||||
CFG_ENABLE_CLANG=1
|
||||
else
|
||||
if [ $("$CFG_GCC" --version 2>&1 | grep -c ' 4\.[0-6]') -ne 0 ]; then
|
||||
@ -1048,6 +1091,13 @@ do
|
||||
fi
|
||||
;;
|
||||
|
||||
|
||||
*-musl)
|
||||
if [ ! -f $CFG_MUSL_ROOT/lib/libc.a ]
|
||||
then
|
||||
err "musl libc $CFG_MUSL_ROOT/lib/libc.a not found"
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
;;
|
||||
esac
|
||||
@ -1134,6 +1184,7 @@ do
|
||||
make_dir $h/test/run-pass-valgrind
|
||||
make_dir $h/test/run-pass-fulldeps
|
||||
make_dir $h/test/run-fail
|
||||
make_dir $h/test/run-fail-fulldeps
|
||||
make_dir $h/test/compile-fail
|
||||
make_dir $h/test/parse-fail
|
||||
make_dir $h/test/compile-fail-fulldeps
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
.TH RUSTC "1" "March 2014" "rustc 0.13.0" "User Commands"
|
||||
.TH RUSTC "1" "June 2015" "rustc 1.1.0" "User Commands"
|
||||
.SH NAME
|
||||
rustc \- The Rust compiler
|
||||
.SH SYNOPSIS
|
||||
@ -160,7 +160,7 @@ If the value is 'help', then a list of available CPUs is printed.
|
||||
\fBtarget\-feature\fR='\fI+feature1\fR,\fI\-feature2\fR'
|
||||
A comma\[hy]separated list of features to enable or disable for the target.
|
||||
A preceding '+' enables a feature while a preceding '\-' disables it.
|
||||
Available features can be discovered through \fItarget\-cpu=help\fR.
|
||||
Available features can be discovered through \fIllc -mcpu=help\fR.
|
||||
.TP
|
||||
\fBpasses\fR=\fIval\fR
|
||||
A space\[hy]separated list of extra LLVM passes to run.
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
.TH RUSTDOC "1" "March 2014" "rustdoc 0.13.0" "User Commands"
|
||||
.TH RUSTDOC "1" "June 2015" "rustdoc 1.1.0" "User Commands"
|
||||
.SH NAME
|
||||
rustdoc \- generate documentation from Rust source code
|
||||
.SH SYNOPSIS
|
||||
|
||||
@ -20,16 +20,12 @@ CFG_GCCISH_CFLAGS_aarch64-apple-ios := -Wall -Werror -fPIC $(CFG_IOS_SDK_FLAGS_a
|
||||
CFG_GCCISH_CXXFLAGS_aarch64-apple-ios := -fno-rtti $(CFG_IOS_SDK_FLAGS_aarch64-apple-ios) -I$(CFG_IOS_SDK_aarch64-apple-ios)/usr/include/c++/4.2.1
|
||||
CFG_GCCISH_LINK_FLAGS_aarch64-apple-ios := -lpthread -syslibroot $(CFG_IOS_SDK_aarch64-apple-ios) -Wl,-no_compact_unwind
|
||||
CFG_GCCISH_DEF_FLAG_aarch64-apple-ios := -Wl,-exported_symbols_list,
|
||||
CFG_GCCISH_PRE_LIB_FLAGS_aarch64-apple-ios :=
|
||||
CFG_GCCISH_POST_LIB_FLAGS_aarch64-apple-ios :=
|
||||
CFG_DEF_SUFFIX_aarch64-apple-ios := .darwin.def
|
||||
CFG_LLC_FLAGS_aarch64-apple-ios := -mattr=+neon,+cyclone,+fp-armv8
|
||||
CFG_INSTALL_NAME_aarch64-apple-ios = -Wl,-install_name,@rpath/$(1)
|
||||
CFG_LIBUV_LINK_FLAGS_aarch64-apple-ios =
|
||||
CFG_EXE_SUFFIX_aarch64-apple-ios :=
|
||||
CFG_WINDOWSY_aarch64-apple-ios :=
|
||||
CFG_UNIXY_aarch64-apple-ios := 1
|
||||
CFG_PATH_MUNGE_aarch64-apple-ios := true
|
||||
CFG_LDPATH_aarch64-apple-ios :=
|
||||
CFG_RUN_aarch64-apple-ios = $(2)
|
||||
CFG_RUN_TARG_aarch64-apple-ios = $(call CFG_RUN_aarch64-apple-ios,,$(2))
|
||||
|
||||
@ -13,15 +13,11 @@ CFG_GCCISH_CFLAGS_aarch64-linux-android := -Wall -g -fPIC -D__aarch64__ -DANDROI
|
||||
CFG_GCCISH_CXXFLAGS_aarch64-linux-android := -fno-rtti $(CXXFLAGS)
|
||||
CFG_GCCISH_LINK_FLAGS_aarch64-linux-android := -shared -fPIC -ldl -g -lm -lsupc++
|
||||
CFG_GCCISH_DEF_FLAG_aarch64-linux-android := -Wl,--export-dynamic,--dynamic-list=
|
||||
CFG_GCCISH_PRE_LIB_FLAGS_aarch64-linux-android := -Wl,-whole-archive
|
||||
CFG_GCCISH_POST_LIB_FLAGS_aarch64-linux-android := -Wl,-no-whole-archive
|
||||
CFG_DEF_SUFFIX_aarch64-linux-android := .android.def
|
||||
CFG_LLC_FLAGS_aarch64-linux-android :=
|
||||
CFG_INSTALL_NAME_aarch64-linux-android =
|
||||
CFG_EXE_SUFFIX_aarch64-linux-android :=
|
||||
CFG_WINDOWSY_aarch64-linux-android :=
|
||||
CFG_UNIXY_aarch64-linux-android := 1
|
||||
CFG_PATH_MUNGE_aarch64-linux-android := true
|
||||
CFG_LDPATH_aarch64-linux-android :=
|
||||
CFG_RUN_aarch64-linux-android=
|
||||
CFG_RUN_TARG_aarch64-linux-android=
|
||||
|
||||
@ -13,15 +13,11 @@ CFG_GCCISH_CFLAGS_aarch64-unknown-linux-gnu := -Wall -g -fPIC -D__aarch64__ $(CF
|
||||
CFG_GCCISH_CXXFLAGS_aarch64-unknown-linux-gnu := -fno-rtti $(CXXFLAGS)
|
||||
CFG_GCCISH_LINK_FLAGS_aarch64-unknown-linux-gnu := -shared -fPIC -g
|
||||
CFG_GCCISH_DEF_FLAG_aarch64-unknown-linux-gnu := -Wl,--export-dynamic,--dynamic-list=
|
||||
CFG_GCCISH_PRE_LIB_FLAGS_aarch64-unknown-linux-gnu := -Wl,-whole-archive
|
||||
CFG_GCCISH_POST_LIB_FLAGS_aarch64-unknown-linux-gnu := -Wl,-no-whole-archive
|
||||
CFG_DEF_SUFFIX_aarch64-unknown-linux-gnu := .linux.def
|
||||
CFG_LLC_FLAGS_aarch64-unknown-linux-gnu :=
|
||||
CFG_INSTALL_NAME_aarch64-unknown-linux-gnu =
|
||||
CFG_EXE_SUFFIX_aarch64-unknown-linux-gnu :=
|
||||
CFG_WINDOWSY_aarch64-unknown-linux-gnu :=
|
||||
CFG_UNIXY_aarch64-unknown-linux-gnu := 1
|
||||
CFG_PATH_MUNGE_aarch64-unknown-linux-gnu := true
|
||||
CFG_LDPATH_aarch64-unknown-linux-gnu :=
|
||||
CFG_RUN_aarch64-unknown-linux-gnu=$(2)
|
||||
CFG_RUN_TARG_aarch64-unknown-linux-gnu=$(call CFG_RUN_aarch64-unknown-linux-gnu,,$(2))
|
||||
|
||||
@ -12,15 +12,11 @@ CFG_GCCISH_CFLAGS_arm-linux-androideabi := -Wall -g -fPIC -D__arm__ -DANDROID -D
|
||||
CFG_GCCISH_CXXFLAGS_arm-linux-androideabi := -fno-rtti $(CXXFLAGS)
|
||||
CFG_GCCISH_LINK_FLAGS_arm-linux-androideabi := -shared -fPIC -ldl -g -lm -lsupc++
|
||||
CFG_GCCISH_DEF_FLAG_arm-linux-androideabi := -Wl,--export-dynamic,--dynamic-list=
|
||||
CFG_GCCISH_PRE_LIB_FLAGS_arm-linux-androideabi := -Wl,-whole-archive
|
||||
CFG_GCCISH_POST_LIB_FLAGS_arm-linux-androideabi := -Wl,-no-whole-archive
|
||||
CFG_DEF_SUFFIX_arm-linux-androideabi := .android.def
|
||||
CFG_LLC_FLAGS_arm-linux-androideabi :=
|
||||
CFG_INSTALL_NAME_arm-linux-androideabi =
|
||||
CFG_EXE_SUFFIX_arm-linux-androideabi :=
|
||||
CFG_WINDOWSY_arm-linux-androideabi :=
|
||||
CFG_UNIXY_arm-linux-androideabi := 1
|
||||
CFG_PATH_MUNGE_arm-linux-androideabi := true
|
||||
CFG_LDPATH_arm-linux-androideabi :=
|
||||
CFG_RUN_arm-linux-androideabi=
|
||||
CFG_RUN_TARG_arm-linux-androideabi=
|
||||
|
||||
@ -13,15 +13,11 @@ CFG_GCCISH_CFLAGS_arm-unknown-linux-gnueabi := -Wall -g -fPIC -D__arm__ -mfpu=vf
|
||||
CFG_GCCISH_CXXFLAGS_arm-unknown-linux-gnueabi := -fno-rtti $(CXXFLAGS)
|
||||
CFG_GCCISH_LINK_FLAGS_arm-unknown-linux-gnueabi := -shared -fPIC -g
|
||||
CFG_GCCISH_DEF_FLAG_arm-unknown-linux-gnueabi := -Wl,--export-dynamic,--dynamic-list=
|
||||
CFG_GCCISH_PRE_LIB_FLAGS_arm-unknown-linux-gnueabi := -Wl,-whole-archive
|
||||
CFG_GCCISH_POST_LIB_FLAGS_arm-unknown-linux-gnueabi := -Wl,-no-whole-archive
|
||||
CFG_DEF_SUFFIX_arm-unknown-linux-gnueabi := .linux.def
|
||||
CFG_LLC_FLAGS_arm-unknown-linux-gnueabi :=
|
||||
CFG_INSTALL_NAME_arm-unknown-linux-gnueabi =
|
||||
CFG_EXE_SUFFIX_arm-unknown-linux-gnueabi :=
|
||||
CFG_WINDOWSY_arm-unknown-linux-gnueabi :=
|
||||
CFG_UNIXY_arm-unknown-linux-gnueabi := 1
|
||||
CFG_PATH_MUNGE_arm-unknown-linux-gnueabi := true
|
||||
CFG_LDPATH_arm-unknown-linux-gnueabi :=
|
||||
CFG_RUN_arm-unknown-linux-gnueabi=$(2)
|
||||
CFG_RUN_TARG_arm-unknown-linux-gnueabi=$(call CFG_RUN_arm-unknown-linux-gnueabi,,$(2))
|
||||
|
||||
@ -13,15 +13,11 @@ CFG_GCCISH_CFLAGS_arm-unknown-linux-gnueabihf := -Wall -g -fPIC -D__arm__ $(CFLA
|
||||
CFG_GCCISH_CXXFLAGS_arm-unknown-linux-gnueabihf := -fno-rtti $(CXXFLAGS)
|
||||
CFG_GCCISH_LINK_FLAGS_arm-unknown-linux-gnueabihf := -shared -fPIC -g
|
||||
CFG_GCCISH_DEF_FLAG_arm-unknown-linux-gnueabihf := -Wl,--export-dynamic,--dynamic-list=
|
||||
CFG_GCCISH_PRE_LIB_FLAGS_arm-unknown-linux-gnueabihf := -Wl,-whole-archive
|
||||
CFG_GCCISH_POST_LIB_FLAGS_arm-unknown-linux-gnueabihf := -Wl,-no-whole-archive
|
||||
CFG_DEF_SUFFIX_arm-unknown-linux-gnueabihf := .linux.def
|
||||
CFG_LLC_FLAGS_arm-unknown-linux-gnueabihf :=
|
||||
CFG_INSTALL_NAME_ar,-unknown-linux-gnueabihf =
|
||||
CFG_EXE_SUFFIX_arm-unknown-linux-gnueabihf :=
|
||||
CFG_WINDOWSY_arm-unknown-linux-gnueabihf :=
|
||||
CFG_UNIXY_arm-unknown-linux-gnueabihf := 1
|
||||
CFG_PATH_MUNGE_arm-unknown-linux-gnueabihf := true
|
||||
CFG_LDPATH_arm-unknown-linux-gnueabihf :=
|
||||
CFG_RUN_arm-unknown-linux-gnueabihf=$(2)
|
||||
CFG_RUN_TARG_arm-unknown-linux-gnueabihf=$(call CFG_RUN_arm-unknown-linux-gnueabihf,,$(2))
|
||||
|
||||
@ -19,15 +19,11 @@ CFG_GCCISH_CFLAGS_armv7-apple-ios := -Wall -Werror -g -fPIC $(CFG_IOS_SDK_FLAGS_
|
||||
CFG_GCCISH_CXXFLAGS_armv7-apple-ios := -fno-rtti $(CFG_IOS_SDK_FLAGS_armv7-apple-ios) -I$(CFG_IOS_SDK_armv7-apple-ios)/usr/include/c++/4.2.1
|
||||
CFG_GCCISH_LINK_FLAGS_armv7-apple-ios := -lpthread -syslibroot $(CFG_IOS_SDK_armv7-apple-ios) -Wl,-no_compact_unwind
|
||||
CFG_GCCISH_DEF_FLAG_armv7-apple-ios := -Wl,-exported_symbols_list,
|
||||
CFG_GCCISH_PRE_LIB_FLAGS_armv7-apple-ios :=
|
||||
CFG_GCCISH_POST_LIB_FLAGS_armv7-apple-ios :=
|
||||
CFG_DEF_SUFFIX_armv7-apple-ios := .darwin.def
|
||||
CFG_LLC_FLAGS_armv7-apple-ios := -mattr=+vfp3,+v7,+neon -march=arm
|
||||
CFG_INSTALL_NAME_armv7-apple-ios = -Wl,-install_name,@rpath/$(1)
|
||||
CFG_EXE_SUFFIX_armv7-apple-ios :=
|
||||
CFG_WINDOWSY_armv7-apple-ios :=
|
||||
CFG_UNIXY_armv7-apple-ios := 1
|
||||
CFG_PATH_MUNGE_armv7-apple-ios := true
|
||||
CFG_LDPATH_armv7-apple-ios :=
|
||||
CFG_RUN_armv7-apple-ios = $(2)
|
||||
CFG_RUN_TARG_armv7-apple-ios = $(call CFG_RUN_armv7-apple-ios,,$(2))
|
||||
|
||||
@ -19,15 +19,11 @@ CFG_GCCISH_CFLAGS_armv7s-apple-ios := -Wall -Werror -g -fPIC $(CFG_IOS_SDK_FLAGS
|
||||
CFG_GCCISH_CXXFLAGS_armv7s-apple-ios := -fno-rtti $(CFG_IOS_SDK_FLAGS_armv7s-apple-ios) -I$(CFG_IOS_SDK_armv7s-apple-ios)/usr/include/c++/4.2.1
|
||||
CFG_GCCISH_LINK_FLAGS_armv7s-apple-ios := -lpthread -syslibroot $(CFG_IOS_SDK_armv7s-apple-ios) -Wl,-no_compact_unwind
|
||||
CFG_GCCISH_DEF_FLAG_armv7s-apple-ios := -Wl,-exported_symbols_list,
|
||||
CFG_GCCISH_PRE_LIB_FLAGS_armv7s-apple-ios :=
|
||||
CFG_GCCISH_POST_LIB_FLAGS_armv7s-apple-ios :=
|
||||
CFG_DEF_SUFFIX_armv7s-apple-ios := .darwin.def
|
||||
CFG_LLC_FLAGS_armv7s-apple-ios := -mattr=+vfp4,+v7,+neon
|
||||
CFG_INSTALL_NAME_armv7s-apple-ios = -Wl,-install_name,@rpath/$(1)
|
||||
CFG_EXE_SUFFIX_armv7s-apple-ios :=
|
||||
CFG_WINDOWSY_armv7s-apple-ios :=
|
||||
CFG_UNIXY_armv7s-apple-ios := 1
|
||||
CFG_PATH_MUNGE_armv7s-apple-ios := true
|
||||
CFG_LDPATH_armv7s-apple-ios :=
|
||||
CFG_RUN_armv7s-apple-ios = $(2)
|
||||
CFG_RUN_TARG_armv7s-apple-ios = $(call CFG_RUN_armv7s-apple-ios,,$(2))
|
||||
|
||||
@ -18,15 +18,11 @@ CFG_GCCISH_CFLAGS_i386-apple-ios := -Wall -Werror -g -fPIC -m32 $(CFG_IOSSIM_FLA
|
||||
CFG_GCCISH_CXXFLAGS_i386-apple-ios := -fno-rtti $(CFG_IOSSIM_FLAGS_i386-apple-ios) -I$(CFG_IOSSIM_SDK_i386-apple-ios)/usr/include/c++/4.2.1
|
||||
CFG_GCCISH_LINK_FLAGS_i386-apple-ios := -lpthread -m32 -Wl,-no_compact_unwind -m32 -Wl,-syslibroot $(CFG_IOSSIM_SDK_i386-apple-ios)
|
||||
CFG_GCCISH_DEF_FLAG_i386-apple-ios := -Wl,-exported_symbols_list,
|
||||
CFG_GCCISH_PRE_LIB_FLAGS_i386-apple-ios :=
|
||||
CFG_GCCISH_POST_LIB_FLAGS_i386-apple-ios :=
|
||||
CFG_DEF_SUFFIX_i386-apple-ios := .darwin.def
|
||||
CFG_LLC_FLAGS_i386-apple-ios =
|
||||
CFG_INSTALL_NAME_i386-apple-ios = -Wl,-install_name,@rpath/$(1)
|
||||
CFG_EXE_SUFFIX_i386-apple-ios :=
|
||||
CFG_WINDOWSY_i386-apple-ios :=
|
||||
CFG_UNIXY_i386-apple-ios := 1
|
||||
CFG_PATH_MUNGE_i386-apple-ios = :true
|
||||
CFG_LDPATH_i386-apple-ios =
|
||||
CFG_RUN_i386-apple-ios = $(2)
|
||||
CFG_RUN_TARG_i386-apple-ios = $(call CFG_RUN_i386-apple-ios,,$(2))
|
||||
|
||||
@ -12,15 +12,11 @@ CFG_GCCISH_CFLAGS_i686-apple-darwin := -Wall -Werror -g -fPIC -m32 -arch i386 $(
|
||||
CFG_GCCISH_CXXFLAGS_i686-apple-darwin := -fno-rtti $(CXXFLAGS)
|
||||
CFG_GCCISH_LINK_FLAGS_i686-apple-darwin := -dynamiclib -pthread -framework CoreServices -m32
|
||||
CFG_GCCISH_DEF_FLAG_i686-apple-darwin := -Wl,-exported_symbols_list,
|
||||
CFG_GCCISH_PRE_LIB_FLAGS_i686-apple-darwin :=
|
||||
CFG_GCCISH_POST_LIB_FLAGS_i686-apple-darwin :=
|
||||
CFG_DEF_SUFFIX_i686-apple-darwin := .darwin.def
|
||||
CFG_LLC_FLAGS_i686-apple-darwin :=
|
||||
CFG_INSTALL_NAME_i686-apple-darwin = -Wl,-install_name,@rpath/$(1)
|
||||
CFG_EXE_SUFFIX_i686-apple-darwin :=
|
||||
CFG_WINDOWSY_i686-apple-darwin :=
|
||||
CFG_UNIXY_i686-apple-darwin := 1
|
||||
CFG_PATH_MUNGE_i686-apple-darwin := true
|
||||
CFG_LDPATH_i686-apple-darwin :=
|
||||
CFG_RUN_i686-apple-darwin=$(2)
|
||||
CFG_RUN_TARG_i686-apple-darwin=$(call CFG_RUN_i686-apple-darwin,,$(2))
|
||||
|
||||
@ -13,15 +13,11 @@ CFG_GCCISH_CFLAGS_i686-pc-windows-gnu := -Wall -Werror -g -m32 -D_WIN32_WINNT=0x
|
||||
CFG_GCCISH_CXXFLAGS_i686-pc-windows-gnu := -fno-rtti $(CXXFLAGS)
|
||||
CFG_GCCISH_LINK_FLAGS_i686-pc-windows-gnu := -shared -g -m32
|
||||
CFG_GCCISH_DEF_FLAG_i686-pc-windows-gnu :=
|
||||
CFG_GCCISH_PRE_LIB_FLAGS_i686-pc-windows-gnu :=
|
||||
CFG_GCCISH_POST_LIB_FLAGS_i686-pc-windows-gnu :=
|
||||
CFG_DEF_SUFFIX_i686-pc-windows-gnu := .windows.def
|
||||
CFG_LLC_FLAGS_i686-pc-windows-gnu :=
|
||||
CFG_INSTALL_NAME_i686-pc-windows-gnu =
|
||||
CFG_EXE_SUFFIX_i686-pc-windows-gnu := .exe
|
||||
CFG_WINDOWSY_i686-pc-windows-gnu := 1
|
||||
CFG_UNIXY_i686-pc-windows-gnu :=
|
||||
CFG_PATH_MUNGE_i686-pc-windows-gnu :=
|
||||
CFG_LDPATH_i686-pc-windows-gnu :=
|
||||
CFG_RUN_i686-pc-windows-gnu=$(2)
|
||||
CFG_RUN_TARG_i686-pc-windows-gnu=$(call CFG_RUN_i686-pc-windows-gnu,,$(2))
|
||||
|
||||
@ -12,15 +12,11 @@ CFG_GCCISH_CFLAGS_i686-unknown-linux-gnu := -Wall -Werror -g -fPIC -m32 $(CFLAGS
|
||||
CFG_GCCISH_CXXFLAGS_i686-unknown-linux-gnu := -fno-rtti $(CXXFLAGS)
|
||||
CFG_GCCISH_LINK_FLAGS_i686-unknown-linux-gnu := -shared -fPIC -ldl -pthread -lrt -g -m32
|
||||
CFG_GCCISH_DEF_FLAG_i686-unknown-linux-gnu := -Wl,--export-dynamic,--dynamic-list=
|
||||
CFG_GCCISH_PRE_LIB_FLAGS_i686-unknown-linux-gnu := -Wl,-whole-archive
|
||||
CFG_GCCISH_POST_LIB_FLAGS_i686-unknown-linux-gnu := -Wl,-no-whole-archive
|
||||
CFG_DEF_SUFFIX_i686-unknown-linux-gnu := .linux.def
|
||||
CFG_LLC_FLAGS_i686-unknown-linux-gnu :=
|
||||
CFG_INSTALL_NAME_i686-unknown-linux-gnu =
|
||||
CFG_EXE_SUFFIX_i686-unknown-linux-gnu =
|
||||
CFG_WINDOWSY_i686-unknown-linux-gnu :=
|
||||
CFG_UNIXY_i686-unknown-linux-gnu := 1
|
||||
CFG_PATH_MUNGE_i686-unknown-linux-gnu := true
|
||||
CFG_LDPATH_i686-unknown-linux-gnu :=
|
||||
CFG_RUN_i686-unknown-linux-gnu=$(2)
|
||||
CFG_RUN_TARG_i686-unknown-linux-gnu=$(call CFG_RUN_i686-unknown-linux-gnu,,$(2))
|
||||
|
||||
@ -12,15 +12,11 @@ CFG_GCCISH_CFLAGS_mips-unknown-linux-gnu := -Wall -g -fPIC -mips32r2 -msoft-floa
|
||||
CFG_GCCISH_CXXFLAGS_mips-unknown-linux-gnu := -fno-rtti $(CXXFLAGS)
|
||||
CFG_GCCISH_LINK_FLAGS_mips-unknown-linux-gnu := -shared -fPIC -g -mips32r2 -msoft-float -mabi=32
|
||||
CFG_GCCISH_DEF_FLAG_mips-unknown-linux-gnu := -Wl,--export-dynamic,--dynamic-list=
|
||||
CFG_GCCISH_PRE_LIB_FLAGS_mips-unknown-linux-gnu := -Wl,-whole-archive
|
||||
CFG_GCCISH_POST_LIB_FLAGS_mips-unknown-linux-gnu := -Wl,-no-whole-archive
|
||||
CFG_DEF_SUFFIX_mips-unknown-linux-gnu := .linux.def
|
||||
CFG_LLC_FLAGS_mips-unknown-linux-gnu :=
|
||||
CFG_INSTALL_NAME_mips-unknown-linux-gnu =
|
||||
CFG_EXE_SUFFIX_mips-unknown-linux-gnu :=
|
||||
CFG_WINDOWSY_mips-unknown-linux-gnu :=
|
||||
CFG_UNIXY_mips-unknown-linux-gnu := 1
|
||||
CFG_PATH_MUNGE_mips-unknown-linux-gnu := true
|
||||
CFG_LDPATH_mips-unknown-linux-gnu :=
|
||||
CFG_RUN_mips-unknown-linux-gnu=
|
||||
CFG_RUN_TARG_mips-unknown-linux-gnu=
|
||||
|
||||
@ -12,15 +12,11 @@ CFG_GCCISH_CFLAGS_mipsel-unknown-linux-gnu := -Wall -g -fPIC -mips32 -mabi=32 $(
|
||||
CFG_GCCISH_CXXFLAGS_mipsel-unknown-linux-gnu := -fno-rtti $(CXXFLAGS)
|
||||
CFG_GCCISH_LINK_FLAGS_mipsel-unknown-linux-gnu := -shared -fPIC -g -mips32
|
||||
CFG_GCCISH_DEF_FLAG_mipsel-unknown-linux-gnu := -Wl,--export-dynamic,--dynamic-list=
|
||||
CFG_GCCISH_PRE_LIB_FLAGS_mipsel-unknown-linux-gnu := -Wl,-whole-archive
|
||||
CFG_GCCISH_POST_LIB_FLAGS_mipsel-unknown-linux-gnu := -Wl,-no-whole-archive
|
||||
CFG_DEF_SUFFIX_mipsel-unknown-linux-gnu := .linux.def
|
||||
CFG_LLC_FLAGS_mipsel-unknown-linux-gnu :=
|
||||
CFG_INSTALL_NAME_mipsel-unknown-linux-gnu =
|
||||
CFG_EXE_SUFFIX_mipsel-unknown-linux-gnu :=
|
||||
CFG_WINDOWSY_mipsel-unknown-linux-gnu :=
|
||||
CFG_UNIXY_mipsel-unknown-linux-gnu := 1
|
||||
CFG_PATH_MUNGE_mipsel-unknown-linux-gnu := true
|
||||
CFG_LDPATH_mipsel-unknown-linux-gnu :=
|
||||
CFG_RUN_mipsel-unknown-linux-gnu=
|
||||
CFG_RUN_TARG_mipsel-unknown-linux-gnu=
|
||||
|
||||
@ -13,15 +13,11 @@ CFG_GCCISH_CFLAGS_powerpc-unknown-linux-gnu := -Wall -Werror -g -fPIC -m32 $(CFL
|
||||
CFG_GCCISH_CXXFLAGS_powerpc-unknown-linux-gnu := -fno-rtti $(CXXFLAGS)
|
||||
CFG_GCCISH_LINK_FLAGS_powerpc-unknown-linux-gnu := -shared -fPIC -ldl -pthread -lrt -g -m32
|
||||
CFG_GCCISH_DEF_FLAG_powerpc-unknown-linux-gnu := -Wl,--export-dynamic,--dynamic-list=
|
||||
CFG_GCCISH_PRE_LIB_FLAGS_powerpc-unknown-linux-gnu := -Wl,-whole-archive
|
||||
CFG_GCCISH_POST_LIB_FLAGS_powerpc-unknown-linux-gnu := -Wl,-no-whole-archive
|
||||
CFG_DEF_SUFFIX_powerpc-unknown-linux-gnu := .linux.def
|
||||
CFG_LLC_FLAGS_powerpc-unknown-linux-gnu :=
|
||||
CFG_INSTALL_NAME_powerpc-unknown-linux-gnu =
|
||||
CFG_EXE_SUFFIX_powerpc-unknown-linux-gnu =
|
||||
CFG_WINDOWSY_powerpc-unknown-linux-gnu :=
|
||||
CFG_UNIXY_powerpc-unknown-linux-gnu := 1
|
||||
CFG_PATH_MUNGE_powerpc-unknown-linux-gnu := true
|
||||
CFG_LDPATH_powerpc-unknown-linux-gnu :=
|
||||
CFG_RUN_powerpc-unknown-linux-gnu=$(2)
|
||||
CFG_RUN_TARG_powerpc-unknown-linux-gnu=$(call CFG_RUN_powerpc-unknown-linux-gnu,,$(2))
|
||||
|
||||
@ -12,15 +12,11 @@ CFG_GCCISH_CFLAGS_x86_64-apple-darwin := -Wall -Werror -g -fPIC -m64 -arch x86_6
|
||||
CFG_GCCISH_CXXFLAGS_x86_64-apple-darwin := -fno-rtti $(CXXFLAGS)
|
||||
CFG_GCCISH_LINK_FLAGS_x86_64-apple-darwin := -dynamiclib -pthread -framework CoreServices -m64
|
||||
CFG_GCCISH_DEF_FLAG_x86_64-apple-darwin := -Wl,-exported_symbols_list,
|
||||
CFG_GCCISH_PRE_LIB_FLAGS_x86_64-apple-darwin :=
|
||||
CFG_GCCISH_POST_LIB_FLAGS_x86_64-apple-darwin :=
|
||||
CFG_DEF_SUFFIX_x86_64-apple-darwin := .darwin.def
|
||||
CFG_LLC_FLAGS_x86_64-apple-darwin :=
|
||||
CFG_INSTALL_NAME_x86_64-apple-darwin = -Wl,-install_name,@rpath/$(1)
|
||||
CFG_EXE_SUFFIX_x86_64-apple-darwin :=
|
||||
CFG_WINDOWSY_x86_64-apple-darwin :=
|
||||
CFG_UNIXY_x86_64-apple-darwin := 1
|
||||
CFG_PATH_MUNGE_x86_64-apple-darwin := true
|
||||
CFG_LDPATH_x86_64-apple-darwin :=
|
||||
CFG_RUN_x86_64-apple-darwin=$(2)
|
||||
CFG_RUN_TARG_x86_64-apple-darwin=$(call CFG_RUN_x86_64-apple-darwin,,$(2))
|
||||
|
||||
@ -20,16 +20,12 @@ CFG_GCCISH_CFLAGS_x86_64-apple-ios := -Wall -Werror -fPIC $(CFG_IOSSIM_FLAGS_x86
|
||||
CFG_GCCISH_CXXFLAGS_x86_64-apple-ios := -fno-rtti $(CFG_IOSSIM_FLAGS_x86_64-apple-ios) -I$(CFG_IOSSIM_SDK_x86_64-apple-ios)/usr/include/c++/4.2.1
|
||||
CFG_GCCISH_LINK_FLAGS_x86_64-apple-ios := -lpthread -Wl,-no_compact_unwind -m64 -Wl,-syslibroot $(CFG_IOSSIM_SDK_x86_64-apple-ios)
|
||||
CFG_GCCISH_DEF_FLAG_x86_64-apple-ios := -Wl,-exported_symbols_list,
|
||||
CFG_GCCISH_PRE_LIB_FLAGS_x86_64-apple-ios :=
|
||||
CFG_GCCISH_POST_LIB_FLAGS_x86_64-apple-ios :=
|
||||
CFG_DEF_SUFFIX_x86_64-apple-ios := .darwin.def
|
||||
CFG_LLC_FLAGS_x86_64-apple-ios :=
|
||||
CFG_INSTALL_NAME_x86_64-apple-ios = -Wl,-install_name,@rpath/$(1)
|
||||
CFG_LIBUV_LINK_FLAGS_x86_64-apple-ios :=
|
||||
CFG_EXE_SUFFIX_x86_64-apple-ios :=
|
||||
CFG_WINDOWSY_x86_64-apple-ios :=
|
||||
CFG_UNIXY_x86_64-apple-ios := 1
|
||||
CFG_PATH_MUNGE_x86_64-apple-ios := true
|
||||
CFG_LDPATH_x86_64-apple-ios :=
|
||||
CFG_RUN_x86_64-apple-ios = $(2)
|
||||
CFG_RUN_TARG_x86_64-apple-ios = $(call CFG_RUN_x86_64-apple-ios,,$(2))
|
||||
|
||||
@ -13,15 +13,11 @@ CFG_GCCISH_CFLAGS_x86_64-pc-windows-gnu := -Wall -Werror -g -m64 -D_WIN32_WINNT=
|
||||
CFG_GCCISH_CXXFLAGS_x86_64-pc-windows-gnu := -fno-rtti $(CXXFLAGS)
|
||||
CFG_GCCISH_LINK_FLAGS_x86_64-pc-windows-gnu := -shared -g -m64
|
||||
CFG_GCCISH_DEF_FLAG_x86_64-pc-windows-gnu :=
|
||||
CFG_GCCISH_PRE_LIB_FLAGS_x86_64-pc-windows-gnu :=
|
||||
CFG_GCCISH_POST_LIB_FLAGS_x86_64-pc-windows-gnu :=
|
||||
CFG_DEF_SUFFIX_x86_64-pc-windows-gnu := .windows.def
|
||||
CFG_LLC_FLAGS_x86_64-pc-windows-gnu :=
|
||||
CFG_INSTALL_NAME_x86_64-pc-windows-gnu =
|
||||
CFG_EXE_SUFFIX_x86_64-pc-windows-gnu := .exe
|
||||
CFG_WINDOWSY_x86_64-pc-windows-gnu := 1
|
||||
CFG_UNIXY_x86_64-pc-windows-gnu :=
|
||||
CFG_PATH_MUNGE_x86_64-pc-windows-gnu :=
|
||||
CFG_LDPATH_x86_64-pc-windows-gnu :=
|
||||
CFG_RUN_x86_64-pc-windows-gnu=$(2)
|
||||
CFG_RUN_TARG_x86_64-pc-windows-gnu=$(call CFG_RUN_x86_64-pc-windows-gnu,,$(2))
|
||||
|
||||
@ -11,15 +11,11 @@ CFG_JEMALLOC_CFLAGS_x86_64-unknown-bitrig := -m64 -I/usr/include $(CFLAGS)
|
||||
CFG_GCCISH_CFLAGS_x86_64-unknown-bitrig := -Wall -Werror -fPIC -m64 -I/usr/include $(CFLAGS)
|
||||
CFG_GCCISH_LINK_FLAGS_x86_64-unknown-bitrig := -shared -pic -pthread -m64 $(LDFLAGS)
|
||||
CFG_GCCISH_DEF_FLAG_x86_64-unknown-bitrig := -Wl,--export-dynamic,--dynamic-list=
|
||||
CFG_GCCISH_PRE_LIB_FLAGS_x86_64-unknown-bitrig := -Wl,-pic -Wl,-whole-archive
|
||||
CFG_GCCISH_POST_LIB_FLAGS_x86_64-unknown-bitrig := -Wl,-no-whole-archive
|
||||
CFG_DEF_SUFFIX_x86_64-unknown-bitrig := .bsd.def
|
||||
CFG_LLC_FLAGS_x86_64-unknown-bitrig :=
|
||||
CFG_INSTALL_NAME_x86_64-unknown-bitrig =
|
||||
CFG_EXE_SUFFIX_x86_64-unknown-bitrig :=
|
||||
CFG_WINDOWSY_x86_64-unknown-bitrig :=
|
||||
CFG_UNIXY_x86_64-unknown-bitrig := 1
|
||||
CFG_PATH_MUNGE_x86_64-unknown-bitrig :=
|
||||
CFG_LDPATH_x86_64-unknown-bitrig :=
|
||||
CFG_RUN_x86_64-unknown-bitrig=$(2)
|
||||
CFG_RUN_TARG_x86_64-unknown-bitrig=$(call CFG_RUN_x86_64-unknown-bitrig,,$(2))
|
||||
|
||||
@ -11,15 +11,11 @@ CFG_JEMALLOC_CFLAGS_x86_64-unknown-dragonfly := -m64 -I/usr/include -I/usr/local
|
||||
CFG_GCCISH_CFLAGS_x86_64-unknown-dragonfly := -Wall -Werror -g -fPIC -m64 -I/usr/include -I/usr/local/include $(CFLAGS)
|
||||
CFG_GCCISH_LINK_FLAGS_x86_64-unknown-dragonfly := -shared -fPIC -g -pthread -lrt -m64
|
||||
CFG_GCCISH_DEF_FLAG_x86_64-unknown-dragonfly := -Wl,--export-dynamic,--dynamic-list=
|
||||
CFG_GCCISH_PRE_LIB_FLAGS_x86_64-unknown-dragonfly := -Wl,-whole-archive
|
||||
CFG_GCCISH_POST_LIB_FLAGS_x86_64-unknown-dragonfly := -Wl,-no-whole-archive
|
||||
CFG_DEF_SUFFIX_x86_64-unknown-dragonfly := .bsd.def
|
||||
CFG_LLC_FLAGS_x86_64-unknown-dragonfly :=
|
||||
CFG_INSTALL_NAME_x86_64-unknown-dragonfly =
|
||||
CFG_EXE_SUFFIX_x86_64-unknown-dragonfly :=
|
||||
CFG_WINDOWSY_x86_64-unknown-dragonfly :=
|
||||
CFG_UNIXY_x86_64-unknown-dragonfly := 1
|
||||
CFG_PATH_MUNGE_x86_64-unknown-dragonfly :=
|
||||
CFG_LDPATH_x86_64-unknown-dragonfly :=
|
||||
CFG_RUN_x86_64-unknown-dragonfly=$(2)
|
||||
CFG_RUN_TARG_x86_64-unknown-dragonfly=$(call CFG_RUN_x86_64-unknown-dragonfly,,$(2))
|
||||
|
||||
@ -11,15 +11,11 @@ CFG_JEMALLOC_CFLAGS_x86_64-unknown-freebsd := -I/usr/local/include $(CFLAGS)
|
||||
CFG_GCCISH_CFLAGS_x86_64-unknown-freebsd := -Wall -Werror -g -fPIC -I/usr/local/include $(CFLAGS)
|
||||
CFG_GCCISH_LINK_FLAGS_x86_64-unknown-freebsd := -shared -fPIC -g -pthread -lrt
|
||||
CFG_GCCISH_DEF_FLAG_x86_64-unknown-freebsd := -Wl,--export-dynamic,--dynamic-list=
|
||||
CFG_GCCISH_PRE_LIB_FLAGS_x86_64-unknown-freebsd := -Wl,-whole-archive
|
||||
CFG_GCCISH_POST_LIB_FLAGS_x86_64-unknown-freebsd := -Wl,-no-whole-archive
|
||||
CFG_DEF_SUFFIX_x86_64-unknown-freebsd := .bsd.def
|
||||
CFG_LLC_FLAGS_x86_64-unknown-freebsd :=
|
||||
CFG_INSTALL_NAME_x86_64-unknown-freebsd =
|
||||
CFG_EXE_SUFFIX_x86_64-unknown-freebsd :=
|
||||
CFG_WINDOWSY_x86_64-unknown-freebsd :=
|
||||
CFG_UNIXY_x86_64-unknown-freebsd := 1
|
||||
CFG_PATH_MUNGE_x86_64-unknown-freebsd :=
|
||||
CFG_LDPATH_x86_64-unknown-freebsd :=
|
||||
CFG_RUN_x86_64-unknown-freebsd=$(2)
|
||||
CFG_RUN_TARG_x86_64-unknown-freebsd=$(call CFG_RUN_x86_64-unknown-freebsd,,$(2))
|
||||
|
||||
@ -12,15 +12,11 @@ CFG_GCCISH_CFLAGS_x86_64-unknown-linux-gnu := -Wall -Werror -g -fPIC -m64
|
||||
CFG_GCCISH_CXXFLAGS_x86_64-unknown-linux-gnu := -fno-rtti
|
||||
CFG_GCCISH_LINK_FLAGS_x86_64-unknown-linux-gnu := -shared -fPIC -ldl -pthread -lrt -g -m64
|
||||
CFG_GCCISH_DEF_FLAG_x86_64-unknown-linux-gnu := -Wl,--export-dynamic,--dynamic-list=
|
||||
CFG_GCCISH_PRE_LIB_FLAGS_x86_64-unknown-linux-gnu := -Wl,-whole-archive
|
||||
CFG_GCCISH_POST_LIB_FLAGS_x86_64-unknown-linux-gnu := -Wl,-no-whole-archive
|
||||
CFG_DEF_SUFFIX_x86_64-unknown-linux-gnu := .linux.def
|
||||
CFG_LLC_FLAGS_x86_64-unknown-linux-gnu :=
|
||||
CFG_INSTALL_NAME_x86_64-unknown-linux-gnu =
|
||||
CFG_EXE_SUFFIX_x86_64-unknown-linux-gnu =
|
||||
CFG_WINDOWSY_x86_64-unknown-linux-gnu :=
|
||||
CFG_UNIXY_x86_64-unknown-linux-gnu := 1
|
||||
CFG_PATH_MUNGE_x86_64-unknown-linux-gnu := true
|
||||
CFG_LDPATH_x86_64-unknown-linux-gnu :=
|
||||
CFG_RUN_x86_64-unknown-linux-gnu=$(2)
|
||||
CFG_RUN_TARG_x86_64-unknown-linux-gnu=$(call CFG_RUN_x86_64-unknown-linux-gnu,,$(2))
|
||||
|
||||
27
mk/cfg/x86_64-unknown-linux-musl.mk
Normal file
27
mk/cfg/x86_64-unknown-linux-musl.mk
Normal file
@ -0,0 +1,27 @@
|
||||
# x86_64-unknown-linux-musl configuration
|
||||
CC_x86_64-unknown-linux-musl=$(CFG_MUSL_ROOT)/bin/musl-gcc
|
||||
CXX_x86_64-unknown-linux-musl=notaprogram
|
||||
CPP_x86_64-unknown-linux-musl=$(CFG_MUSL_ROOT)/bin/musl-gcc -E
|
||||
AR_x86_64-unknown-linux-musl=$(AR)
|
||||
CFG_LIB_NAME_x86_64-unknown-linux-musl=lib$(1).so
|
||||
CFG_STATIC_LIB_NAME_x86_64-unknown-linux-musl=lib$(1).a
|
||||
CFG_LIB_GLOB_x86_64-unknown-linux-musl=lib$(1)-*.so
|
||||
CFG_JEMALLOC_CFLAGS_x86_64-unknown-linux-musl := -m64
|
||||
CFG_GCCISH_CFLAGS_x86_64-unknown-linux-musl := -Wall -Werror -g -fPIC -m64
|
||||
CFG_GCCISH_CXXFLAGS_x86_64-unknown-linux-musl :=
|
||||
CFG_GCCISH_LINK_FLAGS_x86_64-unknown-linux-musl :=
|
||||
CFG_GCCISH_DEF_FLAG_x86_64-unknown-linux-musl :=
|
||||
CFG_LLC_FLAGS_x86_64-unknown-linux-musl :=
|
||||
CFG_INSTALL_NAME_x86_64-unknown-linux-musl =
|
||||
CFG_EXE_SUFFIX_x86_64-unknown-linux-musl =
|
||||
CFG_WINDOWSY_x86_64-unknown-linux-musl :=
|
||||
CFG_UNIXY_x86_64-unknown-linux-musl := 1
|
||||
CFG_LDPATH_x86_64-unknown-linux-musl :=
|
||||
CFG_RUN_x86_64-unknown-linux-musl=$(2)
|
||||
CFG_RUN_TARG_x86_64-unknown-linux-musl=$(call CFG_RUN_x86_64-unknown-linux-musl,,$(2))
|
||||
CFG_GNU_TRIPLE_x86_64-unknown-linux-musl := x86_64-unknown-linux-musl
|
||||
|
||||
NATIVE_DEPS_libc_T_x86_64-unknown-linux-musl += libc.a
|
||||
NATIVE_DEPS_std_T_x86_64-unknown-linux-musl += libunwind.a \
|
||||
crt1.o crti.o crtn.o
|
||||
INSTALLED_OBJECTS_x86_64-unknown-linux-musl += crt1.o crti.o crtn.o
|
||||
@ -11,15 +11,11 @@ CFG_JEMALLOC_CFLAGS_x86_64-unknown-openbsd := -m64 -I/usr/include $(CFLAGS)
|
||||
CFG_GCCISH_CFLAGS_x86_64-unknown-openbsd := -Wall -Werror -g -fPIC -m64 -I/usr/include $(CFLAGS)
|
||||
CFG_GCCISH_LINK_FLAGS_x86_64-unknown-openbsd := -shared -fPIC -g -pthread -m64
|
||||
CFG_GCCISH_DEF_FLAG_x86_64-unknown-openbsd := -Wl,--export-dynamic,--dynamic-list=
|
||||
CFG_GCCISH_PRE_LIB_FLAGS_x86_64-unknown-openbsd := -Wl,-whole-archive
|
||||
CFG_GCCISH_POST_LIB_FLAGS_x86_64-unknown-openbsd := -Wl,-no-whole-archive
|
||||
CFG_DEF_SUFFIX_x86_64-unknown-openbsd := .bsd.def
|
||||
CFG_LLC_FLAGS_x86_64-unknown-openbsd :=
|
||||
CFG_INSTALL_NAME_x86_64-unknown-openbsd =
|
||||
CFG_EXE_SUFFIX_x86_64-unknown-openbsd :=
|
||||
CFG_WINDOWSY_x86_64-unknown-openbsd :=
|
||||
CFG_UNIXY_x86_64-unknown-openbsd := 1
|
||||
CFG_PATH_MUNGE_x86_64-unknown-openbsd :=
|
||||
CFG_LDPATH_x86_64-unknown-openbsd :=
|
||||
CFG_RUN_x86_64-unknown-openbsd=$(2)
|
||||
CFG_RUN_TARG_x86_64-unknown-openbsd=$(call CFG_RUN_x86_64-unknown-openbsd,,$(2))
|
||||
|
||||
29
mk/crates.mk
29
mk/crates.mk
@ -52,18 +52,19 @@
|
||||
TARGET_CRATES := libc std flate arena term \
|
||||
serialize getopts collections test rand \
|
||||
log graphviz core rbml alloc \
|
||||
unicode rustc_bitflags
|
||||
rustc_unicode rustc_bitflags
|
||||
RUSTC_CRATES := rustc rustc_typeck rustc_borrowck rustc_resolve rustc_driver \
|
||||
rustc_trans rustc_back rustc_llvm rustc_privacy rustc_lint
|
||||
rustc_trans rustc_back rustc_llvm rustc_privacy rustc_lint \
|
||||
rustc_data_structures
|
||||
HOST_CRATES := syntax $(RUSTC_CRATES) rustdoc fmt_macros
|
||||
CRATES := $(TARGET_CRATES) $(HOST_CRATES)
|
||||
TOOLS := compiletest rustdoc rustc rustbook
|
||||
TOOLS := compiletest rustdoc rustc rustbook error-index-generator
|
||||
|
||||
DEPS_core :=
|
||||
DEPS_libc := core
|
||||
DEPS_unicode := core
|
||||
DEPS_rustc_unicode := core
|
||||
DEPS_alloc := core libc native:jemalloc
|
||||
DEPS_std := core libc rand alloc collections unicode \
|
||||
DEPS_std := core libc rand alloc collections rustc_unicode \
|
||||
native:rust_builtin native:backtrace native:rustrt_native \
|
||||
rustc_bitflags
|
||||
DEPS_graphviz := std
|
||||
@ -80,9 +81,10 @@ DEPS_rustc_resolve := rustc log syntax
|
||||
DEPS_rustc_privacy := rustc log syntax
|
||||
DEPS_rustc_lint := rustc log syntax
|
||||
DEPS_rustc := syntax flate arena serialize getopts rbml \
|
||||
log graphviz rustc_llvm rustc_back
|
||||
log graphviz rustc_llvm rustc_back rustc_data_structures
|
||||
DEPS_rustc_llvm := native:rustllvm libc std
|
||||
DEPS_rustc_back := std syntax rustc_llvm flate log libc
|
||||
DEPS_rustc_data_structures := std log serialize
|
||||
DEPS_rustdoc := rustc rustc_driver native:hoedown serialize getopts \
|
||||
test rustc_lint
|
||||
DEPS_rustc_bitflags := core
|
||||
@ -94,7 +96,7 @@ DEPS_serialize := std log
|
||||
DEPS_rbml := std log serialize
|
||||
DEPS_term := std log
|
||||
DEPS_getopts := std
|
||||
DEPS_collections := core alloc unicode
|
||||
DEPS_collections := core alloc rustc_unicode
|
||||
DEPS_num := std
|
||||
DEPS_test := std getopts serialize rbml term native:rust_test_helpers
|
||||
DEPS_rand := core
|
||||
@ -105,21 +107,26 @@ TOOL_DEPS_compiletest := test getopts
|
||||
TOOL_DEPS_rustdoc := rustdoc
|
||||
TOOL_DEPS_rustc := rustc_driver
|
||||
TOOL_DEPS_rustbook := std rustdoc
|
||||
TOOL_DEPS_error-index-generator := rustdoc syntax serialize
|
||||
TOOL_SOURCE_compiletest := $(S)src/compiletest/compiletest.rs
|
||||
TOOL_SOURCE_rustdoc := $(S)src/driver/driver.rs
|
||||
TOOL_SOURCE_rustc := $(S)src/driver/driver.rs
|
||||
TOOL_SOURCE_rustbook := $(S)src/rustbook/main.rs
|
||||
TOOL_SOURCE_error-index-generator := $(S)src/error-index-generator/main.rs
|
||||
|
||||
ONLY_RLIB_core := 1
|
||||
ONLY_RLIB_libc := 1
|
||||
ONLY_RLIB_alloc := 1
|
||||
ONLY_RLIB_rand := 1
|
||||
ONLY_RLIB_collections := 1
|
||||
ONLY_RLIB_unicode := 1
|
||||
ONLY_RLIB_rustc_unicode := 1
|
||||
ONLY_RLIB_rustc_bitflags := 1
|
||||
|
||||
# Documented-by-default crates
|
||||
DOC_CRATES := std alloc collections core libc unicode
|
||||
DOC_CRATES := std alloc collections core libc rustc_unicode
|
||||
|
||||
# Installed objects/libraries by default
|
||||
INSTALLED_OBJECTS := libmorestack.a libcompiler-rt.a
|
||||
|
||||
################################################################################
|
||||
# You should not need to edit below this line
|
||||
@ -146,3 +153,7 @@ TOOL_INPUTS_$(1) := $$(call rwildcard,$$(dir $$(TOOL_SOURCE_$(1))),*.rs)
|
||||
endef
|
||||
|
||||
$(foreach crate,$(TOOLS),$(eval $(call RUST_TOOL,$(crate))))
|
||||
|
||||
ifdef CFG_DISABLE_ELF_TLS
|
||||
RUSTFLAGS_std := --cfg no_elf_tls
|
||||
endif
|
||||
|
||||
@ -52,6 +52,7 @@ PKG_FILES := \
|
||||
doc \
|
||||
driver \
|
||||
etc \
|
||||
error-index-generator \
|
||||
$(foreach crate,$(CRATES),lib$(crate)) \
|
||||
libcollectionstest \
|
||||
libcoretest \
|
||||
|
||||
12
mk/docs.mk
12
mk/docs.mk
@ -71,9 +71,13 @@ RUSTBOOK_EXE = $(HBIN2_H_$(CFG_BUILD))/rustbook$(X_$(CFG_BUILD))
|
||||
# ./configure
|
||||
RUSTBOOK = $(RPATH_VAR2_T_$(CFG_BUILD)_H_$(CFG_BUILD)) $(RUSTBOOK_EXE)
|
||||
|
||||
# The error-index-generator executable...
|
||||
ERR_IDX_GEN_EXE = $(HBIN2_H_$(CFG_BUILD))/error-index-generator$(X_$(CFG_BUILD))
|
||||
ERR_IDX_GEN = $(RPATH_VAR2_T_$(CFG_BUILD)_H_$(CFG_BUILD)) $(ERR_IDX_GEN_EXE)
|
||||
|
||||
D := $(S)src/doc
|
||||
|
||||
DOC_TARGETS := trpl style
|
||||
DOC_TARGETS := trpl style error-index
|
||||
COMPILER_DOC_TARGETS :=
|
||||
DOC_L10N_TARGETS :=
|
||||
|
||||
@ -288,3 +292,9 @@ doc/style/index.html: $(RUSTBOOK_EXE) $(wildcard $(S)/src/doc/style/*.md) | doc/
|
||||
@$(call E, rustbook: $@)
|
||||
$(Q)rm -rf doc/style
|
||||
$(Q)$(RUSTBOOK) build $(S)src/doc/style doc/style
|
||||
|
||||
error-index: doc/error-index.html
|
||||
|
||||
doc/error-index.html: $(ERR_IDX_GEN_EXE) | doc/
|
||||
$(Q)$(call E, error-index-generator: $@)
|
||||
$(Q)$(ERR_IDX_GEN)
|
||||
|
||||
23
mk/main.mk
23
mk/main.mk
@ -13,14 +13,16 @@
|
||||
######################################################################
|
||||
|
||||
# The version number
|
||||
CFG_RELEASE_NUM=1.0.0
|
||||
CFG_RELEASE_NUM=1.1.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=.5
|
||||
|
||||
CFG_FILENAME_EXTRA=4e7c5e5c
|
||||
# Append a version-dependent hash to each library, so we can install different
|
||||
# versions in the same place
|
||||
CFG_FILENAME_EXTRA=$(shell printf '%s' $(CFG_RELEASE) | $(CFG_HASH_COMMAND))
|
||||
|
||||
ifeq ($(CFG_RELEASE_CHANNEL),stable)
|
||||
# This is the normal semver version string, e.g. "0.12.0", "0.12.0-nightly"
|
||||
@ -31,7 +33,11 @@ CFG_DISABLE_UNSTABLE_FEATURES=1
|
||||
endif
|
||||
ifeq ($(CFG_RELEASE_CHANNEL),beta)
|
||||
CFG_RELEASE=$(CFG_RELEASE_NUM)-beta$(CFG_PRERELEASE_VERSION)
|
||||
CFG_PACKAGE_VERS=$(CFG_RELEASE_NUM)-beta$(CFG_PRERELEASE_VERSION)
|
||||
# When building beta distributables just reuse the same "beta" name
|
||||
# so when we upload we'll always override the previous beta. This
|
||||
# doesn't actually impact the version reported by rustc - it's just
|
||||
# for file naming.
|
||||
CFG_PACKAGE_VERS=beta
|
||||
CFG_DISABLE_UNSTABLE_FEATURES=1
|
||||
endif
|
||||
ifeq ($(CFG_RELEASE_CHANNEL),nightly)
|
||||
@ -68,9 +74,6 @@ ifneq ($(wildcard $(subst $(SPACE),\$(SPACE),$(CFG_GIT_DIR))),)
|
||||
endif
|
||||
endif
|
||||
|
||||
CFG_BUILD_DATE = $(shell date +%F)
|
||||
CFG_VERSION += (built $(CFG_BUILD_DATE))
|
||||
|
||||
# Windows exe's need numeric versions - don't use anything but
|
||||
# numbers and dots here
|
||||
CFG_VERSION_WIN = $(CFG_RELEASE_NUM)
|
||||
@ -191,6 +194,7 @@ ifndef CFG_DISABLE_VALGRIND_RPASS
|
||||
$(info cfg: valgrind-rpass command set to $(CFG_VALGRIND))
|
||||
CFG_VALGRIND_RPASS :=$(CFG_VALGRIND)
|
||||
else
|
||||
$(info cfg: disabling valgrind run-pass tests)
|
||||
CFG_VALGRIND_RPASS :=
|
||||
endif
|
||||
|
||||
@ -326,7 +330,6 @@ endif
|
||||
ifdef CFG_VER_HASH
|
||||
export CFG_VER_HASH
|
||||
endif
|
||||
export CFG_BUILD_DATE
|
||||
export CFG_VERSION
|
||||
export CFG_VERSION_WIN
|
||||
export CFG_RELEASE
|
||||
@ -395,8 +398,10 @@ endif
|
||||
# Prerequisites for using the stageN compiler to build target artifacts
|
||||
TSREQ$(1)_T_$(2)_H_$(3) = \
|
||||
$$(HSREQ$(1)_H_$(3)) \
|
||||
$$(TLIB$(1)_T_$(2)_H_$(3))/libmorestack.a \
|
||||
$$(TLIB$(1)_T_$(2)_H_$(3))/libcompiler-rt.a
|
||||
$$(foreach obj,$$(INSTALLED_OBJECTS),\
|
||||
$$(TLIB$(1)_T_$(2)_H_$(3))/$$(obj)) \
|
||||
$$(foreach obj,$$(INSTALLED_OBJECTS_$(2)),\
|
||||
$$(TLIB$(1)_T_$(2)_H_$(3))/$$(obj))
|
||||
|
||||
# Prerequisites for a working stageN compiler and libraries, for a specific
|
||||
# target
|
||||
|
||||
@ -46,8 +46,9 @@ endif
|
||||
# see https://blog.mozilla.org/jseward/2012/06/05/valgrind-now-supports-jemalloc-builds-directly/
|
||||
ifdef CFG_VALGRIND
|
||||
CFG_VALGRIND += --error-exitcode=100 \
|
||||
--soname-synonyms=somalloc=NONE \
|
||||
--fair-sched=try \
|
||||
--quiet \
|
||||
--soname-synonyms=somalloc=NONE \
|
||||
--suppressions=$(CFG_SRC_DIR)src/etc/x86.supp \
|
||||
$(OS_SUPP)
|
||||
ifdef CFG_ENABLE_HELGRIND
|
||||
|
||||
@ -70,7 +70,7 @@ define PREPARE_MAN
|
||||
$(Q)$(PREPARE_MAN_CMD) $(PREPARE_SOURCE_MAN_DIR)/$(1) $(PREPARE_DEST_MAN_DIR)/$(1)
|
||||
endef
|
||||
|
||||
PREPARE_TOOLS = $(filter-out compiletest rustbook, $(TOOLS))
|
||||
PREPARE_TOOLS = $(filter-out compiletest rustbook error-index-generator, $(TOOLS))
|
||||
|
||||
|
||||
# $(1) is tool
|
||||
@ -140,8 +140,8 @@ prepare-target-$(2)-host-$(3)-$(1)-$(4): prepare-maybe-clean-$(4) \
|
||||
$$(if $$(findstring $(2),$$(CFG_HOST)), \
|
||||
$$(foreach crate,$$(HOST_CRATES), \
|
||||
$$(call PREPARE_LIB,$$(call CFG_LIB_GLOB_$(2),$$(crate)))),) \
|
||||
$$(call PREPARE_LIB,libmorestack.a) \
|
||||
$$(call PREPARE_LIB,libcompiler-rt.a),),),)
|
||||
$$(foreach object,$$(INSTALLED_OBJECTS) $$(INSTALLED_OBJECTS_$(2)),\
|
||||
$$(call PREPARE_LIB,$$(object))),),),)
|
||||
endef
|
||||
|
||||
define INSTALL_GDB_DEBUGGER_SCRIPTS_COMMANDS
|
||||
|
||||
23
mk/rt.mk
23
mk/rt.mk
@ -74,7 +74,8 @@ $$(RT_OUTPUT_DIR_$(1))/%.o: $(S)src/rt/%.ll $$(MKFILE_DEPS) \
|
||||
@mkdir -p $$(@D)
|
||||
@$$(call E, compile: $$@)
|
||||
$$(Q)$$(LLC_$$(CFG_BUILD)) $$(CFG_LLC_FLAGS_$(1)) \
|
||||
-filetype=obj -mtriple=$$(CFG_LLVM_TARGET_$(1)) -relocation-model=pic -o $$@ $$<
|
||||
-filetype=obj -mtriple=$$(CFG_LLVM_TARGET_$(1)) \
|
||||
-relocation-model=pic -o $$@ $$<
|
||||
|
||||
$$(RT_OUTPUT_DIR_$(1))/%.o: $(S)src/rt/%.c $$(MKFILE_DEPS)
|
||||
@mkdir -p $$(@D)
|
||||
@ -110,6 +111,11 @@ $$(RT_OUTPUT_DIR_$(1))/$$(NATIVE_$(2)_$(1)): $$(OBJS_$(2)_$(1))
|
||||
@$$(call E, link: $$@)
|
||||
$$(Q)$$(AR_$(1)) rcs $$@ $$^
|
||||
|
||||
ifeq ($$(findstring windows,$(1)),windows)
|
||||
$$(RT_OUTPUT_DIR_$(1))/lib$(2).a: $$(RT_OUTPUT_DIR_$(1))/$$(NATIVE_$(2)_$(1))
|
||||
$$(Q)cp $$^ $$@
|
||||
endif
|
||||
|
||||
endef
|
||||
|
||||
$(foreach target,$(CFG_TARGET), \
|
||||
@ -221,7 +227,7 @@ COMPRT_DEPS := $(wildcard \
|
||||
$(S)src/compiler-rt/*/*/*/*)
|
||||
endif
|
||||
|
||||
COMPRT_NAME_$(1) := $$(call CFG_STATIC_LIB_NAME_$(1),compiler-rt)
|
||||
COMPRT_NAME_$(1) := libcompiler-rt.a
|
||||
COMPRT_LIB_$(1) := $$(RT_OUTPUT_DIR_$(1))/$$(COMPRT_NAME_$(1))
|
||||
COMPRT_BUILD_DIR_$(1) := $$(RT_OUTPUT_DIR_$(1))/compiler-rt
|
||||
|
||||
@ -312,6 +318,19 @@ endif # endif for windowsy
|
||||
endif # endif for ios
|
||||
endif # endif for darwin
|
||||
|
||||
################################################################################
|
||||
# libc/libunwind for musl
|
||||
#
|
||||
# When we're building a musl-like target we're going to link libc/libunwind
|
||||
# statically into the standard library and liblibc, so we need to make sure
|
||||
# they're in a location that we can find
|
||||
################################################################################
|
||||
|
||||
ifeq ($$(findstring musl,$(1)),musl)
|
||||
$$(RT_OUTPUT_DIR_$(1))/%: $$(CFG_MUSL_ROOT)/lib/%
|
||||
cp $$^ $$@
|
||||
endif
|
||||
|
||||
endef
|
||||
|
||||
# Instantiate template for all stages/targets
|
||||
|
||||
@ -25,8 +25,6 @@ endif
|
||||
RUSTLLVM_OBJS_CS_$(1) := $$(addprefix rustllvm/, \
|
||||
ExecutionEngineWrapper.cpp RustWrapper.cpp PassWrapper.cpp)
|
||||
|
||||
RUSTLLVM_DEF_$(1) := $(1)/rustllvm/rustllvm$(CFG_DEF_SUFFIX_$(1))
|
||||
|
||||
RUSTLLVM_INCS_$(1) = $$(LLVM_EXTRA_INCDIRS_$(1)) \
|
||||
-iquote $$(LLVM_INCDIR_$(1)) \
|
||||
-iquote $$(S)src/rustllvm/include
|
||||
|
||||
13
mk/target.mk
13
mk/target.mk
@ -35,7 +35,9 @@ CRATE_FULLDEPS_$(1)_T_$(2)_H_$(3)_$(4) := \
|
||||
$$(foreach dep,$$(RUST_DEPS_$(4)), \
|
||||
$$(TLIB$(1)_T_$(2)_H_$(3))/stamp.$$(dep)) \
|
||||
$$(foreach dep,$$(NATIVE_DEPS_$(4)), \
|
||||
$$(RT_OUTPUT_DIR_$(2))/$$(call CFG_STATIC_LIB_NAME_$(2),$$(dep)))
|
||||
$$(RT_OUTPUT_DIR_$(2))/$$(call CFG_STATIC_LIB_NAME_$(2),$$(dep))) \
|
||||
$$(foreach dep,$$(NATIVE_DEPS_$(4)_T_$(2)), \
|
||||
$$(RT_OUTPUT_DIR_$(2))/$$(dep))
|
||||
endef
|
||||
|
||||
$(foreach host,$(CFG_HOST), \
|
||||
@ -143,14 +145,7 @@ $$(TBIN$(1)_T_$(2)_H_$(3))/:
|
||||
$$(TLIB$(1)_T_$(2)_H_$(3))/:
|
||||
mkdir -p $$@
|
||||
|
||||
$$(TLIB$(1)_T_$(2)_H_$(3))/libcompiler-rt.a: \
|
||||
$$(RT_OUTPUT_DIR_$(2))/$$(call CFG_STATIC_LIB_NAME_$(2),compiler-rt) \
|
||||
| $$(TLIB$(1)_T_$(2)_H_$(3))/ $$(SNAPSHOT_RUSTC_POST_CLEANUP)
|
||||
@$$(call E, cp: $$@)
|
||||
$$(Q)cp $$< $$@
|
||||
|
||||
$$(TLIB$(1)_T_$(2)_H_$(3))/libmorestack.a: \
|
||||
$$(RT_OUTPUT_DIR_$(2))/$$(call CFG_STATIC_LIB_NAME_$(2),morestack) \
|
||||
$$(TLIB$(1)_T_$(2)_H_$(3))/%: $$(RT_OUTPUT_DIR_$(2))/% \
|
||||
| $$(TLIB$(1)_T_$(2)_H_$(3))/ $$(SNAPSHOT_RUSTC_POST_CLEANUP)
|
||||
@$$(call E, cp: $$@)
|
||||
$$(Q)cp $$< $$@
|
||||
|
||||
49
mk/tests.mk
49
mk/tests.mk
@ -15,14 +15,14 @@
|
||||
|
||||
# The names of crates that must be tested
|
||||
|
||||
# libcore/libunicode tests are in a separate crate
|
||||
# libcore/librustc_unicode tests are in a separate crate
|
||||
DEPS_coretest :=
|
||||
$(eval $(call RUST_CRATE,coretest))
|
||||
|
||||
DEPS_collectionstest :=
|
||||
$(eval $(call RUST_CRATE,collectionstest))
|
||||
|
||||
TEST_TARGET_CRATES = $(filter-out core unicode,$(TARGET_CRATES)) \
|
||||
TEST_TARGET_CRATES = $(filter-out core rustc_unicode,$(TARGET_CRATES)) \
|
||||
collectionstest coretest
|
||||
TEST_DOC_CRATES = $(DOC_CRATES)
|
||||
TEST_HOST_CRATES = $(filter-out rustc_typeck rustc_borrowck rustc_resolve \
|
||||
@ -304,6 +304,7 @@ check-stage$(1)-T-$(2)-H-$(3)-exec: \
|
||||
check-stage$(1)-T-$(2)-H-$(3)-pfail-exec \
|
||||
check-stage$(1)-T-$(2)-H-$(3)-rpass-valgrind-exec \
|
||||
check-stage$(1)-T-$(2)-H-$(3)-rpass-full-exec \
|
||||
check-stage$(1)-T-$(2)-H-$(3)-rfail-full-exec \
|
||||
check-stage$(1)-T-$(2)-H-$(3)-cfail-full-exec \
|
||||
check-stage$(1)-T-$(2)-H-$(3)-rmake-exec \
|
||||
check-stage$(1)-T-$(2)-H-$(3)-rustdocck-exec \
|
||||
@ -345,6 +346,7 @@ check-stage$(1)-T-$(2)-H-$(3)-pretty-exec: \
|
||||
check-stage$(1)-T-$(2)-H-$(3)-pretty-rpass-valgrind-exec \
|
||||
check-stage$(1)-T-$(2)-H-$(3)-pretty-rpass-full-exec \
|
||||
check-stage$(1)-T-$(2)-H-$(3)-pretty-rfail-exec \
|
||||
check-stage$(1)-T-$(2)-H-$(3)-pretty-rfail-full-exec \
|
||||
check-stage$(1)-T-$(2)-H-$(3)-pretty-bench-exec \
|
||||
check-stage$(1)-T-$(2)-H-$(3)-pretty-pretty-exec
|
||||
|
||||
@ -464,6 +466,7 @@ $(foreach host,$(CFG_HOST), \
|
||||
RPASS_RS := $(wildcard $(S)src/test/run-pass/*.rs)
|
||||
RPASS_VALGRIND_RS := $(wildcard $(S)src/test/run-pass-valgrind/*.rs)
|
||||
RPASS_FULL_RS := $(wildcard $(S)src/test/run-pass-fulldeps/*.rs)
|
||||
RFAIL_FULL_RS := $(wildcard $(S)src/test/run-fail-fulldeps/*.rs)
|
||||
CFAIL_FULL_RS := $(wildcard $(S)src/test/compile-fail-fulldeps/*.rs)
|
||||
RFAIL_RS := $(wildcard $(S)src/test/run-fail/*.rs)
|
||||
CFAIL_RS := $(wildcard $(S)src/test/compile-fail/*.rs)
|
||||
@ -483,6 +486,7 @@ PERF_RS := $(wildcard $(S)src/test/bench/*.rs)
|
||||
RPASS_TESTS := $(RPASS_RS)
|
||||
RPASS_VALGRIND_TESTS := $(RPASS_VALGRIND_RS)
|
||||
RPASS_FULL_TESTS := $(RPASS_FULL_RS)
|
||||
RFAIL_FULL_TESTS := $(RFAIL_FULL_RS)
|
||||
CFAIL_FULL_TESTS := $(CFAIL_FULL_RS)
|
||||
RFAIL_TESTS := $(RFAIL_RS)
|
||||
CFAIL_TESTS := $(CFAIL_RS)
|
||||
@ -510,6 +514,11 @@ CTEST_BUILD_BASE_rpass-full = run-pass-fulldeps
|
||||
CTEST_MODE_rpass-full = run-pass
|
||||
CTEST_RUNTOOL_rpass-full = $(CTEST_RUNTOOL)
|
||||
|
||||
CTEST_SRC_BASE_rfail-full = run-fail-fulldeps
|
||||
CTEST_BUILD_BASE_rfail-full = run-fail-fulldeps
|
||||
CTEST_MODE_rfail-full = run-fail
|
||||
CTEST_RUNTOOL_rfail-full = $(CTEST_RUNTOOL)
|
||||
|
||||
CTEST_SRC_BASE_cfail-full = compile-fail-fulldeps
|
||||
CTEST_BUILD_BASE_cfail-full = compile-fail-fulldeps
|
||||
CTEST_MODE_cfail-full = compile-fail
|
||||
@ -623,6 +632,13 @@ ifndef CFG_DISABLE_OPTIMIZE_TESTS
|
||||
CTEST_RUSTC_FLAGS += -O
|
||||
endif
|
||||
|
||||
# Analogously to the above, whether to pass `-g` when compiling tests
|
||||
# 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))
|
||||
ifdef CFG_ENABLE_DEBUGINFO_TESTS
|
||||
CTEST_RUSTC_FLAGS += -g
|
||||
endif
|
||||
|
||||
CTEST_COMMON_ARGS$(1)-T-$(2)-H-$(3) := \
|
||||
--compile-lib-path $$(HLIB$(1)_H_$(3)) \
|
||||
@ -661,6 +677,7 @@ endif
|
||||
CTEST_DEPS_rpass_$(1)-T-$(2)-H-$(3) = $$(RPASS_TESTS)
|
||||
CTEST_DEPS_rpass-valgrind_$(1)-T-$(2)-H-$(3) = $$(RPASS_VALGRIND_TESTS)
|
||||
CTEST_DEPS_rpass-full_$(1)-T-$(2)-H-$(3) = $$(RPASS_FULL_TESTS) $$(CSREQ$(1)_T_$(3)_H_$(3)) $$(SREQ$(1)_T_$(2)_H_$(3))
|
||||
CTEST_DEPS_rfail-full_$(1)-T-$(2)-H-$(3) = $$(RFAIL_FULL_TESTS) $$(CSREQ$(1)_T_$(3)_H_$(3)) $$(SREQ$(1)_T_$(2)_H_$(3))
|
||||
CTEST_DEPS_cfail-full_$(1)-T-$(2)-H-$(3) = $$(CFAIL_FULL_TESTS) $$(CSREQ$(1)_T_$(3)_H_$(3)) $$(SREQ$(1)_T_$(2)_H_$(3))
|
||||
CTEST_DEPS_rfail_$(1)-T-$(2)-H-$(3) = $$(RFAIL_TESTS)
|
||||
CTEST_DEPS_cfail_$(1)-T-$(2)-H-$(3) = $$(CFAIL_TESTS)
|
||||
@ -737,7 +754,7 @@ endif
|
||||
|
||||
endef
|
||||
|
||||
CTEST_NAMES = rpass rpass-valgrind rpass-full cfail-full rfail cfail pfail \
|
||||
CTEST_NAMES = rpass rpass-valgrind rpass-full rfail-full cfail-full rfail cfail pfail \
|
||||
bench perf debuginfo-gdb debuginfo-lldb codegen rustdocck
|
||||
|
||||
$(foreach host,$(CFG_HOST), \
|
||||
@ -746,27 +763,33 @@ $(foreach host,$(CFG_HOST), \
|
||||
$(eval $(foreach name,$(CTEST_NAMES), \
|
||||
$(eval $(call DEF_RUN_COMPILETEST,$(stage),$(target),$(host),$(name))))))))))
|
||||
|
||||
PRETTY_NAMES = pretty-rpass pretty-rpass-valgrind pretty-rpass-full pretty-rfail pretty-bench pretty-pretty
|
||||
PRETTY_NAMES = pretty-rpass pretty-rpass-valgrind pretty-rpass-full pretty-rfail-full pretty-rfail \
|
||||
pretty-bench pretty-pretty
|
||||
PRETTY_DEPS_pretty-rpass = $(RPASS_TESTS)
|
||||
PRETTY_DEPS_pretty-rpass-valgrind = $(RPASS_VALGRIND_TESTS)
|
||||
PRETTY_DEPS_pretty-rpass-full = $(RPASS_FULL_TESTS)
|
||||
PRETTY_DEPS_pretty-rfail-full = $(RFAIL_FULL_TESTS)
|
||||
PRETTY_DEPS_pretty-rfail = $(RFAIL_TESTS)
|
||||
PRETTY_DEPS_pretty-bench = $(BENCH_TESTS)
|
||||
PRETTY_DEPS_pretty-pretty = $(PRETTY_TESTS)
|
||||
# The stage- and host-specific dependencies are for e.g. macro_crate_test which pulls in
|
||||
# external crates.
|
||||
PRETTY_DEPS$(1)_H_$(3)_pretty-rpass =
|
||||
PRETTY_DEPS$(1)_H_$(3)_pretty-rpass-full = $$(HLIB$(1)_H_$(3))/stamp.syntax $$(HLIB$(1)_H_$(3))/stamp.rustc
|
||||
PRETTY_DEPS$(1)_H_$(3)_pretty-rfail =
|
||||
PRETTY_DEPS$(1)_H_$(3)_pretty-bench =
|
||||
PRETTY_DEPS$(1)_H_$(3)_pretty-pretty =
|
||||
PRETTY_DIRNAME_pretty-rpass = run-pass
|
||||
PRETTY_DIRNAME_pretty-rpass-valgrind = run-pass-valgrind
|
||||
PRETTY_DIRNAME_pretty-rpass-full = run-pass-fulldeps
|
||||
PRETTY_DIRNAME_pretty-rfail-full = run-fail-fulldeps
|
||||
PRETTY_DIRNAME_pretty-rfail = run-fail
|
||||
PRETTY_DIRNAME_pretty-bench = bench
|
||||
PRETTY_DIRNAME_pretty-pretty = pretty
|
||||
|
||||
define DEF_PRETTY_FULLDEPS
|
||||
PRETTY_DEPS$(1)_T_$(2)_H_$(3)_pretty-rpass-full = $$(CSREQ$(1)_T_$(3)_H_$(3))
|
||||
PRETTY_DEPS$(1)_T_$(2)_H_$(3)_pretty-rfail-full = $$(CSREQ$(1)_T_$(3)_H_$(3))
|
||||
endef
|
||||
|
||||
$(foreach host,$(CFG_HOST), \
|
||||
$(foreach target,$(CFG_TARGET), \
|
||||
$(foreach stage,$(STAGES), \
|
||||
$(eval $(call DEF_PRETTY_FULLDEPS,$(stage),$(target),$(host))))))
|
||||
|
||||
define DEF_RUN_PRETTY_TEST
|
||||
|
||||
PRETTY_ARGS$(1)-T-$(2)-H-$(3)-$(4) := \
|
||||
@ -780,7 +803,7 @@ check-stage$(1)-T-$(2)-H-$(3)-$(4)-exec: $$(call TEST_OK_FILE,$(1),$(2),$(3),$(4
|
||||
$$(call TEST_OK_FILE,$(1),$(2),$(3),$(4)): \
|
||||
$$(TEST_SREQ$(1)_T_$(2)_H_$(3)) \
|
||||
$$(PRETTY_DEPS_$(4)) \
|
||||
$$(PRETTY_DEPS$(1)_H_$(3)_$(4))
|
||||
$$(PRETTY_DEPS$(1)_T_$(2)_H_$(3)_$(4))
|
||||
@$$(call E, run pretty-rpass [$(2)]: $$<)
|
||||
$$(Q)touch $$@.start_time
|
||||
$$(Q)$$(call CFG_RUN_CTEST_$(2),$(1),$$<,$(3)) \
|
||||
@ -899,6 +922,7 @@ TEST_GROUPS = \
|
||||
rpass \
|
||||
rpass-valgrind \
|
||||
rpass-full \
|
||||
rfail-full \
|
||||
cfail-full \
|
||||
rfail \
|
||||
cfail \
|
||||
@ -916,6 +940,7 @@ TEST_GROUPS = \
|
||||
pretty-rpass \
|
||||
pretty-rpass-valgrind \
|
||||
pretty-rpass-full \
|
||||
pretty-rfail-full \
|
||||
pretty-rfail \
|
||||
pretty-bench \
|
||||
pretty-pretty \
|
||||
|
||||
@ -269,7 +269,7 @@ pub fn test_opts(config: &Config) -> test::TestOpts {
|
||||
run_ignored: config.run_ignored,
|
||||
logfile: config.logfile.clone(),
|
||||
run_tests: true,
|
||||
run_benchmarks: true,
|
||||
bench_benchmarks: true,
|
||||
nocapture: env::var("RUST_TEST_NOCAPTURE").is_ok(),
|
||||
color: test::AutoColor,
|
||||
}
|
||||
|
||||
@ -170,6 +170,9 @@ pub fn is_test_ignored(config: &Config, testfile: &Path) -> bool {
|
||||
format!("ignore-{}",
|
||||
config.stage_id.split('-').next().unwrap())
|
||||
}
|
||||
fn ignore_env(config: &Config) -> String {
|
||||
format!("ignore-{}", util::get_env(&config.target).unwrap_or("<unknown>"))
|
||||
}
|
||||
fn ignore_gdb(config: &Config, line: &str) -> bool {
|
||||
if config.mode != common::DebugInfoGdb {
|
||||
return false;
|
||||
@ -231,6 +234,7 @@ pub fn is_test_ignored(config: &Config, testfile: &Path) -> bool {
|
||||
!parse_name_directive(ln, &ignore_target(config)) &&
|
||||
!parse_name_directive(ln, &ignore_architecture(config)) &&
|
||||
!parse_name_directive(ln, &ignore_stage(config)) &&
|
||||
!parse_name_directive(ln, &ignore_env(config)) &&
|
||||
!(config.mode == common::Pretty && parse_name_directive(ln, "ignore-pretty")) &&
|
||||
!(config.target != config.host && parse_name_directive(ln, "ignore-cross-compile")) &&
|
||||
!ignore_gdb(config, ln) &&
|
||||
|
||||
@ -979,6 +979,7 @@ fn check_expected_errors(expected_errors: Vec<errors::ExpectedError> ,
|
||||
// is the ending point, and * represents ANSI color codes.
|
||||
for line in proc_res.stderr.lines() {
|
||||
let mut was_expected = false;
|
||||
let mut prev = 0;
|
||||
for (i, ee) in expected_errors.iter().enumerate() {
|
||||
if !found_flags[i] {
|
||||
debug!("prefix={} ee.kind={} ee.msg={} line={}",
|
||||
@ -986,6 +987,17 @@ fn check_expected_errors(expected_errors: Vec<errors::ExpectedError> ,
|
||||
ee.kind,
|
||||
ee.msg,
|
||||
line);
|
||||
// Suggestions have no line number in their output, so take on the line number of
|
||||
// the previous expected error
|
||||
if ee.kind == "suggestion" {
|
||||
assert!(expected_errors[prev].kind == "help",
|
||||
"SUGGESTIONs must be preceded by a HELP");
|
||||
if line.contains(&ee.msg) {
|
||||
found_flags[i] = true;
|
||||
was_expected = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (prefix_matches(line, &prefixes[i]) || continuation(line)) &&
|
||||
line.contains(&ee.kind) &&
|
||||
line.contains(&ee.msg) {
|
||||
@ -994,6 +1006,7 @@ fn check_expected_errors(expected_errors: Vec<errors::ExpectedError> ,
|
||||
break;
|
||||
}
|
||||
}
|
||||
prev = i;
|
||||
}
|
||||
|
||||
// ignore this msg which gets printed at the end
|
||||
@ -1220,7 +1233,20 @@ fn compose_and_run_compiler(config: &Config, props: &TestProps,
|
||||
let mut crate_type = if aux_props.no_prefer_dynamic {
|
||||
Vec::new()
|
||||
} else {
|
||||
vec!("--crate-type=dylib".to_string())
|
||||
// We primarily compile all auxiliary libraries as dynamic libraries
|
||||
// to avoid code size bloat and large binaries as much as possible
|
||||
// for the test suite (otherwise including libstd statically in all
|
||||
// executables takes up quite a bit of space).
|
||||
//
|
||||
// For targets like MUSL, however, there is no support for dynamic
|
||||
// libraries so we just go back to building a normal library. Note,
|
||||
// however, that if the library is built with `force_host` then it's
|
||||
// ok to be a dylib as the host should always support dylibs.
|
||||
if config.target.contains("musl") && !aux_props.force_host {
|
||||
vec!("--crate-type=lib".to_string())
|
||||
} else {
|
||||
vec!("--crate-type=dylib".to_string())
|
||||
}
|
||||
};
|
||||
crate_type.extend(extra_link_args.clone().into_iter());
|
||||
let aux_args =
|
||||
@ -1452,7 +1478,7 @@ fn make_out_name(config: &Config, testfile: &Path, extension: &str) -> PathBuf {
|
||||
fn aux_output_dir_name(config: &Config, testfile: &Path) -> PathBuf {
|
||||
let f = output_base_name(config, testfile);
|
||||
let mut fname = f.file_name().unwrap().to_os_string();
|
||||
fname.push("libaux");
|
||||
fname.push(&format!(".{}.libaux", config.mode));
|
||||
f.with_file_name(&fname)
|
||||
}
|
||||
|
||||
|
||||
@ -60,6 +60,10 @@ pub fn get_arch(triple: &str) -> &'static str {
|
||||
panic!("Cannot determine Architecture from triple");
|
||||
}
|
||||
|
||||
pub fn get_env(triple: &str) -> Option<&str> {
|
||||
triple.split('-').nth(3)
|
||||
}
|
||||
|
||||
pub fn make_new_path(path: &str) -> String {
|
||||
assert!(cfg!(windows));
|
||||
// Windows just uses PATH as the library search path, so we have to
|
||||
|
||||
@ -39,7 +39,7 @@ representation as a primitive. This allows using Rust `enum`s in FFI where C
|
||||
`enum`s are also used, for most use cases. The attribute can also be applied
|
||||
to `struct`s to get the same layout as a C struct would.
|
||||
|
||||
[repr]: reference.html#miscellaneous-attributes
|
||||
[repr]: reference.html#ffi-attributes
|
||||
|
||||
## There is no GC
|
||||
|
||||
|
||||
@ -109,7 +109,7 @@ This does mean that indexed access to a Unicode codepoint inside a `str` value i
|
||||
* Most "character oriented" operations on text only work under very restricted language assumptions sets such as "ASCII-range codepoints only". Outside ASCII-range, you tend to have to use a complex (non-constant-time) algorithm for determining linguistic-unit (glyph, word, paragraph) boundaries anyways. We recommend using an "honest" linguistically-aware, Unicode-approved algorithm.
|
||||
* The `char` type is UCS4. If you honestly need to do a codepoint-at-a-time algorithm, it's trivial to write a `type wstr = [char]`, and unpack a `str` into it in a single pass, then work with the `wstr`. In other words: the fact that the language is not "decoding to UCS4 by default" shouldn't stop you from decoding (or re-encoding any other way) if you need to work with that encoding.
|
||||
|
||||
## Why are strings, vectors etc. built-in types rather than (say) special kinds of trait/impl?
|
||||
## Why are `str`s, slices, arrays etc. built-in types rather than (say) special kinds of trait/impl?
|
||||
|
||||
In each case there is one or more operator, literal constructor, overloaded use or integration with a built-in control structure that makes us think it would be awkward to phrase the type in terms of more-general type constructors. Same as, say, with numbers! But this is partly an aesthetic call, and we'd be willing to look at a worked-out proposal for eliminating or rephrasing these special cases.
|
||||
|
||||
@ -121,7 +121,7 @@ Yes. Calling C code from Rust is simple and exactly as efficient as calling C co
|
||||
|
||||
Yes. The Rust code has to be exposed via an `extern` declaration, which makes it C-ABI compatible. Such a function can be passed to C code as a function pointer or, if given the `#[no_mangle]` attribute to disable symbol mangling, can be called directly from C code.
|
||||
|
||||
## Why aren't function signatures inferred? Why only local slots?
|
||||
## Why aren't function signatures inferred? Why only local variables?
|
||||
|
||||
* Mechanically, it simplifies the inference algorithm; inference only requires looking at one function at a time.
|
||||
* The same simplification goes double for human readers. A reader does not need an IDE running an inference algorithm across an entire crate to be able to guess at a function's argument types; it's always explicit and nearby.
|
||||
|
||||
@ -1346,6 +1346,8 @@ vtable when the trait is used as a [trait object](#trait-objects).
|
||||
Traits are implemented for specific types through separate
|
||||
[implementations](#implementations).
|
||||
|
||||
Consider the following trait:
|
||||
|
||||
```
|
||||
# type Surface = i32;
|
||||
# type BoundingBox = i32;
|
||||
@ -1360,6 +1362,20 @@ This defines a trait with two methods. All values that have
|
||||
`draw` and `bounding_box` methods called, using `value.bounding_box()`
|
||||
[syntax](#method-call-expressions).
|
||||
|
||||
Traits can include default implementations of methods, as in:
|
||||
|
||||
```
|
||||
trait Foo {
|
||||
fn bar(&self);
|
||||
|
||||
fn baz(&self) { println!("We called baz."); }
|
||||
}
|
||||
```
|
||||
|
||||
Here the `baz` method has a default implementation, so types that implement
|
||||
`Foo` need only implement `bar`. It is also possible for implementing types
|
||||
to override a method that has a default implementation.
|
||||
|
||||
Type parameters can be specified for a trait to make it generic. These appear
|
||||
after the trait name, using the same syntax used in [generic
|
||||
functions](#generic-functions).
|
||||
@ -1372,6 +1388,35 @@ trait Seq<T> {
|
||||
}
|
||||
```
|
||||
|
||||
It is also possible to define associated types for a trait. Consider the
|
||||
following example of a `Container` trait. Notice how the type is available
|
||||
for use in the method signatures:
|
||||
|
||||
```
|
||||
trait Container {
|
||||
type E;
|
||||
fn empty() -> Self;
|
||||
fn insert(&mut self, Self::E);
|
||||
}
|
||||
```
|
||||
|
||||
In order for a type to implement this trait, it must not only provide
|
||||
implementations for every method, but it must specify the type `E`. Here's
|
||||
an implementation of `Container` for the standard library type `Vec`:
|
||||
|
||||
```
|
||||
# trait Container {
|
||||
# type E;
|
||||
# fn empty() -> Self;
|
||||
# fn insert(&mut self, Self::E);
|
||||
# }
|
||||
impl<T> Container for Vec<T> {
|
||||
type E = T;
|
||||
fn empty() -> Vec<T> { Vec::new() }
|
||||
fn insert(&mut self, x: T) { self.push(x); }
|
||||
}
|
||||
```
|
||||
|
||||
Generic functions may use traits as _bounds_ on their type parameters. This
|
||||
will have two effects: only types that have the trait may instantiate the
|
||||
parameter, and within the generic function, the methods of the trait can be
|
||||
@ -3470,13 +3515,23 @@ more of the closure traits:
|
||||
|
||||
### Trait objects
|
||||
|
||||
Every trait item (see [traits](#traits)) defines a type with the same name as
|
||||
the trait. This type is called the _trait object_ of the trait. Trait objects
|
||||
permit "late binding" of methods, dispatched using _virtual method tables_
|
||||
("vtables"). Whereas most calls to trait methods are "early bound" (statically
|
||||
resolved) to specific implementations at compile time, a call to a method on an
|
||||
trait objects is only resolved to a vtable entry at compile time. The actual
|
||||
implementation for each vtable entry can vary on an object-by-object basis.
|
||||
In Rust, a type like `&SomeTrait` or `Box<SomeTrait>` is called a _trait object_.
|
||||
Each instance of a trait object includes:
|
||||
|
||||
- a pointer to an instance of a type `T` that implements `SomeTrait`
|
||||
- a _virtual method table_, often just called a _vtable_, which contains, for
|
||||
each method of `SomeTrait` that `T` implements, a pointer to `T`'s
|
||||
implementation (i.e. a function pointer).
|
||||
|
||||
The purpose of trait objects is to permit "late binding" of methods. A call to
|
||||
a method on a trait object is only resolved to a vtable entry at compile time.
|
||||
The actual implementation for each vtable entry can vary on an object-by-object
|
||||
basis.
|
||||
|
||||
Note that for a trait object to be instantiated, the trait must be
|
||||
_object-safe_. Object safety rules are defined in [RFC 255].
|
||||
|
||||
[RFC 255]: https://github.com/rust-lang/rfcs/blob/master/text/0255-object-safety.md
|
||||
|
||||
Given a pointer-typed expression `E` of type `&T` or `Box<T>`, where `T`
|
||||
implements trait `R`, casting `E` to the corresponding pointer type `&R` or
|
||||
|
||||
@ -175,7 +175,7 @@ data, we call the `clone()` method. In this example, `y` is no longer a referenc
|
||||
to the vector stored in `x`, but a copy of its first element, `"Hello"`. Now
|
||||
that we don’t have a reference, our `push()` works just fine.
|
||||
|
||||
[move]: move-semantics.html
|
||||
[move]: ownership.html#move-semantics
|
||||
|
||||
If we truly want a reference, we need the other option: ensure that our reference
|
||||
goes out of scope before we try to do the mutation. That looks like this:
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
With the `associated_consts` feature, you can define constants like this:
|
||||
|
||||
```rust,ignore
|
||||
```rust
|
||||
#![feature(associated_consts)]
|
||||
|
||||
trait Foo {
|
||||
@ -41,7 +41,7 @@ error: not all trait items implemented, missing: `ID` [E0046]
|
||||
|
||||
A default value can be implemented as well:
|
||||
|
||||
```rust,ignore
|
||||
```rust
|
||||
#![feature(associated_consts)]
|
||||
|
||||
trait Foo {
|
||||
@ -68,7 +68,7 @@ add our own definition.
|
||||
Associated constants don’t have to be associated with a trait. An `impl` block
|
||||
for a `struct` works fine too:
|
||||
|
||||
```rust,ignore
|
||||
```rust
|
||||
#![feature(associated_consts)]
|
||||
|
||||
struct Foo;
|
||||
|
||||
@ -6,7 +6,7 @@ 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
|
||||
concurrent Rust programs must be memory safe, having no data races. Rust's type
|
||||
system is up to the thread, and gives you powerful ways to reason about
|
||||
system is up to the task, and gives you powerful ways to reason about
|
||||
concurrent code at compile time.
|
||||
|
||||
Before we talk about the concurrency features that come with Rust, it's important
|
||||
|
||||
@ -1,3 +0,0 @@
|
||||
% `const`
|
||||
|
||||
Coming soon!
|
||||
@ -1,3 +0,0 @@
|
||||
% Debug and Display
|
||||
|
||||
Coming soon!
|
||||
@ -73,6 +73,9 @@ a name is all we need. We choose the [`String`][string] type for the name,
|
||||
rather than `&str`. Generally speaking, working with a type which owns its
|
||||
data is easier than working with one that uses references.
|
||||
|
||||
[struct]: structs.html
|
||||
[string]: strings.html
|
||||
|
||||
Let’s continue:
|
||||
|
||||
```rust
|
||||
@ -393,7 +396,7 @@ let handles: Vec<_> = philosophers.into_iter().map(|p| {
|
||||
}).collect();
|
||||
```
|
||||
|
||||
While this is only five lines, they’re a dense four. Let’s break it down.
|
||||
While this is only five lines, they’re a dense five. Let’s break it down.
|
||||
|
||||
```rust,ignore
|
||||
let handles: Vec<_> =
|
||||
@ -450,7 +453,7 @@ which blocks execution until the thread has completed execution. This ensures
|
||||
that the threads complete their work before the program exits.
|
||||
|
||||
If you run this program, you’ll see that the philosophers eat out of order!
|
||||
We have mult-threading!
|
||||
We have multi-threading!
|
||||
|
||||
```text
|
||||
Gilles Deleuze is eating.
|
||||
|
||||
@ -55,9 +55,6 @@ fn process_color_change(msg: Message) {
|
||||
}
|
||||
```
|
||||
|
||||
Both variants are named `Digit`, but since they’re scoped to the `enum` name
|
||||
there's no ambiguity.
|
||||
|
||||
Not supporting these operations may seem rather limiting, but it’s a limitation
|
||||
which we can overcome. There are two ways: by implementing equality ourselves,
|
||||
or by pattern matching variants with [`match`][match] expressions, which you’ll
|
||||
@ -66,3 +63,4 @@ equality yet, but we’ll find out in the [`traits`][traits] section.
|
||||
|
||||
[match]: match.html
|
||||
[if-let]: if-let.html
|
||||
[traits]: traits.html
|
||||
|
||||
@ -181,6 +181,8 @@ match version {
|
||||
This function makes use of an enum, `ParseError`, to enumerate the various
|
||||
errors that can occur.
|
||||
|
||||
The [`Debug`](../std/fmt/trait.Debug.html) trait is what lets us print the enum value using the `{:?}` format operation.
|
||||
|
||||
# Non-recoverable errors with `panic!`
|
||||
|
||||
In the case of an error that is unexpected and not recoverable, the `panic!`
|
||||
|
||||
@ -27,7 +27,7 @@ Check out the generated `Cargo.toml`:
|
||||
[package]
|
||||
|
||||
name = "guessing_game"
|
||||
version = "0.0.1"
|
||||
version = "0.1.0"
|
||||
authors = ["Your Name <you@example.com>"]
|
||||
```
|
||||
|
||||
@ -46,7 +46,7 @@ Let’s try compiling what Cargo gave us:
|
||||
|
||||
```{bash}
|
||||
$ cargo build
|
||||
Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game)
|
||||
Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game)
|
||||
```
|
||||
|
||||
Excellent! Open up your `src/main.rs` again. We’ll be writing all of
|
||||
@ -58,7 +58,7 @@ Try it out:
|
||||
|
||||
```bash
|
||||
$ cargo run
|
||||
Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game)
|
||||
Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game)
|
||||
Running `target/debug/guessing_game`
|
||||
Hello, world!
|
||||
```
|
||||
@ -213,12 +213,12 @@ The next part will use this handle to get input from the user:
|
||||
```
|
||||
|
||||
Here, we call the [`read_line()`][read_line] method on our handle.
|
||||
[Method][method]s are like associated functions, but are only available on a
|
||||
[Methods][method] are like associated functions, but are only available on a
|
||||
particular instance of a type, rather than the type itself. We’re also passing
|
||||
one argument to `read_line()`: `&mut guess`.
|
||||
|
||||
[read_line]: ../std/io/struct.Stdin.html#method.read_line
|
||||
[method]: methods.html
|
||||
[method]: method-syntax.html
|
||||
|
||||
Remember how we bound `guess` above? We said it was mutable. However,
|
||||
`read_line` doesn’t take a `String` as an argument: it takes a `&mut String`.
|
||||
@ -727,7 +727,7 @@ Let’s try our program out!
|
||||
|
||||
```bash
|
||||
$ cargo run
|
||||
Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game)
|
||||
Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game)
|
||||
Running `target/guessing_game`
|
||||
Guess the number!
|
||||
The secret number is: 58
|
||||
@ -792,7 +792,7 @@ and quit. Observe:
|
||||
|
||||
```bash
|
||||
$ cargo run
|
||||
Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game)
|
||||
Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game)
|
||||
Running `target/guessing_game`
|
||||
Guess the number!
|
||||
The secret number is: 59
|
||||
@ -929,7 +929,7 @@ Now we should be good! Let’s try:
|
||||
|
||||
```bash
|
||||
$ cargo run
|
||||
Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game)
|
||||
Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game)
|
||||
Running `target/guessing_game`
|
||||
Guess the number!
|
||||
The secret number is: 61
|
||||
|
||||
@ -20,11 +20,9 @@ $ sh rustup.sh
|
||||
|
||||
[insecurity]: http://curlpipesh.tumblr.com
|
||||
|
||||
If you're on Windows, please download either the [32-bit installer][win32] or
|
||||
the [64-bit installer][win64] and run it.
|
||||
If you're on Windows, please download the appropriate [installer][install-page].
|
||||
|
||||
[win32]: https://static.rust-lang.org/dist/rust-1.0.0-beta-i686-pc-windows-gnu.msi
|
||||
[win64]: https://static.rust-lang.org/dist/rust-1.0.0-beta-x86_64-pc-windows-gnu.msi
|
||||
[install-page]: http://www.rust-lang.org/install.html
|
||||
|
||||
## Uninstalling
|
||||
|
||||
@ -44,10 +42,9 @@ Some people, and somewhat rightfully so, get very upset when we tell you to
|
||||
people who maintain Rust aren't going to hack your computer and do bad things.
|
||||
That's a good instinct! If you're one of those people, please check out the
|
||||
documentation on [building Rust from Source][from source], or [the official
|
||||
binary downloads][install page].
|
||||
binary downloads][install-page].
|
||||
|
||||
[from source]: https://github.com/rust-lang/rust#building-from-source
|
||||
[install page]: http://www.rust-lang.org/install.html
|
||||
|
||||
Oh, we should also mention the officially supported platforms:
|
||||
|
||||
@ -71,10 +68,11 @@ If you've got Rust installed, you can open up a shell, and type this:
|
||||
$ rustc --version
|
||||
```
|
||||
|
||||
You should see the version number, commit hash, commit date and build date:
|
||||
You should see the version number, commit hash, and commit date. If you just
|
||||
installed version 1.0.0, you should see:
|
||||
|
||||
```bash
|
||||
rustc 1.0.0-beta (9854143cb 2015-04-02) (built 2015-04-02)
|
||||
rustc 1.0.0 (a59de37e9 2015-05-13)
|
||||
```
|
||||
|
||||
If you did, Rust has been installed successfully! Congrats!
|
||||
|
||||
@ -42,7 +42,7 @@ loop is just a handy way to write this `loop`/`match`/`break` construct.
|
||||
`for` loops aren't the only thing that uses iterators, however. Writing your
|
||||
own iterator involves implementing the `Iterator` trait. While doing that is
|
||||
outside of the scope of this guide, Rust provides a number of useful iterators
|
||||
to accomplish various threads. Before we talk about those, we should talk about a
|
||||
to accomplish various tasks. Before we talk about those, we should talk about a
|
||||
Rust anti-pattern. And that's using ranges like this.
|
||||
|
||||
Yes, we just talked about how ranges are cool. But ranges are also very
|
||||
|
||||
@ -97,4 +97,4 @@ Unlike the previous uses of `match`, you can’t use the normal `if`
|
||||
statement to do this. You can use the [`if let`][if-let] statement,
|
||||
which can be seen as an abbreviated form of `match`.
|
||||
|
||||
[if-let][if-let.html]
|
||||
[if-let]: if-let.html
|
||||
|
||||
@ -1,3 +0,0 @@
|
||||
% Move Semantics
|
||||
|
||||
Coming Soon
|
||||
@ -35,7 +35,7 @@ let y = &mut x;
|
||||
|
||||
`y` is an immutable binding to a mutable reference, which means that you can’t
|
||||
bind `y` to something else (`y = &mut z`), but you can mutate the thing that’s
|
||||
bound to `y`. (`*y = 5`) A subtle distinction.
|
||||
bound to `y` (`*y = 5`). A subtle distinction.
|
||||
|
||||
Of course, if you need both:
|
||||
|
||||
|
||||
@ -66,7 +66,7 @@ match x {
|
||||
}
|
||||
```
|
||||
|
||||
This prints `something else`
|
||||
This prints `something else`.
|
||||
|
||||
# Bindings
|
||||
|
||||
@ -152,7 +152,7 @@ match x {
|
||||
}
|
||||
```
|
||||
|
||||
This prints `Got an int!`
|
||||
This prints `Got an int!`.
|
||||
|
||||
# ref and ref mut
|
||||
|
||||
|
||||
@ -1,3 +0,0 @@
|
||||
% `static`
|
||||
|
||||
Coming soon!
|
||||
@ -196,3 +196,5 @@ useful. For instance, a library may ask you to create a structure that
|
||||
implements a certain [trait][trait] to handle events. If you don’t have
|
||||
any data you need to store in the structure, you can just create a
|
||||
unit-like struct.
|
||||
|
||||
[trait]: traits.html
|
||||
|
||||
@ -80,7 +80,7 @@ This memory is kind of like a giant array: addresses start at zero and go
|
||||
up to the final number. So here’s a diagram of our first stack frame:
|
||||
|
||||
| Address | Name | Value |
|
||||
+---------+------+-------+
|
||||
|---------|------|-------|
|
||||
| 0 | x | 42 |
|
||||
|
||||
We’ve got `x` located at address `0`, with the value `42`.
|
||||
@ -88,7 +88,7 @@ We’ve got `x` located at address `0`, with the value `42`.
|
||||
When `foo()` is called, a new stack frame is allocated:
|
||||
|
||||
| Address | Name | Value |
|
||||
+---------+------+-------+
|
||||
|---------|------|-------|
|
||||
| 2 | z | 100 |
|
||||
| 1 | y | 5 |
|
||||
| 0 | x | 42 |
|
||||
@ -107,7 +107,7 @@ value being stored.
|
||||
After `foo()` is over, its frame is deallocated:
|
||||
|
||||
| Address | Name | Value |
|
||||
+---------+------+-------+
|
||||
|---------|------|-------|
|
||||
| 0 | x | 42 |
|
||||
|
||||
And then, after `main()`, even this last value goes away. Easy!
|
||||
@ -142,13 +142,13 @@ fn main() {
|
||||
Okay, first, we call `main()`:
|
||||
|
||||
| Address | Name | Value |
|
||||
+---------+------+-------+
|
||||
|---------|------|-------|
|
||||
| 0 | x | 42 |
|
||||
|
||||
Next up, `main()` calls `foo()`:
|
||||
|
||||
| Address | Name | Value |
|
||||
+---------+------+-------+
|
||||
|---------|------|-------|
|
||||
| 3 | c | 1 |
|
||||
| 2 | b | 100 |
|
||||
| 1 | a | 5 |
|
||||
@ -157,7 +157,7 @@ Next up, `main()` calls `foo()`:
|
||||
And then `foo()` calls `bar()`:
|
||||
|
||||
| Address | Name | Value |
|
||||
+---------+------+-------+
|
||||
|---------|------|-------|
|
||||
| 4 | i | 6 |
|
||||
| 3 | c | 1 |
|
||||
| 2 | b | 100 |
|
||||
@ -170,7 +170,7 @@ After `bar()` is over, its frame is deallocated, leaving just `foo()` and
|
||||
`main()`:
|
||||
|
||||
| Address | Name | Value |
|
||||
+---------+------+-------+
|
||||
|---------|------|-------|
|
||||
| 3 | c | 1 |
|
||||
| 2 | b | 100 |
|
||||
| 1 | a | 5 |
|
||||
@ -179,7 +179,7 @@ After `bar()` is over, its frame is deallocated, leaving just `foo()` and
|
||||
And then `foo()` ends, leaving just `main()`
|
||||
|
||||
| Address | Name | Value |
|
||||
+---------+------+-------+
|
||||
|---------|------|-------|
|
||||
| 0 | x | 42 |
|
||||
|
||||
And then we’re done. Getting the hang of it? It’s like piling up dishes: you
|
||||
@ -206,7 +206,7 @@ fn main() {
|
||||
Here’s what happens in memory when `main()` is called:
|
||||
|
||||
| Address | Name | Value |
|
||||
+---------+------+--------+
|
||||
|---------|------|--------|
|
||||
| 1 | y | 42 |
|
||||
| 0 | x | ?????? |
|
||||
|
||||
@ -218,7 +218,7 @@ it allocates some memory for the heap, and puts `5` there. The memory now looks
|
||||
like this:
|
||||
|
||||
| Address | Name | Value |
|
||||
+-----------------+------+----------------+
|
||||
|-----------------|------|----------------|
|
||||
| 2<sup>30</sup> | | 5 |
|
||||
| ... | ... | ... |
|
||||
| 1 | y | 42 |
|
||||
@ -243,7 +243,7 @@ layout of a program which has been running for a while now:
|
||||
|
||||
|
||||
| Address | Name | Value |
|
||||
+----------------------+------+----------------------+
|
||||
|----------------------|------|----------------------|
|
||||
| 2<sup>30</sup> | | 5 |
|
||||
| (2<sup>30</sup>) - 1 | | |
|
||||
| (2<sup>30</sup>) - 2 | | |
|
||||
@ -266,13 +266,13 @@ Rust programs use [jemalloc][jemalloc] for this purpose.
|
||||
Anyway, back to our example. Since this memory is on the heap, it can stay
|
||||
alive longer than the function which allocates the box. In this case, however,
|
||||
it doesn’t.[^moving] When the function is over, we need to free the stack frame
|
||||
for `main()`. `Box<T>`, though, has a trick up its sleve: [Drop][drop]. The
|
||||
for `main()`. `Box<T>`, though, has a trick up its sleeve: [Drop][drop]. The
|
||||
implementation of `Drop` for `Box` deallocates the memory that was allocated
|
||||
when it was created. Great! So when `x` goes away, it first frees the memory
|
||||
allocated on the heap:
|
||||
|
||||
| Address | Name | Value |
|
||||
+---------+------+--------+
|
||||
|---------|------|--------|
|
||||
| 1 | y | 42 |
|
||||
| 0 | x | ?????? |
|
||||
|
||||
@ -305,7 +305,7 @@ fn main() {
|
||||
When we enter `main()`, memory looks like this:
|
||||
|
||||
| Address | Name | Value |
|
||||
+---------+------+-------+
|
||||
|---------|------|-------|
|
||||
| 1 | y | 0 |
|
||||
| 0 | x | 5 |
|
||||
|
||||
@ -315,7 +315,7 @@ memory location that `x` lives at, which in this case is `0`.
|
||||
What about when we call `foo()`, passing `y` as an argument?
|
||||
|
||||
| Address | Name | Value |
|
||||
+---------+------+-------+
|
||||
|---------|------|-------|
|
||||
| 3 | z | 42 |
|
||||
| 2 | i | 0 |
|
||||
| 1 | y | 0 |
|
||||
@ -367,7 +367,7 @@ fn main() {
|
||||
First, we call `main()`:
|
||||
|
||||
| Address | Name | Value |
|
||||
+-----------------+------+----------------+
|
||||
|-----------------|------|----------------|
|
||||
| 2<sup>30</sup> | | 20 |
|
||||
| ... | ... | ... |
|
||||
| 2 | j | 0 |
|
||||
@ -380,7 +380,7 @@ value pointing there.
|
||||
Next, at the end of `main()`, `foo()` gets called:
|
||||
|
||||
| Address | Name | Value |
|
||||
+-----------------+------+----------------+
|
||||
|-----------------|------|----------------|
|
||||
| 2<sup>30</sup> | | 20 |
|
||||
| ... | ... | ... |
|
||||
| 5 | z | 4 |
|
||||
@ -397,7 +397,7 @@ since `j` points at `h`.
|
||||
Next, `foo()` calls `baz()`, passing `z`:
|
||||
|
||||
| Address | Name | Value |
|
||||
+-----------------+------+----------------+
|
||||
|-----------------|------|----------------|
|
||||
| 2<sup>30</sup> | | 20 |
|
||||
| ... | ... | ... |
|
||||
| 7 | g | 100 |
|
||||
@ -413,7 +413,7 @@ We’ve allocated memory for `f` and `g`. `baz()` is very short, so when it’s
|
||||
over, we get rid of its stack frame:
|
||||
|
||||
| Address | Name | Value |
|
||||
+-----------------+------+----------------+
|
||||
|-----------------|------|----------------|
|
||||
| 2<sup>30</sup> | | 20 |
|
||||
| ... | ... | ... |
|
||||
| 5 | z | 4 |
|
||||
@ -426,11 +426,11 @@ over, we get rid of its stack frame:
|
||||
Next, `foo()` calls `bar()` with `x` and `z`:
|
||||
|
||||
| Address | Name | Value |
|
||||
+----------------------+------+----------------------+
|
||||
|----------------------|------|----------------------|
|
||||
| 2<sup>30</sup> | | 20 |
|
||||
| (2<sup>30</sup>) - 1 | | 5 |
|
||||
| ... | ... | ... |
|
||||
| 10 | e | 4 |
|
||||
| 10 | e | 9 |
|
||||
| 9 | d | (2<sup>30</sup>) - 1 |
|
||||
| 8 | c | 5 |
|
||||
| 7 | b | 4 |
|
||||
@ -449,13 +449,13 @@ case, we set up the variables as usual.
|
||||
At the end of `bar()`, it calls `baz()`:
|
||||
|
||||
| Address | Name | Value |
|
||||
+----------------------+------+----------------------+
|
||||
|----------------------|------|----------------------|
|
||||
| 2<sup>30</sup> | | 20 |
|
||||
| (2<sup>30</sup>) - 1 | | 5 |
|
||||
| ... | ... | ... |
|
||||
| 12 | g | 100 |
|
||||
| 11 | f | 4 |
|
||||
| 10 | e | 4 |
|
||||
| 10 | e | 9 |
|
||||
| 9 | d | (2<sup>30</sup>) - 1 |
|
||||
| 8 | c | 5 |
|
||||
| 7 | b | 4 |
|
||||
@ -473,11 +473,11 @@ far.
|
||||
After `baz()` is over, we get rid of `f` and `g`:
|
||||
|
||||
| Address | Name | Value |
|
||||
+----------------------+------+----------------------+
|
||||
|----------------------|------|----------------------|
|
||||
| 2<sup>30</sup> | | 20 |
|
||||
| (2<sup>30</sup>) - 1 | | 5 |
|
||||
| ... | ... | ... |
|
||||
| 10 | e | 4 |
|
||||
| 10 | e | 9 |
|
||||
| 9 | d | (2<sup>30</sup>) - 1 |
|
||||
| 8 | c | 5 |
|
||||
| 7 | b | 4 |
|
||||
@ -493,7 +493,7 @@ Next, we return from `bar()`. `d` in this case is a `Box<T>`, so it also frees
|
||||
what it points to: (2<sup>30</sup>) - 1.
|
||||
|
||||
| Address | Name | Value |
|
||||
+-----------------+------+----------------+
|
||||
|-----------------|------|----------------|
|
||||
| 2<sup>30</sup> | | 20 |
|
||||
| ... | ... | ... |
|
||||
| 5 | z | 4 |
|
||||
@ -506,7 +506,7 @@ what it points to: (2<sup>30</sup>) - 1.
|
||||
And after that, `foo()` returns:
|
||||
|
||||
| Address | Name | Value |
|
||||
+-----------------+------+----------------+
|
||||
|-----------------|------|----------------|
|
||||
| 2<sup>30</sup> | | 20 |
|
||||
| ... | ... | ... |
|
||||
| 2 | j | 0 |
|
||||
|
||||
@ -1,56 +0,0 @@
|
||||
% Tuple Structs
|
||||
|
||||
Rust has another data type that's like a hybrid between a tuple and a struct,
|
||||
called a *tuple struct*. Tuple structs do have a name, but their fields don't:
|
||||
|
||||
```{rust}
|
||||
struct Color(i32, i32, i32);
|
||||
struct Point(i32, i32, i32);
|
||||
```
|
||||
|
||||
These two will not be equal, even if they have the same values:
|
||||
|
||||
```{rust}
|
||||
# struct Color(i32, i32, i32);
|
||||
# struct Point(i32, i32, i32);
|
||||
let black = Color(0, 0, 0);
|
||||
let origin = Point(0, 0, 0);
|
||||
```
|
||||
|
||||
It is almost always better to use a struct than a tuple struct. We would write
|
||||
`Color` and `Point` like this instead:
|
||||
|
||||
```{rust}
|
||||
struct Color {
|
||||
red: i32,
|
||||
blue: i32,
|
||||
green: i32,
|
||||
}
|
||||
|
||||
struct Point {
|
||||
x: i32,
|
||||
y: i32,
|
||||
z: i32,
|
||||
}
|
||||
```
|
||||
|
||||
Now, we have actual names, rather than positions. Good names are important,
|
||||
and with a struct, we have actual names.
|
||||
|
||||
There _is_ one case when a tuple struct is very useful, though, and that's a
|
||||
tuple struct with only one element. We call this the *newtype* pattern, because
|
||||
it allows you to create a new type, distinct from that of its contained value
|
||||
and expressing its own semantic meaning:
|
||||
|
||||
```{rust}
|
||||
struct Inches(i32);
|
||||
|
||||
let length = Inches(10);
|
||||
|
||||
let Inches(integer_length) = length;
|
||||
println!("length is {} inches", integer_length);
|
||||
```
|
||||
|
||||
As you can see here, you can extract the inner integer type through a
|
||||
destructuring `let`, as we discussed previously in 'tuples.' In this case, the
|
||||
`let Inches(integer_length)` assigns `10` to `integer_length`.
|
||||
@ -1,183 +0,0 @@
|
||||
% Unsafe Code
|
||||
|
||||
# Introduction
|
||||
|
||||
Rust aims to provide safe abstractions over the low-level details of
|
||||
the CPU and operating system, but sometimes one needs to drop down and
|
||||
write code at that level. This guide aims to provide an overview of
|
||||
the dangers and power one gets with Rust's unsafe subset.
|
||||
|
||||
Rust provides an escape hatch in the form of the `unsafe { ... }`
|
||||
block which allows the programmer to dodge some of the compiler's
|
||||
checks and do a wide range of operations, such as:
|
||||
|
||||
- dereferencing [raw pointers](#raw-pointers)
|
||||
- calling a function via FFI ([covered by the FFI guide](ffi.html))
|
||||
- casting between types bitwise (`transmute`, aka "reinterpret cast")
|
||||
- [inline assembly](#inline-assembly)
|
||||
|
||||
Note that an `unsafe` block does not relax the rules about lifetimes
|
||||
of `&` and the freezing of borrowed data.
|
||||
|
||||
Any use of `unsafe` is the programmer saying "I know more than you" to
|
||||
the compiler, and, as such, the programmer should be very sure that
|
||||
they actually do know more about why that piece of code is valid. In
|
||||
general, one should try to minimize the amount of unsafe code in a
|
||||
code base; preferably by using the bare minimum `unsafe` blocks to
|
||||
build safe interfaces.
|
||||
|
||||
> **Note**: the low-level details of the Rust language are still in
|
||||
> flux, and there is no guarantee of stability or backwards
|
||||
> compatibility. In particular, there may be changes that do not cause
|
||||
> compilation errors, but do cause semantic changes (such as invoking
|
||||
> undefined behaviour). As such, extreme care is required.
|
||||
|
||||
# Pointers
|
||||
|
||||
## References
|
||||
|
||||
One of Rust's biggest features is memory safety. This is achieved in
|
||||
part via [the ownership system](ownership.html), which is how the
|
||||
compiler can guarantee that every `&` reference is always valid, and,
|
||||
for example, never pointing to freed memory.
|
||||
|
||||
These restrictions on `&` have huge advantages. However, they also
|
||||
constrain how we can use them. For example, `&` doesn't behave
|
||||
identically to C's pointers, and so cannot be used for pointers in
|
||||
foreign function interfaces (FFI). Additionally, both immutable (`&`)
|
||||
and mutable (`&mut`) references have some aliasing and freezing
|
||||
guarantees, required for memory safety.
|
||||
|
||||
In particular, if you have an `&T` reference, then the `T` must not be
|
||||
modified through that reference or any other reference. There are some
|
||||
standard library types, e.g. `Cell` and `RefCell`, that provide inner
|
||||
mutability by replacing compile time guarantees with dynamic checks at
|
||||
runtime.
|
||||
|
||||
An `&mut` reference has a different constraint: when an object has an
|
||||
`&mut T` pointing into it, then that `&mut` reference must be the only
|
||||
such usable path to that object in the whole program. That is, an
|
||||
`&mut` cannot alias with any other references.
|
||||
|
||||
Using `unsafe` code to incorrectly circumvent and violate these
|
||||
restrictions is undefined behaviour. For example, the following
|
||||
creates two aliasing `&mut` pointers, and is invalid.
|
||||
|
||||
```
|
||||
use std::mem;
|
||||
let mut x: u8 = 1;
|
||||
|
||||
let ref_1: &mut u8 = &mut x;
|
||||
let ref_2: &mut u8 = unsafe { mem::transmute(&mut *ref_1) };
|
||||
|
||||
// oops, ref_1 and ref_2 point to the same piece of data (x) and are
|
||||
// both usable
|
||||
*ref_1 = 10;
|
||||
*ref_2 = 20;
|
||||
```
|
||||
|
||||
## Raw pointers
|
||||
|
||||
Rust offers two additional pointer types (*raw pointers*), written as
|
||||
`*const T` and `*mut T`. They're an approximation of C's `const T*` and `T*`
|
||||
respectively; indeed, one of their most common uses is for FFI,
|
||||
interfacing with external C libraries.
|
||||
|
||||
Raw pointers have much fewer guarantees than other pointer types
|
||||
offered by the Rust language and libraries. For example, they
|
||||
|
||||
- are not guaranteed to point to valid memory and are not even
|
||||
guaranteed to be non-null (unlike both `Box` and `&`);
|
||||
- do not have any automatic clean-up, unlike `Box`, and so require
|
||||
manual resource management;
|
||||
- are plain-old-data, that is, they don't move ownership, again unlike
|
||||
`Box`, hence the Rust compiler cannot protect against bugs like
|
||||
use-after-free;
|
||||
- lack any form of lifetimes, unlike `&`, and so the compiler cannot
|
||||
reason about dangling pointers; and
|
||||
- have no guarantees about aliasing or mutability other than mutation
|
||||
not being allowed directly through a `*const T`.
|
||||
|
||||
Fortunately, they come with a redeeming feature: the weaker guarantees
|
||||
mean weaker restrictions. The missing restrictions make raw pointers
|
||||
appropriate as a building block for implementing things like smart
|
||||
pointers and vectors inside libraries. For example, `*` pointers are
|
||||
allowed to alias, allowing them to be used to write shared-ownership
|
||||
types like reference counted and garbage collected pointers, and even
|
||||
thread-safe shared memory types (`Rc` and the `Arc` types are both
|
||||
implemented entirely in Rust).
|
||||
|
||||
There are two things that you are required to be careful about
|
||||
(i.e. require an `unsafe { ... }` block) with raw pointers:
|
||||
|
||||
- dereferencing: they can have any value: so possible results include
|
||||
a crash, a read of uninitialised memory, a use-after-free, or
|
||||
reading data as normal.
|
||||
- pointer arithmetic via the `offset` [intrinsic](#intrinsics) (or
|
||||
`.offset` method): this intrinsic uses so-called "in-bounds"
|
||||
arithmetic, that is, it is only defined behaviour if the result is
|
||||
inside (or one-byte-past-the-end) of the object from which the
|
||||
original pointer came.
|
||||
|
||||
The latter assumption allows the compiler to optimize more
|
||||
effectively. As can be seen, actually *creating* a raw pointer is not
|
||||
unsafe, and neither is converting to an integer.
|
||||
|
||||
### References and raw pointers
|
||||
|
||||
At runtime, a raw pointer `*` and a reference pointing to the same
|
||||
piece of data have an identical representation. In fact, an `&T`
|
||||
reference will implicitly coerce to an `*const T` raw pointer in safe code
|
||||
and similarly for the `mut` variants (both coercions can be performed
|
||||
explicitly with, respectively, `value as *const T` and `value as *mut T`).
|
||||
|
||||
Going the opposite direction, from `*const` to a reference `&`, is not
|
||||
safe. A `&T` is always valid, and so, at a minimum, the raw pointer
|
||||
`*const T` has to point to a valid instance of type `T`. Furthermore,
|
||||
the resulting pointer must satisfy the aliasing and mutability laws of
|
||||
references. The compiler assumes these properties are true for any
|
||||
references, no matter how they are created, and so any conversion from
|
||||
raw pointers is asserting that they hold. The programmer *must*
|
||||
guarantee this.
|
||||
|
||||
The recommended method for the conversion is
|
||||
|
||||
```
|
||||
let i: u32 = 1;
|
||||
// explicit cast
|
||||
let p_imm: *const u32 = &i as *const u32;
|
||||
let mut m: u32 = 2;
|
||||
// implicit coercion
|
||||
let p_mut: *mut u32 = &mut m;
|
||||
|
||||
unsafe {
|
||||
let ref_imm: &u32 = &*p_imm;
|
||||
let ref_mut: &mut u32 = &mut *p_mut;
|
||||
}
|
||||
```
|
||||
|
||||
The `&*x` dereferencing style is preferred to using a `transmute`.
|
||||
The latter is far more powerful than necessary, and the more
|
||||
restricted operation is harder to use incorrectly; for example, it
|
||||
requires that `x` is a pointer (unlike `transmute`).
|
||||
|
||||
|
||||
|
||||
## Making the unsafe safe(r)
|
||||
|
||||
There are various ways to expose a safe interface around some unsafe
|
||||
code:
|
||||
|
||||
- store pointers privately (i.e. not in public fields of public
|
||||
structs), so that you can see and control all reads and writes to
|
||||
the pointer in one place.
|
||||
- use `assert!()` a lot: since you can't rely on the protection of the
|
||||
compiler & type-system to ensure that your `unsafe` code is correct
|
||||
at compile-time, use `assert!()` to verify that it is doing the
|
||||
right thing at run-time.
|
||||
- implement the `Drop` for resource clean-up via a destructor, and use
|
||||
RAII (Resource Acquisition Is Initialization). This reduces the need
|
||||
for any manual memory management by users, and automatically ensures
|
||||
that clean-up is always run, even when the thread panics.
|
||||
- ensure that any data stored behind a raw pointer is destroyed at the
|
||||
appropriate time.
|
||||
@ -3,7 +3,7 @@
|
||||
Rust also has a `while` loop. It looks like this:
|
||||
|
||||
```{rust}
|
||||
let mut x = 5; // mut x: u32
|
||||
let mut x = 5; // mut x: i32
|
||||
let mut done = false; // mut done: bool
|
||||
|
||||
while !done {
|
||||
|
||||
119
src/error-index-generator/main.rs
Normal file
119
src/error-index-generator/main.rs
Normal file
@ -0,0 +1,119 @@
|
||||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(rustc_private, rustdoc)]
|
||||
|
||||
extern crate syntax;
|
||||
extern crate rustdoc;
|
||||
extern crate serialize as rustc_serialize;
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
use std::fs::{read_dir, File};
|
||||
use std::io::{Read, Write};
|
||||
use std::path::Path;
|
||||
use std::error::Error;
|
||||
|
||||
use syntax::diagnostics::metadata::{get_metadata_dir, ErrorMetadataMap};
|
||||
|
||||
use rustdoc::html::markdown::Markdown;
|
||||
use rustc_serialize::json;
|
||||
|
||||
/// Load all the metadata files from `metadata_dir` into an in-memory map.
|
||||
fn load_all_errors(metadata_dir: &Path) -> Result<ErrorMetadataMap, Box<Error>> {
|
||||
let mut all_errors = BTreeMap::new();
|
||||
|
||||
for entry in try!(read_dir(metadata_dir)) {
|
||||
let path = try!(entry).path();
|
||||
|
||||
let mut metadata_str = String::new();
|
||||
try!(
|
||||
File::open(&path).and_then(|mut f|
|
||||
f.read_to_string(&mut metadata_str))
|
||||
);
|
||||
|
||||
let some_errors: ErrorMetadataMap = try!(json::decode(&metadata_str));
|
||||
|
||||
for (err_code, info) in some_errors {
|
||||
all_errors.insert(err_code, info);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(all_errors)
|
||||
}
|
||||
|
||||
/// Output an HTML page for the errors in `err_map` to `output_path`.
|
||||
fn render_error_page(err_map: &ErrorMetadataMap, output_path: &Path) -> Result<(), Box<Error>> {
|
||||
let mut output_file = try!(File::create(output_path));
|
||||
|
||||
try!(write!(&mut output_file,
|
||||
r##"<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Rust Compiler Error Index</title>
|
||||
<meta charset="utf-8">
|
||||
<!-- Include rust.css after main.css so its rules take priority. -->
|
||||
<link rel="stylesheet" type="text/css" href="main.css"/>
|
||||
<link rel="stylesheet" type="text/css" href="rust.css"/>
|
||||
<style>
|
||||
.error-undescribed {{
|
||||
display: none;
|
||||
}}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
"##
|
||||
));
|
||||
|
||||
try!(write!(&mut output_file, "<h1>Rust Compiler Error Index</h1>\n"));
|
||||
|
||||
for (err_code, info) in err_map.iter() {
|
||||
// Enclose each error in a div so they can be shown/hidden en masse.
|
||||
let desc_desc = match info.description {
|
||||
Some(_) => "error-described",
|
||||
None => "error-undescribed"
|
||||
};
|
||||
let use_desc = match info.use_site {
|
||||
Some(_) => "error-used",
|
||||
None => "error-unused"
|
||||
};
|
||||
try!(write!(&mut output_file, "<div class=\"{} {}\">", desc_desc, use_desc));
|
||||
|
||||
// Error title (with self-link).
|
||||
try!(write!(&mut output_file,
|
||||
"<h2 id=\"{0}\" class=\"section-header\"><a href=\"#{0}\">{0}</a></h2>\n",
|
||||
err_code
|
||||
));
|
||||
|
||||
// Description rendered as markdown.
|
||||
match info.description {
|
||||
Some(ref desc) => try!(write!(&mut output_file, "{}", Markdown(desc))),
|
||||
None => try!(write!(&mut output_file, "<p>No description.</p>\n"))
|
||||
}
|
||||
|
||||
try!(write!(&mut output_file, "</div>\n"));
|
||||
}
|
||||
|
||||
try!(write!(&mut output_file, "</body>\n</html>"));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn main_with_result() -> Result<(), Box<Error>> {
|
||||
let metadata_dir = get_metadata_dir();
|
||||
let err_map = try!(load_all_errors(&metadata_dir));
|
||||
try!(render_error_page(&err_map, Path::new("doc/error-index.html")));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn main() {
|
||||
if let Err(e) = main_with_result() {
|
||||
panic!("{}", e.description());
|
||||
}
|
||||
}
|
||||
@ -1,6 +1,8 @@
|
||||
# Configs
|
||||
|
||||
Here are some links to repos with configs which ease the use of rust:
|
||||
These are some links to repos with configs which ease the use of rust.
|
||||
|
||||
## Officially Maintained Configs
|
||||
|
||||
* [rust.vim](https://github.com/rust-lang/rust.vim)
|
||||
* [emacs rust-mode](https://github.com/rust-lang/rust-mode)
|
||||
@ -8,3 +10,7 @@ Here are some links to repos with configs which ease the use of rust:
|
||||
* [kate-config](https://github.com/rust-lang/kate-config)
|
||||
* [nano-config](https://github.com/rust-lang/nano-config)
|
||||
* [zsh-config](https://github.com/rust-lang/zsh-config)
|
||||
|
||||
## Community-maintained Configs
|
||||
|
||||
* [.editorconfig](https://gist.github.com/derhuerst/c9d1b9309e308d9851fa) ([what is this?](http://editorconfig.org/))
|
||||
|
||||
@ -13,7 +13,6 @@
|
||||
import os
|
||||
import sys
|
||||
import functools
|
||||
import resource
|
||||
|
||||
STATUS = 0
|
||||
|
||||
@ -37,6 +36,7 @@ def only_on(platforms):
|
||||
|
||||
@only_on(('linux', 'darwin', 'freebsd', 'openbsd'))
|
||||
def check_rlimit_core():
|
||||
import resource
|
||||
soft, hard = resource.getrlimit(resource.RLIMIT_CORE)
|
||||
if soft > 0:
|
||||
error_unless_permitted('ALLOW_NONZERO_RLIMIT_CORE', """\
|
||||
|
||||
@ -1,156 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
|
||||
# file at the top-level directory of this distribution and at
|
||||
# http://rust-lang.org/COPYRIGHT.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
# option. This file may not be copied, modified, or distributed
|
||||
# except according to those terms.
|
||||
|
||||
# This script is for extracting the grammar from the rust docs.
|
||||
|
||||
import fileinput
|
||||
|
||||
collections = {"gram": [],
|
||||
"keyword": [],
|
||||
"reserved": [],
|
||||
"binop": [],
|
||||
"unop": []}
|
||||
|
||||
|
||||
in_coll = False
|
||||
coll = ""
|
||||
|
||||
for line in fileinput.input(openhook=fileinput.hook_encoded("utf-8")):
|
||||
if in_coll:
|
||||
if line.startswith("~~~~"):
|
||||
in_coll = False
|
||||
else:
|
||||
if coll in ["keyword", "reserved", "binop", "unop"]:
|
||||
for word in line.split():
|
||||
if word not in collections[coll]:
|
||||
collections[coll].append(word)
|
||||
else:
|
||||
collections[coll].append(line)
|
||||
|
||||
else:
|
||||
if line.startswith("~~~~"):
|
||||
for cname in collections:
|
||||
if ("." + cname) in line:
|
||||
coll = cname
|
||||
in_coll = True
|
||||
break
|
||||
|
||||
# Define operator symbol-names here
|
||||
|
||||
tokens = ["non_star", "non_slash", "non_eol",
|
||||
"non_single_quote", "non_double_quote", "ident"]
|
||||
|
||||
symnames = {
|
||||
".": "dot",
|
||||
"+": "plus",
|
||||
"-": "minus",
|
||||
"/": "slash",
|
||||
"*": "star",
|
||||
"%": "percent",
|
||||
|
||||
"~": "tilde",
|
||||
"@": "at",
|
||||
|
||||
"!": "not",
|
||||
"&": "and",
|
||||
"|": "or",
|
||||
"^": "xor",
|
||||
|
||||
"<<": "lsl",
|
||||
">>": "lsr",
|
||||
">>>": "asr",
|
||||
|
||||
"&&": "andand",
|
||||
"||": "oror",
|
||||
|
||||
"<": "lt",
|
||||
"<=": "le",
|
||||
"==": "eqeq",
|
||||
">=": "ge",
|
||||
">": "gt",
|
||||
|
||||
"=": "eq",
|
||||
|
||||
"+=": "plusequal",
|
||||
"-=": "minusequal",
|
||||
"/=": "divequal",
|
||||
"*=": "starequal",
|
||||
"%=": "percentequal",
|
||||
|
||||
"&=": "andequal",
|
||||
"|=": "orequal",
|
||||
"^=": "xorequal",
|
||||
|
||||
">>=": "lsrequal",
|
||||
">>>=": "asrequal",
|
||||
"<<=": "lslequal",
|
||||
|
||||
"::": "coloncolon",
|
||||
|
||||
"->": "rightarrow",
|
||||
"<-": "leftarrow",
|
||||
"<->": "swaparrow",
|
||||
|
||||
"//": "linecomment",
|
||||
"/*": "openblockcomment",
|
||||
"*/": "closeblockcomment",
|
||||
"macro_rules": "macro_rules",
|
||||
"=>": "eg",
|
||||
"..": "dotdot",
|
||||
",": "comma"
|
||||
}
|
||||
|
||||
lines = []
|
||||
|
||||
for line in collections["gram"]:
|
||||
line2 = ""
|
||||
for word in line.split():
|
||||
# replace strings with keyword-names or symbol-names from table
|
||||
if word.startswith("\""):
|
||||
word = word[1:-1]
|
||||
if word in symnames:
|
||||
word = symnames[word]
|
||||
else:
|
||||
for ch in word:
|
||||
if not ch.isalpha():
|
||||
raise Exception("non-alpha apparent keyword: "
|
||||
+ word)
|
||||
if word not in tokens:
|
||||
if (word in collections["keyword"] or
|
||||
word in collections["reserved"]):
|
||||
tokens.append(word)
|
||||
else:
|
||||
raise Exception("unknown keyword/reserved word: "
|
||||
+ word)
|
||||
|
||||
line2 += " " + word
|
||||
lines.append(line2)
|
||||
|
||||
|
||||
for word in collections["keyword"] + collections["reserved"]:
|
||||
if word not in tokens:
|
||||
tokens.append(word)
|
||||
|
||||
for sym in collections["unop"] + collections["binop"] + symnames.keys():
|
||||
word = symnames[sym]
|
||||
if word not in tokens:
|
||||
tokens.append(word)
|
||||
|
||||
|
||||
print("%start parser, token;")
|
||||
print("%%token %s ;" % ("\n\t, ".join(tokens)))
|
||||
for coll in ["keyword", "reserved"]:
|
||||
print("%s: %s ; " % (coll, "\n\t| ".join(collections[coll])))
|
||||
for coll in ["binop", "unop"]:
|
||||
print("%s: %s ; " % (coll, "\n\t| ".join([symnames[x]
|
||||
for x in collections[coll]])))
|
||||
print("\n".join(lines))
|
||||
@ -46,13 +46,8 @@ def run(args):
|
||||
|
||||
f.write("\n")
|
||||
|
||||
version = run([llconfig, '--version']).strip()
|
||||
|
||||
# LLVM libs
|
||||
if version < '3.5':
|
||||
args = [llconfig, '--libs']
|
||||
else:
|
||||
args = [llconfig, '--libs', '--system-libs']
|
||||
args = [llconfig, '--libs', '--system-libs']
|
||||
|
||||
args.extend(components)
|
||||
out = run(args)
|
||||
@ -73,11 +68,6 @@ for lib in out.strip().replace("\n", ' ').split(' '):
|
||||
f.write(", kind = \"static\"")
|
||||
f.write(")]\n")
|
||||
|
||||
# llvm-config before 3.5 didn't have a system-libs flag
|
||||
if version < '3.5':
|
||||
if os == 'win32':
|
||||
f.write("#[link(name = \"imagehlp\")]")
|
||||
|
||||
# LLVM ldflags
|
||||
out = run([llconfig, '--ldflags'])
|
||||
for lib in out.strip().split(' '):
|
||||
|
||||
Binary file not shown.
@ -25,7 +25,7 @@
|
||||
|
||||
import fileinput, re, os, sys, operator
|
||||
|
||||
preamble = '''// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
|
||||
preamble = '''// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
@ -207,8 +207,8 @@ def format_table_content(f, content, indent):
|
||||
def load_properties(f, interestingprops):
|
||||
fetch(f)
|
||||
props = {}
|
||||
re1 = re.compile("^([0-9A-F]+) +; (\w+)")
|
||||
re2 = re.compile("^([0-9A-F]+)\.\.([0-9A-F]+) +; (\w+)")
|
||||
re1 = re.compile("^ *([0-9A-F]+) *; *(\w+)")
|
||||
re2 = re.compile("^ *([0-9A-F]+)\.\.([0-9A-F]+) *; *(\w+)")
|
||||
|
||||
for line in fileinput.input(os.path.basename(f)):
|
||||
prop = None
|
||||
@ -234,6 +234,11 @@ def load_properties(f, interestingprops):
|
||||
if prop not in props:
|
||||
props[prop] = []
|
||||
props[prop].append((d_lo, d_hi))
|
||||
|
||||
# optimize if possible
|
||||
for prop in props:
|
||||
props[prop] = group_cat(ungroup_cat(props[prop]))
|
||||
|
||||
return props
|
||||
|
||||
# load all widths of want_widths, except those in except_cats
|
||||
@ -518,11 +523,14 @@ def emit_norm_module(f, canon, compat, combine, norm_props):
|
||||
emit_table(f, "combining_class_table", combine, "&'static [(char, char, u8)]", is_pub=False,
|
||||
pfun=lambda x: "(%s,%s,%s)" % (escape_char(x[0]), escape_char(x[1]), x[2]))
|
||||
|
||||
f.write(" pub fn canonical_combining_class(c: char) -> u8 {\n"
|
||||
+ " bsearch_range_value_table(c, combining_class_table)\n"
|
||||
+ " }\n")
|
||||
f.write(""" #[deprecated(reason = "use the crates.io `unicode-normalization` lib instead",
|
||||
since = "1.0.0")]
|
||||
#[unstable(feature = "unicode",
|
||||
reason = "this functionality will be moved to crates.io")]
|
||||
pub fn canonical_combining_class(c: char) -> u8 {
|
||||
bsearch_range_value_table(c, combining_class_table)
|
||||
}
|
||||
|
||||
f.write("""
|
||||
}
|
||||
|
||||
""")
|
||||
|
||||
@ -1 +1 @@
|
||||
0.12.0-8398-ga59de37e99060162a2674e3ff45409ac73595c0e
|
||||
0.12.0-9659-g35ceea3997c79a3b7562e89b462ab76af5b86b22
|
||||
|
||||
@ -355,7 +355,6 @@ impl<T: Clone> Arc<T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[unsafe_destructor]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T> Drop for Arc<T> {
|
||||
/// Drops the `Arc<T>`.
|
||||
@ -489,7 +488,6 @@ impl<T> Clone for Weak<T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[unsafe_destructor]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T> Drop for Weak<T> {
|
||||
/// Drops the `Weak<T>`.
|
||||
@ -675,7 +673,7 @@ impl<T> fmt::Pointer for Arc<T> {
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: Default + Sync + Send> Default for Arc<T> {
|
||||
impl<T: Default> Default for Arc<T> {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
fn default() -> Arc<T> { Arc::new(Default::default()) }
|
||||
}
|
||||
|
||||
@ -37,7 +37,7 @@
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! This will print `Cons(1, Box(Cons(2, Box(Nil))))`.
|
||||
//! This will print `Cons(1, Cons(2, Nil))`.
|
||||
//!
|
||||
//! Recursive structures must be boxed, because if the definition of `Cons` looked like this:
|
||||
//!
|
||||
@ -62,6 +62,11 @@ use core::ops::{Deref, DerefMut};
|
||||
use core::ptr::{Unique};
|
||||
use core::raw::{TraitObject};
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
use core::marker::Unsize;
|
||||
#[cfg(not(stage0))]
|
||||
use core::ops::CoerceUnsized;
|
||||
|
||||
/// A value that represents the heap. This is the default place that the `box`
|
||||
/// keyword allocates into when no place is supplied.
|
||||
///
|
||||
@ -390,3 +395,6 @@ impl<'a,A,R> FnOnce<A> for Box<FnBox<A,Output=R>+Send+'a> {
|
||||
self.call_box(args)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
impl<T: ?Sized+Unsize<U>, U: ?Sized> CoerceUnsized<Box<U>> for Box<T> {}
|
||||
|
||||
@ -8,6 +8,15 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use core::{isize, usize};
|
||||
|
||||
#[inline(always)]
|
||||
fn check_size_and_alignment(size: usize, align: usize) {
|
||||
debug_assert!(size != 0);
|
||||
debug_assert!(size <= isize::MAX as usize, "Tried to allocate too much: {} bytes", size);
|
||||
debug_assert!(usize::is_power_of_two(align), "Invalid alignment of allocation: {}", align);
|
||||
}
|
||||
|
||||
// FIXME: #13996: mark the `allocate` and `reallocate` return value as `noalias`
|
||||
|
||||
/// Return a pointer to `size` bytes of memory aligned to `align`.
|
||||
@ -19,6 +28,7 @@
|
||||
/// size on the platform.
|
||||
#[inline]
|
||||
pub unsafe fn allocate(size: usize, align: usize) -> *mut u8 {
|
||||
check_size_and_alignment(size, align);
|
||||
imp::allocate(size, align)
|
||||
}
|
||||
|
||||
@ -38,6 +48,7 @@ pub unsafe fn allocate(size: usize, align: usize) -> *mut u8 {
|
||||
/// any value in range_inclusive(requested_size, usable_size).
|
||||
#[inline]
|
||||
pub unsafe fn reallocate(ptr: *mut u8, old_size: usize, size: usize, align: usize) -> *mut u8 {
|
||||
check_size_and_alignment(size, align);
|
||||
imp::reallocate(ptr, old_size, size, align)
|
||||
}
|
||||
|
||||
@ -56,6 +67,7 @@ pub unsafe fn reallocate(ptr: *mut u8, old_size: usize, size: usize, align: usiz
|
||||
#[inline]
|
||||
pub unsafe fn reallocate_inplace(ptr: *mut u8, old_size: usize, size: usize,
|
||||
align: usize) -> usize {
|
||||
check_size_and_alignment(size, align);
|
||||
imp::reallocate_inplace(ptr, old_size, size, align)
|
||||
}
|
||||
|
||||
@ -95,7 +107,7 @@ pub const EMPTY: *mut () = 0x1 as *mut ();
|
||||
|
||||
/// The allocator for unique pointers.
|
||||
#[cfg(not(test))]
|
||||
#[lang="exchange_malloc"]
|
||||
#[lang = "exchange_malloc"]
|
||||
#[inline]
|
||||
unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 {
|
||||
if size == 0 {
|
||||
@ -108,7 +120,7 @@ unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 {
|
||||
}
|
||||
|
||||
#[cfg(not(test))]
|
||||
#[lang="exchange_free"]
|
||||
#[lang = "exchange_free"]
|
||||
#[inline]
|
||||
unsafe fn exchange_free(ptr: *mut u8, old_size: usize, align: usize) {
|
||||
deallocate(ptr, old_size, align);
|
||||
@ -133,6 +145,7 @@ const MIN_ALIGN: usize = 16;
|
||||
|
||||
#[cfg(feature = "external_funcs")]
|
||||
mod imp {
|
||||
#[allow(improper_ctypes)]
|
||||
extern {
|
||||
fn rust_allocate(size: usize, align: usize) -> *mut u8;
|
||||
fn rust_deallocate(ptr: *mut u8, old_size: usize, align: usize);
|
||||
@ -210,7 +223,9 @@ mod imp {
|
||||
}
|
||||
|
||||
// -lpthread needs to occur after -ljemalloc, the earlier argument isn't enough
|
||||
#[cfg(all(not(windows), not(target_os = "android")))]
|
||||
#[cfg(all(not(windows),
|
||||
not(target_os = "android"),
|
||||
not(target_env = "musl")))]
|
||||
#[link(name = "pthread")]
|
||||
extern {}
|
||||
|
||||
@ -383,7 +398,7 @@ mod imp {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
mod tests {
|
||||
extern crate test;
|
||||
use self::test::Bencher;
|
||||
use boxed::Box;
|
||||
|
||||
@ -73,7 +73,7 @@
|
||||
#![feature(allocator)]
|
||||
#![feature(custom_attribute)]
|
||||
#![feature(fundamental)]
|
||||
#![feature(lang_items, unsafe_destructor)]
|
||||
#![feature(lang_items)]
|
||||
#![feature(box_syntax)]
|
||||
#![feature(optin_builtin_traits)]
|
||||
#![feature(unboxed_closures)]
|
||||
|
||||
@ -159,7 +159,7 @@ use core::cmp::{PartialEq, PartialOrd, Eq, Ord, Ordering};
|
||||
use core::default::Default;
|
||||
use core::fmt;
|
||||
use core::hash::{Hasher, Hash};
|
||||
use core::marker;
|
||||
use core::marker::{self, Sized};
|
||||
use core::mem::{self, min_align_of, size_of, forget};
|
||||
use core::nonzero::NonZero;
|
||||
use core::ops::{Deref, Drop};
|
||||
@ -170,17 +170,36 @@ use core::result::Result;
|
||||
use core::result::Result::{Ok, Err};
|
||||
use core::intrinsics::assume;
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
use core::intrinsics::drop_in_place;
|
||||
#[cfg(not(stage0))]
|
||||
use core::marker::Unsize;
|
||||
#[cfg(not(stage0))]
|
||||
use core::mem::{min_align_of_val, size_of_val};
|
||||
#[cfg(not(stage0))]
|
||||
use core::ops::CoerceUnsized;
|
||||
|
||||
use heap::deallocate;
|
||||
|
||||
#[cfg(stage0)]
|
||||
struct RcBox<T> {
|
||||
value: T,
|
||||
strong: Cell<usize>,
|
||||
weak: Cell<usize>
|
||||
weak: Cell<usize>,
|
||||
value: T,
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
struct RcBox<T: ?Sized> {
|
||||
strong: Cell<usize>,
|
||||
weak: Cell<usize>,
|
||||
value: T,
|
||||
}
|
||||
|
||||
|
||||
/// A reference-counted pointer type over an immutable value.
|
||||
///
|
||||
/// See the [module level documentation](./index.html) for more details.
|
||||
#[cfg(stage0)]
|
||||
#[unsafe_no_drop_flag]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub struct Rc<T> {
|
||||
@ -188,11 +207,30 @@ pub struct Rc<T> {
|
||||
// accesses of the contained type via Deref
|
||||
_ptr: NonZero<*mut RcBox<T>>,
|
||||
}
|
||||
#[cfg(not(stage0))]
|
||||
#[unsafe_no_drop_flag]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub struct Rc<T: ?Sized> {
|
||||
// FIXME #12808: strange names to try to avoid interfering with field
|
||||
// accesses of the contained type via Deref
|
||||
_ptr: NonZero<*mut RcBox<T>>,
|
||||
}
|
||||
|
||||
#[cfg(stage0)]
|
||||
impl<T> !marker::Send for Rc<T> {}
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
impl<T: ?Sized> !marker::Send for Rc<T> {}
|
||||
|
||||
#[cfg(stage0)]
|
||||
impl<T> !marker::Sync for Rc<T> {}
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
impl<T: ?Sized> !marker::Sync for Rc<T> {}
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
impl<T: ?Sized+Unsize<U>, U: ?Sized> CoerceUnsized<Rc<U>> for Rc<T> {}
|
||||
|
||||
impl<T> Rc<T> {
|
||||
/// Constructs a new `Rc<T>`.
|
||||
///
|
||||
@ -212,14 +250,39 @@ impl<T> Rc<T> {
|
||||
// the allocation while the strong destructor is running, even
|
||||
// if the weak pointer is stored inside the strong one.
|
||||
_ptr: NonZero::new(boxed::into_raw(box RcBox {
|
||||
value: value,
|
||||
strong: Cell::new(1),
|
||||
weak: Cell::new(1)
|
||||
weak: Cell::new(1),
|
||||
value: value
|
||||
})),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
impl<T: ?Sized> Rc<T> {
|
||||
/// Downgrades the `Rc<T>` to a `Weak<T>` reference.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(alloc)]
|
||||
/// use std::rc::Rc;
|
||||
///
|
||||
/// let five = Rc::new(5);
|
||||
///
|
||||
/// let weak_five = five.downgrade();
|
||||
/// ```
|
||||
#[unstable(feature = "alloc",
|
||||
reason = "Weak pointers may not belong in this module")]
|
||||
pub fn downgrade(&self) -> Weak<T> {
|
||||
self.inc_weak();
|
||||
Weak { _ptr: self._ptr }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(stage0)]
|
||||
impl<T> Rc<T> {
|
||||
/// Downgrades the `Rc<T>` to a `Weak<T>` reference.
|
||||
///
|
||||
/// # Examples
|
||||
@ -241,14 +304,24 @@ impl<T> Rc<T> {
|
||||
}
|
||||
|
||||
/// Get the number of weak references to this value.
|
||||
#[cfg(stage0)]
|
||||
#[inline]
|
||||
#[unstable(feature = "alloc")]
|
||||
pub fn weak_count<T>(this: &Rc<T>) -> usize { this.weak() - 1 }
|
||||
#[cfg(not(stage0))]
|
||||
#[inline]
|
||||
#[unstable(feature = "alloc")]
|
||||
pub fn weak_count<T: ?Sized>(this: &Rc<T>) -> usize { this.weak() - 1 }
|
||||
|
||||
/// Get the number of strong references to this value.
|
||||
#[cfg(stage0)]
|
||||
#[inline]
|
||||
#[unstable(feature = "alloc")]
|
||||
pub fn strong_count<T>(this: &Rc<T>) -> usize { this.strong() }
|
||||
#[cfg(not(stage0))]
|
||||
#[inline]
|
||||
#[unstable(feature = "alloc")]
|
||||
pub fn strong_count<T: ?Sized>(this: &Rc<T>) -> usize { this.strong() }
|
||||
|
||||
/// Returns true if there are no other `Rc` or `Weak<T>` values that share the
|
||||
/// same inner value.
|
||||
@ -365,6 +438,7 @@ impl<T: Clone> Rc<T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(stage0)]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T> Deref for Rc<T> {
|
||||
type Target = T;
|
||||
@ -374,8 +448,18 @@ impl<T> Deref for Rc<T> {
|
||||
&self.inner().value
|
||||
}
|
||||
}
|
||||
#[cfg(not(stage0))]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: ?Sized> Deref for Rc<T> {
|
||||
type Target = T;
|
||||
|
||||
#[unsafe_destructor]
|
||||
#[inline(always)]
|
||||
fn deref(&self) -> &T {
|
||||
&self.inner().value
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(stage0)]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T> Drop for Rc<T> {
|
||||
/// Drops the `Rc<T>`.
|
||||
@ -426,6 +510,61 @@ impl<T> Drop for Rc<T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: ?Sized> Drop for Rc<T> {
|
||||
/// Drops the `Rc<T>`.
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(alloc)]
|
||||
/// use std::rc::Rc;
|
||||
///
|
||||
/// {
|
||||
/// let five = Rc::new(5);
|
||||
///
|
||||
/// // stuff
|
||||
///
|
||||
/// drop(five); // explicit drop
|
||||
/// }
|
||||
/// {
|
||||
/// let five = Rc::new(5);
|
||||
///
|
||||
/// // stuff
|
||||
///
|
||||
/// } // implicit drop
|
||||
/// ```
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
let ptr = *self._ptr;
|
||||
if !(*(&ptr as *const _ as *const *const ())).is_null() &&
|
||||
ptr as usize != mem::POST_DROP_USIZE {
|
||||
self.dec_strong();
|
||||
if self.strong() == 0 {
|
||||
// destroy the contained object
|
||||
drop_in_place(&mut (*ptr).value);
|
||||
|
||||
// remove the implicit "strong weak" pointer now that we've
|
||||
// destroyed the contents.
|
||||
self.dec_weak();
|
||||
|
||||
if self.weak() == 0 {
|
||||
deallocate(ptr as *mut u8,
|
||||
size_of_val(&*ptr),
|
||||
min_align_of_val(&*ptr))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(stage0)]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T> Clone for Rc<T> {
|
||||
|
||||
@ -450,6 +589,31 @@ impl<T> Clone for Rc<T> {
|
||||
Rc { _ptr: self._ptr }
|
||||
}
|
||||
}
|
||||
#[cfg(not(stage0))]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: ?Sized> Clone for Rc<T> {
|
||||
|
||||
/// Makes a clone of the `Rc<T>`.
|
||||
///
|
||||
/// When you clone an `Rc<T>`, it will create another pointer to the data and
|
||||
/// increase the strong reference counter.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(alloc)]
|
||||
/// use std::rc::Rc;
|
||||
///
|
||||
/// let five = Rc::new(5);
|
||||
///
|
||||
/// five.clone();
|
||||
/// ```
|
||||
#[inline]
|
||||
fn clone(&self) -> Rc<T> {
|
||||
self.inc_strong();
|
||||
Rc { _ptr: self._ptr }
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: Default> Default for Rc<T> {
|
||||
@ -611,27 +775,50 @@ impl<T: Ord> Ord for Rc<T> {
|
||||
fn cmp(&self, other: &Rc<T>) -> Ordering { (**self).cmp(&**other) }
|
||||
}
|
||||
|
||||
// FIXME (#18248) Make `T` `Sized?`
|
||||
#[cfg(stage0)]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: Hash> Hash for Rc<T> {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
(**self).hash(state);
|
||||
}
|
||||
}
|
||||
#[cfg(not(stage0))]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: ?Sized+Hash> Hash for Rc<T> {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
(**self).hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(stage0)]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: fmt::Display> fmt::Display for Rc<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt::Display::fmt(&**self, f)
|
||||
}
|
||||
}
|
||||
#[cfg(not(stage0))]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: ?Sized+fmt::Display> fmt::Display for Rc<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt::Display::fmt(&**self, f)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(stage0)]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: fmt::Debug> fmt::Debug for Rc<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt::Debug::fmt(&**self, f)
|
||||
}
|
||||
}
|
||||
#[cfg(not(stage0))]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: ?Sized+fmt::Debug> fmt::Debug for Rc<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt::Debug::fmt(&**self, f)
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T> fmt::Pointer for Rc<T> {
|
||||
@ -646,6 +833,7 @@ impl<T> fmt::Pointer for Rc<T> {
|
||||
/// dropped.
|
||||
///
|
||||
/// See the [module level documentation](./index.html) for more.
|
||||
#[cfg(stage0)]
|
||||
#[unsafe_no_drop_flag]
|
||||
#[unstable(feature = "alloc",
|
||||
reason = "Weak pointers may not belong in this module.")]
|
||||
@ -654,12 +842,28 @@ pub struct Weak<T> {
|
||||
// field accesses of the contained type via Deref
|
||||
_ptr: NonZero<*mut RcBox<T>>,
|
||||
}
|
||||
#[cfg(not(stage0))]
|
||||
#[unsafe_no_drop_flag]
|
||||
#[unstable(feature = "alloc",
|
||||
reason = "Weak pointers may not belong in this module.")]
|
||||
pub struct Weak<T: ?Sized> {
|
||||
// FIXME #12808: strange names to try to avoid interfering with
|
||||
// field accesses of the contained type via Deref
|
||||
_ptr: NonZero<*mut RcBox<T>>,
|
||||
}
|
||||
|
||||
#[cfg(stage0)]
|
||||
impl<T> !marker::Send for Weak<T> {}
|
||||
#[cfg(not(stage0))]
|
||||
impl<T: ?Sized> !marker::Send for Weak<T> {}
|
||||
|
||||
#[cfg(stage0)]
|
||||
impl<T> !marker::Sync for Weak<T> {}
|
||||
#[cfg(not(stage0))]
|
||||
impl<T: ?Sized> !marker::Sync for Weak<T> {}
|
||||
|
||||
|
||||
#[cfg(stage0)]
|
||||
#[unstable(feature = "alloc",
|
||||
reason = "Weak pointers may not belong in this module.")]
|
||||
impl<T> Weak<T> {
|
||||
@ -692,8 +896,41 @@ impl<T> Weak<T> {
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(not(stage0))]
|
||||
#[unstable(feature = "alloc",
|
||||
reason = "Weak pointers may not belong in this module.")]
|
||||
impl<T: ?Sized> Weak<T> {
|
||||
|
||||
#[unsafe_destructor]
|
||||
/// Upgrades a weak reference to a strong reference.
|
||||
///
|
||||
/// Upgrades the `Weak<T>` reference to an `Rc<T>`, if possible.
|
||||
///
|
||||
/// Returns `None` if there were no strong references and the data was
|
||||
/// destroyed.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(alloc)]
|
||||
/// use std::rc::Rc;
|
||||
///
|
||||
/// let five = Rc::new(5);
|
||||
///
|
||||
/// let weak_five = five.downgrade();
|
||||
///
|
||||
/// let strong_five: Option<Rc<_>> = weak_five.upgrade();
|
||||
/// ```
|
||||
pub fn upgrade(&self) -> Option<Rc<T>> {
|
||||
if self.strong() == 0 {
|
||||
None
|
||||
} else {
|
||||
self.inc_strong();
|
||||
Some(Rc { _ptr: self._ptr })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(stage0)]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T> Drop for Weak<T> {
|
||||
/// Drops the `Weak<T>`.
|
||||
@ -738,6 +975,53 @@ impl<T> Drop for Weak<T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: ?Sized> Drop for Weak<T> {
|
||||
/// Drops the `Weak<T>`.
|
||||
///
|
||||
/// This will decrement the weak reference count.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(alloc)]
|
||||
/// use std::rc::Rc;
|
||||
///
|
||||
/// {
|
||||
/// let five = Rc::new(5);
|
||||
/// let weak_five = five.downgrade();
|
||||
///
|
||||
/// // stuff
|
||||
///
|
||||
/// drop(weak_five); // explicit drop
|
||||
/// }
|
||||
/// {
|
||||
/// let five = Rc::new(5);
|
||||
/// let weak_five = five.downgrade();
|
||||
///
|
||||
/// // stuff
|
||||
///
|
||||
/// } // implicit drop
|
||||
/// ```
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
let ptr = *self._ptr;
|
||||
if !(*(&ptr as *const _ as *const *const ())).is_null() &&
|
||||
ptr as usize != mem::POST_DROP_USIZE {
|
||||
self.dec_weak();
|
||||
// the weak count starts at 1, and will only go to zero if all
|
||||
// the strong pointers have disappeared.
|
||||
if self.weak() == 0 {
|
||||
deallocate(ptr as *mut u8, size_of_val(&*ptr),
|
||||
min_align_of_val(&*ptr))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(stage0)]
|
||||
#[unstable(feature = "alloc",
|
||||
reason = "Weak pointers may not belong in this module.")]
|
||||
impl<T> Clone for Weak<T> {
|
||||
@ -762,14 +1046,48 @@ impl<T> Clone for Weak<T> {
|
||||
Weak { _ptr: self._ptr }
|
||||
}
|
||||
}
|
||||
#[cfg(not(stage0))]
|
||||
#[unstable(feature = "alloc",
|
||||
reason = "Weak pointers may not belong in this module.")]
|
||||
impl<T: ?Sized> Clone for Weak<T> {
|
||||
|
||||
/// Makes a clone of the `Weak<T>`.
|
||||
///
|
||||
/// This increases the weak reference count.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(alloc)]
|
||||
/// use std::rc::Rc;
|
||||
///
|
||||
/// let weak_five = Rc::new(5).downgrade();
|
||||
///
|
||||
/// weak_five.clone();
|
||||
/// ```
|
||||
#[inline]
|
||||
fn clone(&self) -> Weak<T> {
|
||||
self.inc_weak();
|
||||
Weak { _ptr: self._ptr }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(stage0)]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: fmt::Debug> fmt::Debug for Weak<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "(Weak)")
|
||||
}
|
||||
}
|
||||
#[cfg(not(stage0))]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: ?Sized+fmt::Debug> fmt::Debug for Weak<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "(Weak)")
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(stage0)]
|
||||
#[doc(hidden)]
|
||||
trait RcBoxPtr<T> {
|
||||
fn inner(&self) -> &RcBox<T>;
|
||||
@ -792,7 +1110,31 @@ trait RcBoxPtr<T> {
|
||||
#[inline]
|
||||
fn dec_weak(&self) { self.inner().weak.set(self.weak() - 1); }
|
||||
}
|
||||
#[cfg(not(stage0))]
|
||||
#[doc(hidden)]
|
||||
trait RcBoxPtr<T: ?Sized> {
|
||||
fn inner(&self) -> &RcBox<T>;
|
||||
|
||||
#[inline]
|
||||
fn strong(&self) -> usize { self.inner().strong.get() }
|
||||
|
||||
#[inline]
|
||||
fn inc_strong(&self) { self.inner().strong.set(self.strong() + 1); }
|
||||
|
||||
#[inline]
|
||||
fn dec_strong(&self) { self.inner().strong.set(self.strong() - 1); }
|
||||
|
||||
#[inline]
|
||||
fn weak(&self) -> usize { self.inner().weak.get() }
|
||||
|
||||
#[inline]
|
||||
fn inc_weak(&self) { self.inner().weak.set(self.weak() + 1); }
|
||||
|
||||
#[inline]
|
||||
fn dec_weak(&self) { self.inner().weak.set(self.weak() - 1); }
|
||||
}
|
||||
|
||||
#[cfg(stage0)]
|
||||
impl<T> RcBoxPtr<T> for Rc<T> {
|
||||
#[inline(always)]
|
||||
fn inner(&self) -> &RcBox<T> {
|
||||
@ -801,12 +1143,27 @@ impl<T> RcBoxPtr<T> for Rc<T> {
|
||||
// the contract anyway.
|
||||
// This allows the null check to be elided in the destructor if we
|
||||
// manipulated the reference count in the same function.
|
||||
assume(!self._ptr.is_null());
|
||||
assume(!(*(&self._ptr as *const _ as *const *const ())).is_null());
|
||||
&(**self._ptr)
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(not(stage0))]
|
||||
impl<T: ?Sized> RcBoxPtr<T> for Rc<T> {
|
||||
#[inline(always)]
|
||||
fn inner(&self) -> &RcBox<T> {
|
||||
unsafe {
|
||||
// Safe to assume this here, as if it weren't true, we'd be breaking
|
||||
// the contract anyway.
|
||||
// This allows the null check to be elided in the destructor if we
|
||||
// manipulated the reference count in the same function.
|
||||
assume(!(*(&self._ptr as *const _ as *const *const ())).is_null());
|
||||
&(**self._ptr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(stage0)]
|
||||
impl<T> RcBoxPtr<T> for Weak<T> {
|
||||
#[inline(always)]
|
||||
fn inner(&self) -> &RcBox<T> {
|
||||
@ -815,7 +1172,21 @@ impl<T> RcBoxPtr<T> for Weak<T> {
|
||||
// the contract anyway.
|
||||
// This allows the null check to be elided in the destructor if we
|
||||
// manipulated the reference count in the same function.
|
||||
assume(!self._ptr.is_null());
|
||||
assume(!(*(&self._ptr as *const _ as *const *const ())).is_null());
|
||||
&(**self._ptr)
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(not(stage0))]
|
||||
impl<T: ?Sized> RcBoxPtr<T> for Weak<T> {
|
||||
#[inline(always)]
|
||||
fn inner(&self) -> &RcBox<T> {
|
||||
unsafe {
|
||||
// Safe to assume this here, as if it weren't true, we'd be breaking
|
||||
// the contract anyway.
|
||||
// This allows the null check to be elided in the destructor if we
|
||||
// manipulated the reference count in the same function.
|
||||
assume(!(*(&self._ptr as *const _ as *const *const ())).is_null());
|
||||
&(**self._ptr)
|
||||
}
|
||||
}
|
||||
|
||||
@ -35,7 +35,6 @@
|
||||
#![feature(core)]
|
||||
#![feature(staged_api)]
|
||||
#![feature(unboxed_closures)]
|
||||
#![feature(unsafe_destructor)]
|
||||
#![cfg_attr(test, feature(test))]
|
||||
|
||||
extern crate alloc;
|
||||
@ -124,7 +123,6 @@ fn chunk(size: usize, is_copy: bool) -> Chunk {
|
||||
}
|
||||
}
|
||||
|
||||
#[unsafe_destructor]
|
||||
impl<'longer_than_self> Drop for Arena<'longer_than_self> {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
@ -510,7 +508,6 @@ impl<T> TypedArena<T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[unsafe_destructor]
|
||||
impl<T> Drop for TypedArena<T> {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
|
||||
@ -153,7 +153,7 @@
|
||||
use core::prelude::*;
|
||||
|
||||
use core::iter::{FromIterator};
|
||||
use core::mem::{zeroed, replace, swap};
|
||||
use core::mem::swap;
|
||||
use core::ptr;
|
||||
|
||||
use slice;
|
||||
@ -484,46 +484,42 @@ impl<T: Ord> BinaryHeap<T> {
|
||||
|
||||
// The implementations of sift_up and sift_down use unsafe blocks in
|
||||
// order to move an element out of the vector (leaving behind a
|
||||
// zeroed element), shift along the others and move it back into the
|
||||
// vector over the junk element. This reduces the constant factor
|
||||
// compared to using swaps, which involves twice as many moves.
|
||||
fn sift_up(&mut self, start: usize, mut pos: usize) {
|
||||
// hole), shift along the others and move the removed element back into the
|
||||
// vector at the final location of the hole.
|
||||
// The `Hole` type is used to represent this, and make sure
|
||||
// the hole is filled back at the end of its scope, even on panic.
|
||||
// Using a hole reduces the constant factor compared to using swaps,
|
||||
// which involves twice as many moves.
|
||||
fn sift_up(&mut self, start: usize, pos: usize) {
|
||||
unsafe {
|
||||
let new = replace(&mut self.data[pos], zeroed());
|
||||
// Take out the value at `pos` and create a hole.
|
||||
let mut hole = Hole::new(&mut self.data, pos);
|
||||
|
||||
while pos > start {
|
||||
let parent = (pos - 1) >> 1;
|
||||
|
||||
if new <= self.data[parent] { break; }
|
||||
|
||||
let x = replace(&mut self.data[parent], zeroed());
|
||||
ptr::write(&mut self.data[pos], x);
|
||||
pos = parent;
|
||||
while hole.pos() > start {
|
||||
let parent = (hole.pos() - 1) / 2;
|
||||
if hole.removed() <= hole.get(parent) { break }
|
||||
hole.move_to(parent);
|
||||
}
|
||||
ptr::write(&mut self.data[pos], new);
|
||||
}
|
||||
}
|
||||
|
||||
fn sift_down_range(&mut self, mut pos: usize, end: usize) {
|
||||
let start = pos;
|
||||
unsafe {
|
||||
let start = pos;
|
||||
let new = replace(&mut self.data[pos], zeroed());
|
||||
|
||||
let mut hole = Hole::new(&mut self.data, pos);
|
||||
let mut child = 2 * pos + 1;
|
||||
while child < end {
|
||||
let right = child + 1;
|
||||
if right < end && !(self.data[child] > self.data[right]) {
|
||||
if right < end && !(hole.get(child) > hole.get(right)) {
|
||||
child = right;
|
||||
}
|
||||
let x = replace(&mut self.data[child], zeroed());
|
||||
ptr::write(&mut self.data[pos], x);
|
||||
pos = child;
|
||||
child = 2 * pos + 1;
|
||||
hole.move_to(child);
|
||||
child = 2 * hole.pos() + 1;
|
||||
}
|
||||
|
||||
ptr::write(&mut self.data[pos], new);
|
||||
self.sift_up(start, pos);
|
||||
pos = hole.pos;
|
||||
}
|
||||
self.sift_up(start, pos);
|
||||
}
|
||||
|
||||
fn sift_down(&mut self, pos: usize) {
|
||||
@ -546,7 +542,7 @@ impl<T: Ord> BinaryHeap<T> {
|
||||
#[unstable(feature = "collections",
|
||||
reason = "matches collection reform specification, waiting for dust to settle")]
|
||||
pub fn drain(&mut self) -> Drain<T> {
|
||||
Drain { iter: self.data.drain() }
|
||||
Drain { iter: self.data.drain(..) }
|
||||
}
|
||||
|
||||
/// Drops all items from the binary heap.
|
||||
@ -554,6 +550,73 @@ impl<T: Ord> BinaryHeap<T> {
|
||||
pub fn clear(&mut self) { self.drain(); }
|
||||
}
|
||||
|
||||
/// Hole represents a hole in a slice i.e. an index without valid value
|
||||
/// (because it was moved from or duplicated).
|
||||
/// In drop, `Hole` will restore the slice by filling the hole
|
||||
/// position with the value that was originally removed.
|
||||
struct Hole<'a, T: 'a> {
|
||||
data: &'a mut [T],
|
||||
/// `elt` is always `Some` from new until drop.
|
||||
elt: Option<T>,
|
||||
pos: usize,
|
||||
}
|
||||
|
||||
impl<'a, T> Hole<'a, T> {
|
||||
/// Create a new Hole at index `pos`.
|
||||
fn new(data: &'a mut [T], pos: usize) -> Self {
|
||||
unsafe {
|
||||
let elt = ptr::read(&data[pos]);
|
||||
Hole {
|
||||
data: data,
|
||||
elt: Some(elt),
|
||||
pos: pos,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn pos(&self) -> usize { self.pos }
|
||||
|
||||
/// Return a reference to the element removed
|
||||
#[inline(always)]
|
||||
fn removed(&self) -> &T {
|
||||
self.elt.as_ref().unwrap()
|
||||
}
|
||||
|
||||
/// Return a reference to the element at `index`.
|
||||
///
|
||||
/// Panics if the index is out of bounds.
|
||||
///
|
||||
/// Unsafe because index must not equal pos.
|
||||
#[inline(always)]
|
||||
unsafe fn get(&self, index: usize) -> &T {
|
||||
debug_assert!(index != self.pos);
|
||||
&self.data[index]
|
||||
}
|
||||
|
||||
/// Move hole to new location
|
||||
///
|
||||
/// Unsafe because index must not equal pos.
|
||||
#[inline(always)]
|
||||
unsafe fn move_to(&mut self, index: usize) {
|
||||
debug_assert!(index != self.pos);
|
||||
let index_ptr: *const _ = &self.data[index];
|
||||
let hole_ptr = &mut self.data[self.pos];
|
||||
ptr::copy_nonoverlapping(index_ptr, hole_ptr, 1);
|
||||
self.pos = index;
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Drop for Hole<'a, T> {
|
||||
fn drop(&mut self) {
|
||||
// fill the hole again
|
||||
unsafe {
|
||||
let pos = self.pos;
|
||||
ptr::write(&mut self.data[pos], self.elt.take().unwrap());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// `BinaryHeap` iterator.
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub struct Iter <'a, T: 'a> {
|
||||
|
||||
@ -89,6 +89,7 @@ use core::hash;
|
||||
use core::iter::RandomAccessIterator;
|
||||
use core::iter::{Chain, Enumerate, Repeat, Skip, Take, repeat, Cloned};
|
||||
use core::iter::{self, FromIterator};
|
||||
use core::mem::swap;
|
||||
use core::ops::Index;
|
||||
use core::slice;
|
||||
use core::{u8, u32, usize};
|
||||
@ -210,15 +211,13 @@ impl BitVec {
|
||||
assert_eq!(self.len(), other.len());
|
||||
// This could theoretically be a `debug_assert!`.
|
||||
assert_eq!(self.storage.len(), other.storage.len());
|
||||
let mut changed = false;
|
||||
let mut changed_bits = 0;
|
||||
for (a, b) in self.blocks_mut().zip(other.blocks()) {
|
||||
let w = op(*a, b);
|
||||
if *a != w {
|
||||
changed = true;
|
||||
*a = w;
|
||||
}
|
||||
changed_bits |= *a ^ w;
|
||||
*a = w;
|
||||
}
|
||||
changed
|
||||
changed_bits != 0
|
||||
}
|
||||
|
||||
/// Iterator over mutable refs to the underlying blocks of data.
|
||||
@ -604,6 +603,110 @@ impl BitVec {
|
||||
Iter { bit_vec: self, next_idx: 0, end_idx: self.nbits }
|
||||
}
|
||||
|
||||
/// Moves all bits from `other` into `Self`, leaving `other` empty.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(collections, bit_vec_append_split_off)]
|
||||
/// use std::collections::BitVec;
|
||||
///
|
||||
/// let mut a = BitVec::from_bytes(&[0b10000000]);
|
||||
/// let mut b = BitVec::from_bytes(&[0b01100001]);
|
||||
///
|
||||
/// a.append(&mut b);
|
||||
///
|
||||
/// assert_eq!(a.len(), 16);
|
||||
/// assert_eq!(b.len(), 0);
|
||||
/// assert!(a.eq_vec(&[true, false, false, false, false, false, false, false,
|
||||
/// false, true, true, false, false, false, false, true]));
|
||||
/// ```
|
||||
#[unstable(feature = "bit_vec_append_split_off",
|
||||
reason = "recently added as part of collections reform 2")]
|
||||
pub fn append(&mut self, other: &mut Self) {
|
||||
let b = self.len() % u32::BITS;
|
||||
|
||||
self.nbits += other.len();
|
||||
other.nbits = 0;
|
||||
|
||||
if b == 0 {
|
||||
self.storage.append(&mut other.storage);
|
||||
} else {
|
||||
self.storage.reserve(other.storage.len());
|
||||
|
||||
for block in other.storage.drain(..) {
|
||||
*(self.storage.last_mut().unwrap()) |= block << b;
|
||||
self.storage.push(block >> (u32::BITS - b));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Splits the `BitVec` into two at the given bit,
|
||||
/// retaining the first half in-place and returning the second one.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if `at` is out of bounds.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(collections, bit_vec_append_split_off)]
|
||||
/// use std::collections::BitVec;
|
||||
/// let mut a = BitVec::new();
|
||||
/// a.push(true);
|
||||
/// a.push(false);
|
||||
/// a.push(false);
|
||||
/// a.push(true);
|
||||
///
|
||||
/// let b = a.split_off(2);
|
||||
///
|
||||
/// assert_eq!(a.len(), 2);
|
||||
/// assert_eq!(b.len(), 2);
|
||||
/// assert!(a.eq_vec(&[true, false]));
|
||||
/// assert!(b.eq_vec(&[false, true]));
|
||||
/// ```
|
||||
#[unstable(feature = "bit_vec_append_split_off",
|
||||
reason = "recently added as part of collections reform 2")]
|
||||
pub fn split_off(&mut self, at: usize) -> Self {
|
||||
assert!(at <= self.len(), "`at` out of bounds");
|
||||
|
||||
let mut other = BitVec::new();
|
||||
|
||||
if at == 0 {
|
||||
swap(self, &mut other);
|
||||
return other;
|
||||
} else if at == self.len() {
|
||||
return other;
|
||||
}
|
||||
|
||||
let w = at / u32::BITS;
|
||||
let b = at % u32::BITS;
|
||||
other.nbits = self.nbits - at;
|
||||
self.nbits = at;
|
||||
if b == 0 {
|
||||
// Split at block boundary
|
||||
other.storage = self.storage.split_off(w);
|
||||
} else {
|
||||
other.storage.reserve(self.storage.len() - w);
|
||||
|
||||
{
|
||||
let mut iter = self.storage[w..].iter();
|
||||
let mut last = *iter.next().unwrap();
|
||||
for &cur in iter {
|
||||
other.storage.push((last >> b) | (cur << (u32::BITS - b)));
|
||||
last = cur;
|
||||
}
|
||||
other.storage.push(last >> b);
|
||||
}
|
||||
|
||||
self.storage.truncate(w+1);
|
||||
self.fix_last_block();
|
||||
}
|
||||
|
||||
other
|
||||
}
|
||||
|
||||
/// Returns `true` if all bits are 0.
|
||||
///
|
||||
/// # Examples
|
||||
@ -1693,6 +1796,89 @@ impl BitSet {
|
||||
self.other_op(other, |w1, w2| w1 ^ w2);
|
||||
}
|
||||
|
||||
/// Moves all elements from `other` into `Self`, leaving `other` empty.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(collections, bit_set_append_split_off)]
|
||||
/// use std::collections::{BitVec, BitSet};
|
||||
///
|
||||
/// let mut a = BitSet::new();
|
||||
/// a.insert(2);
|
||||
/// a.insert(6);
|
||||
///
|
||||
/// let mut b = BitSet::new();
|
||||
/// b.insert(1);
|
||||
/// b.insert(3);
|
||||
/// b.insert(6);
|
||||
///
|
||||
/// a.append(&mut b);
|
||||
///
|
||||
/// assert_eq!(a.len(), 4);
|
||||
/// assert_eq!(b.len(), 0);
|
||||
/// assert_eq!(a, BitSet::from_bit_vec(BitVec::from_bytes(&[0b01110010])));
|
||||
/// ```
|
||||
#[unstable(feature = "bit_set_append_split_off",
|
||||
reason = "recently added as part of collections reform 2")]
|
||||
pub fn append(&mut self, other: &mut Self) {
|
||||
self.union_with(other);
|
||||
other.clear();
|
||||
}
|
||||
|
||||
/// Splits the `BitSet` into two at the given key including the key.
|
||||
/// Retains the first part in-place while returning the second part.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(collections, bit_set_append_split_off)]
|
||||
/// use std::collections::{BitSet, BitVec};
|
||||
/// let mut a = BitSet::new();
|
||||
/// a.insert(2);
|
||||
/// a.insert(6);
|
||||
/// a.insert(1);
|
||||
/// a.insert(3);
|
||||
///
|
||||
/// let b = a.split_off(3);
|
||||
///
|
||||
/// assert_eq!(a.len(), 2);
|
||||
/// assert_eq!(b.len(), 2);
|
||||
/// assert_eq!(a, BitSet::from_bit_vec(BitVec::from_bytes(&[0b01100000])));
|
||||
/// assert_eq!(b, BitSet::from_bit_vec(BitVec::from_bytes(&[0b00010010])));
|
||||
/// ```
|
||||
#[unstable(feature = "bit_set_append_split_off",
|
||||
reason = "recently added as part of collections reform 2")]
|
||||
pub fn split_off(&mut self, at: usize) -> Self {
|
||||
let mut other = BitSet::new();
|
||||
|
||||
if at == 0 {
|
||||
swap(self, &mut other);
|
||||
return other;
|
||||
} else if at >= self.bit_vec.len() {
|
||||
return other;
|
||||
}
|
||||
|
||||
// Calculate block and bit at which to split
|
||||
let w = at / u32::BITS;
|
||||
let b = at % u32::BITS;
|
||||
|
||||
// Pad `other` with `w` zero blocks,
|
||||
// append `self`'s blocks in the range from `w` to the end to `other`
|
||||
other.bit_vec.storage.extend(repeat(0u32).take(w)
|
||||
.chain(self.bit_vec.storage[w..].iter().cloned()));
|
||||
other.bit_vec.nbits = self.bit_vec.nbits;
|
||||
|
||||
if b > 0 {
|
||||
other.bit_vec.storage[w] &= !0 << b;
|
||||
}
|
||||
|
||||
// Sets `bit_vec.len()` and fixes the last block as well
|
||||
self.bit_vec.truncate(at);
|
||||
|
||||
other
|
||||
}
|
||||
|
||||
/// Returns the number of set bits in this set.
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
||||
@ -21,7 +21,7 @@ use core::ops::Deref;
|
||||
use core::option::Option;
|
||||
|
||||
use fmt;
|
||||
use alloc::{rc, arc};
|
||||
use alloc::{boxed, rc, arc};
|
||||
|
||||
use self::Cow::*;
|
||||
|
||||
@ -37,6 +37,11 @@ use self::Cow::*;
|
||||
/// trait: if `T: Borrow<U>`, then `&U` can be borrowed from `&T`. A given
|
||||
/// type can be borrowed as multiple different types. In particular, `Vec<T>:
|
||||
/// Borrow<Vec<T>>` and `Vec<T>: Borrow<[T]>`.
|
||||
///
|
||||
/// `Borrow` is very similar to, but different than, `AsRef`. See
|
||||
/// [the book][book] for more.
|
||||
///
|
||||
/// [book]: ../../book/borrow-and-asref.html
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub trait Borrow<Borrowed: ?Sized> {
|
||||
/// Immutably borrows from an owned value.
|
||||
@ -111,6 +116,14 @@ impl<'a, T: ?Sized> BorrowMut<T> for &'a mut T {
|
||||
fn borrow_mut(&mut self) -> &mut T { &mut **self }
|
||||
}
|
||||
|
||||
impl<T: ?Sized> Borrow<T> for boxed::Box<T> {
|
||||
fn borrow(&self) -> &T { &**self }
|
||||
}
|
||||
|
||||
impl<T: ?Sized> BorrowMut<T> for boxed::Box<T> {
|
||||
fn borrow_mut(&mut self) -> &mut T { &mut **self }
|
||||
}
|
||||
|
||||
impl<T> Borrow<T> for rc::Rc<T> {
|
||||
fn borrow(&self) -> &T { &**self }
|
||||
}
|
||||
|
||||
@ -270,14 +270,12 @@ impl<T> DoubleEndedIterator for RawItems<T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[unsafe_destructor]
|
||||
impl<T> Drop for RawItems<T> {
|
||||
fn drop(&mut self) {
|
||||
for _ in self.by_ref() {}
|
||||
}
|
||||
}
|
||||
|
||||
#[unsafe_destructor]
|
||||
impl<K, V> Drop for Node<K, V> {
|
||||
fn drop(&mut self) {
|
||||
if self.keys.is_null() ||
|
||||
@ -1394,7 +1392,6 @@ impl<K, V> TraversalImpl for MoveTraversalImpl<K, V> {
|
||||
}
|
||||
}
|
||||
|
||||
#[unsafe_destructor]
|
||||
impl<K, V> Drop for MoveTraversalImpl<K, V> {
|
||||
fn drop(&mut self) {
|
||||
// We need to cleanup the stored values manually, as the RawItems destructor would run
|
||||
|
||||
@ -7,8 +7,6 @@
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
//
|
||||
// ignore-lexer-test FIXME #15679
|
||||
|
||||
//! Utilities for formatting and printing strings
|
||||
//!
|
||||
@ -262,7 +260,6 @@
|
||||
//! Example usage is:
|
||||
//!
|
||||
//! ```
|
||||
//! # #![feature(old_io)]
|
||||
//! # #![allow(unused_must_use)]
|
||||
//! use std::io::Write;
|
||||
//! let mut w = Vec::new();
|
||||
@ -290,7 +287,6 @@
|
||||
//! off, some example usage is:
|
||||
//!
|
||||
//! ```
|
||||
//! # #![feature(old_io)]
|
||||
//! use std::fmt;
|
||||
//! use std::io::{self, Write};
|
||||
//!
|
||||
@ -402,7 +398,7 @@
|
||||
//! longer than this width, then it is truncated down to this many characters and only those are
|
||||
//! emitted.
|
||||
//!
|
||||
//! For integral types, this has no meaning currently.
|
||||
//! For integral types, this is ignored.
|
||||
//!
|
||||
//! For floating-point types, this indicates how many digits after the decimal point should be
|
||||
//! printed.
|
||||
@ -500,6 +496,6 @@ use string;
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn format(args: Arguments) -> string::String {
|
||||
let mut output = string::String::new();
|
||||
let _ = write!(&mut output, "{}", args);
|
||||
let _ = output.write_fmt(args);
|
||||
output
|
||||
}
|
||||
|
||||
@ -33,7 +33,6 @@
|
||||
#![feature(staged_api)]
|
||||
#![feature(unboxed_closures)]
|
||||
#![feature(unicode)]
|
||||
#![feature(unsafe_destructor)]
|
||||
#![feature(unique)]
|
||||
#![feature(unsafe_no_drop_flag, filling_drop)]
|
||||
#![feature(step_by)]
|
||||
@ -42,7 +41,8 @@
|
||||
#![feature(slice_patterns)]
|
||||
#![feature(debug_builders)]
|
||||
#![feature(utf8_error)]
|
||||
#![cfg_attr(test, feature(rand, rustc_private, test, hash, collections))]
|
||||
#![cfg_attr(test, feature(rand, rustc_private, test, hash, collections,
|
||||
collections_drain, collections_range))]
|
||||
#![cfg_attr(test, allow(deprecated))] // rand
|
||||
|
||||
#![feature(no_std)]
|
||||
@ -51,7 +51,7 @@
|
||||
#[macro_use]
|
||||
extern crate core;
|
||||
|
||||
extern crate unicode;
|
||||
extern crate rustc_unicode;
|
||||
extern crate alloc;
|
||||
|
||||
#[cfg(test)] #[macro_use] extern crate std;
|
||||
@ -82,6 +82,7 @@ pub mod borrow;
|
||||
pub mod enum_set;
|
||||
pub mod fmt;
|
||||
pub mod linked_list;
|
||||
pub mod range;
|
||||
pub mod slice;
|
||||
pub mod str;
|
||||
pub mod string;
|
||||
|
||||
@ -616,7 +616,13 @@ impl<T> LinkedList<T> {
|
||||
length: len - at
|
||||
};
|
||||
|
||||
// Swap split_node.next with list_head (which is None), nulling out split_node.next,
|
||||
// as it is the new tail.
|
||||
mem::swap(&mut split_node.resolve().unwrap().next, &mut splitted_list.list_head);
|
||||
// Null out list_head.prev. Note this `unwrap` won't fail because if at == len
|
||||
// we already branched out at the top of the fn to return the empty list.
|
||||
splitted_list.list_head.as_mut().unwrap().prev = Rawlink::none();
|
||||
// Fix the tail ptr
|
||||
self.list_tail = split_node;
|
||||
self.length = at;
|
||||
|
||||
@ -624,7 +630,6 @@ impl<T> LinkedList<T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[unsafe_destructor]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T> Drop for LinkedList<T> {
|
||||
fn drop(&mut self) {
|
||||
@ -933,7 +938,7 @@ impl<A: Hash> Hash for LinkedList<A> {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
mod tests {
|
||||
use std::clone::Clone;
|
||||
use std::iter::{Iterator, IntoIterator};
|
||||
use std::option::Option::{Some, None, self};
|
||||
@ -1083,6 +1088,26 @@ mod test {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_26021() {
|
||||
use std::iter::ExactSizeIterator;
|
||||
// There was a bug in split_off that failed to null out the RHS's head's prev ptr.
|
||||
// This caused the RHS's dtor to walk up into the LHS at drop and delete all of
|
||||
// its nodes.
|
||||
//
|
||||
// https://github.com/rust-lang/rust/issues/26021
|
||||
let mut v1 = LinkedList::new();
|
||||
v1.push_front(1u8);
|
||||
v1.push_front(1u8);
|
||||
v1.push_front(1u8);
|
||||
v1.push_front(1u8);
|
||||
let _ = v1.split_off(3); // Dropping this now should not cause laundry consumption
|
||||
assert_eq!(v1.len(), 3);
|
||||
|
||||
assert_eq!(v1.iter().len(), 3);
|
||||
assert_eq!(v1.iter().collect::<Vec<_>>().len(), 3);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
fn fuzz_test(sz: i32) {
|
||||
let mut m: LinkedList<_> = LinkedList::new();
|
||||
|
||||
45
src/libcollections/range.rs
Normal file
45
src/libcollections/range.rs
Normal file
@ -0,0 +1,45 @@
|
||||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
#![unstable(feature = "collections_range", reason = "was just added")]
|
||||
|
||||
//! Range syntax.
|
||||
|
||||
use core::option::Option::{self, None, Some};
|
||||
use core::ops::{RangeFull, Range, RangeTo, RangeFrom};
|
||||
|
||||
/// **RangeArgument** is implemented by Rust's built-in range types, produced
|
||||
/// by range syntax like `..`, `a..`, `..b` or `c..d`.
|
||||
pub trait RangeArgument<T> {
|
||||
/// Start index (inclusive)
|
||||
///
|
||||
/// Return start value if present, else `None`.
|
||||
fn start(&self) -> Option<&T> { None }
|
||||
|
||||
/// End index (exclusive)
|
||||
///
|
||||
/// Return end value if present, else `None`.
|
||||
fn end(&self) -> Option<&T> { None }
|
||||
}
|
||||
|
||||
|
||||
impl<T> RangeArgument<T> for RangeFull {}
|
||||
|
||||
impl<T> RangeArgument<T> for RangeFrom<T> {
|
||||
fn start(&self) -> Option<&T> { Some(&self.start) }
|
||||
}
|
||||
|
||||
impl<T> RangeArgument<T> for RangeTo<T> {
|
||||
fn end(&self) -> Option<&T> { Some(&self.end) }
|
||||
}
|
||||
|
||||
impl<T> RangeArgument<T> for Range<T> {
|
||||
fn start(&self) -> Option<&T> { Some(&self.start) }
|
||||
fn end(&self) -> Option<&T> { Some(&self.end) }
|
||||
}
|
||||
@ -995,39 +995,38 @@ impl<T> [T] {
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Extension traits for slices over specific kinds of data
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
#[unstable(feature = "collections", reason = "U should be an associated type")]
|
||||
#[unstable(feature = "collections", reason = "recently changed")]
|
||||
/// An extension trait for concatenating slices
|
||||
pub trait SliceConcatExt<T: ?Sized, U> {
|
||||
/// Flattens a slice of `T` into a single value `U`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// let v = vec!["hello", "world"];
|
||||
///
|
||||
/// let s: String = v.concat();
|
||||
///
|
||||
/// println!("{}", s); // prints "helloworld"
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
fn concat(&self) -> U;
|
||||
pub trait SliceConcatExt<T: ?Sized> {
|
||||
#[unstable(feature = "collections", reason = "recently changed")]
|
||||
/// The resulting type after concatenation
|
||||
type Output;
|
||||
|
||||
/// Flattens a slice of `T` into a single value `U`, placing a given separator between each.
|
||||
/// Flattens a slice of `T` into a single value `Self::Output`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// let v = vec!["hello", "world"];
|
||||
///
|
||||
/// let s: String = v.connect(" ");
|
||||
///
|
||||
/// println!("{}", s); // prints "hello world"
|
||||
/// assert_eq!(["hello", "world"].concat(), "helloworld");
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
fn connect(&self, sep: &T) -> U;
|
||||
fn concat(&self) -> Self::Output;
|
||||
|
||||
/// Flattens a slice of `T` into a single value `Self::Output`, placing a given separator
|
||||
/// between each.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// assert_eq!(["hello", "world"].connect(" "), "hello world");
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
fn connect(&self, sep: &T) -> Self::Output;
|
||||
}
|
||||
|
||||
impl<T: Clone, V: Borrow<[T]>> SliceConcatExt<T, Vec<T>> for [V] {
|
||||
impl<T: Clone, V: Borrow<[T]>> SliceConcatExt<T> for [V] {
|
||||
type Output = Vec<T>;
|
||||
|
||||
fn concat(&self) -> Vec<T> {
|
||||
let size = self.iter().fold(0, |acc, v| acc + v.borrow().len());
|
||||
let mut result = Vec::with_capacity(size);
|
||||
|
||||
@ -7,8 +7,6 @@
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
//
|
||||
// ignore-lexer-test FIXME #15679
|
||||
|
||||
//! Unicode string manipulation (the `str` type).
|
||||
//!
|
||||
@ -59,12 +57,12 @@ use core::result::Result;
|
||||
use core::str as core_str;
|
||||
use core::str::pattern::Pattern;
|
||||
use core::str::pattern::{Searcher, ReverseSearcher, DoubleEndedSearcher};
|
||||
use unicode::str::{UnicodeStr, Utf16Encoder};
|
||||
use rustc_unicode::str::{UnicodeStr, Utf16Encoder};
|
||||
|
||||
use vec_deque::VecDeque;
|
||||
use borrow::{Borrow, ToOwned};
|
||||
use string::String;
|
||||
use unicode;
|
||||
use rustc_unicode;
|
||||
use vec::Vec;
|
||||
use slice::SliceConcatExt;
|
||||
|
||||
@ -77,14 +75,16 @@ pub use core::str::{Matches, RMatches};
|
||||
pub use core::str::{MatchIndices, RMatchIndices};
|
||||
pub use core::str::{from_utf8, Chars, CharIndices, Bytes};
|
||||
pub use core::str::{from_utf8_unchecked, ParseBoolError};
|
||||
pub use unicode::str::{Words, Graphemes, GraphemeIndices};
|
||||
pub use rustc_unicode::str::{SplitWhitespace, Words, Graphemes, GraphemeIndices};
|
||||
pub use core::str::pattern;
|
||||
|
||||
/*
|
||||
Section: Creating a string
|
||||
*/
|
||||
|
||||
impl<S: Borrow<str>> SliceConcatExt<str, String> for [S] {
|
||||
impl<S: Borrow<str>> SliceConcatExt<str> for [S] {
|
||||
type Output = String;
|
||||
|
||||
fn concat(&self) -> String {
|
||||
if self.is_empty() {
|
||||
return String::new();
|
||||
@ -160,6 +160,9 @@ enum DecompositionType {
|
||||
/// External iterator for a string decomposition's characters.
|
||||
///
|
||||
/// For use with the `std::iter` module.
|
||||
#[allow(deprecated)]
|
||||
#[deprecated(reason = "use the crates.io `unicode-normalization` library instead",
|
||||
since = "1.0.0")]
|
||||
#[derive(Clone)]
|
||||
#[unstable(feature = "unicode",
|
||||
reason = "this functionality may be replaced with a more generic \
|
||||
@ -171,6 +174,7 @@ pub struct Decompositions<'a> {
|
||||
sorted: bool
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a> Iterator for Decompositions<'a> {
|
||||
type Item = char;
|
||||
@ -197,7 +201,7 @@ impl<'a> Iterator for Decompositions<'a> {
|
||||
{
|
||||
let callback = |d| {
|
||||
let class =
|
||||
unicode::char::canonical_combining_class(d);
|
||||
rustc_unicode::char::canonical_combining_class(d);
|
||||
if class == 0 && !*sorted {
|
||||
canonical_sort(buffer);
|
||||
*sorted = true;
|
||||
@ -206,10 +210,10 @@ impl<'a> Iterator for Decompositions<'a> {
|
||||
};
|
||||
match self.kind {
|
||||
Canonical => {
|
||||
unicode::char::decompose_canonical(ch, callback)
|
||||
rustc_unicode::char::decompose_canonical(ch, callback)
|
||||
}
|
||||
Compatible => {
|
||||
unicode::char::decompose_compatible(ch, callback)
|
||||
rustc_unicode::char::decompose_compatible(ch, callback)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -253,6 +257,9 @@ enum RecompositionState {
|
||||
/// External iterator for a string recomposition's characters.
|
||||
///
|
||||
/// For use with the `std::iter` module.
|
||||
#[allow(deprecated)]
|
||||
#[deprecated(reason = "use the crates.io `unicode-normalization` library instead",
|
||||
since = "1.0.0")]
|
||||
#[derive(Clone)]
|
||||
#[unstable(feature = "unicode",
|
||||
reason = "this functionality may be replaced with a more generic \
|
||||
@ -265,6 +272,7 @@ pub struct Recompositions<'a> {
|
||||
last_ccc: Option<u8>
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a> Iterator for Recompositions<'a> {
|
||||
type Item = char;
|
||||
@ -275,7 +283,7 @@ impl<'a> Iterator for Recompositions<'a> {
|
||||
match self.state {
|
||||
Composing => {
|
||||
for ch in self.iter.by_ref() {
|
||||
let ch_class = unicode::char::canonical_combining_class(ch);
|
||||
let ch_class = rustc_unicode::char::canonical_combining_class(ch);
|
||||
if self.composee.is_none() {
|
||||
if ch_class != 0 {
|
||||
return Some(ch);
|
||||
@ -287,7 +295,7 @@ impl<'a> Iterator for Recompositions<'a> {
|
||||
|
||||
match self.last_ccc {
|
||||
None => {
|
||||
match unicode::char::compose(k, ch) {
|
||||
match rustc_unicode::char::compose(k, ch) {
|
||||
Some(r) => {
|
||||
self.composee = Some(r);
|
||||
continue;
|
||||
@ -315,7 +323,7 @@ impl<'a> Iterator for Recompositions<'a> {
|
||||
self.last_ccc = Some(ch_class);
|
||||
continue;
|
||||
}
|
||||
match unicode::char::compose(k, ch) {
|
||||
match rustc_unicode::char::compose(k, ch) {
|
||||
Some(r) => {
|
||||
self.composee = Some(r);
|
||||
continue;
|
||||
@ -388,6 +396,7 @@ macro_rules! utf8_acc_cont_byte {
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl Borrow<str> for String {
|
||||
#[inline]
|
||||
fn borrow(&self) -> &str { &self[..] }
|
||||
}
|
||||
|
||||
@ -464,6 +473,9 @@ impl str {
|
||||
|
||||
/// Returns an iterator over the string in Unicode Normalization Form D
|
||||
/// (canonical decomposition).
|
||||
#[allow(deprecated)]
|
||||
#[deprecated(reason = "use the crates.io `unicode-normalization` library instead",
|
||||
since = "1.0.0")]
|
||||
#[inline]
|
||||
#[unstable(feature = "unicode",
|
||||
reason = "this functionality may be replaced with a more generic \
|
||||
@ -479,6 +491,9 @@ impl str {
|
||||
|
||||
/// Returns an iterator over the string in Unicode Normalization Form KD
|
||||
/// (compatibility decomposition).
|
||||
#[allow(deprecated)]
|
||||
#[deprecated(reason = "use the crates.io `unicode-normalization` library instead",
|
||||
since = "1.0.0")]
|
||||
#[inline]
|
||||
#[unstable(feature = "unicode",
|
||||
reason = "this functionality may be replaced with a more generic \
|
||||
@ -494,6 +509,9 @@ impl str {
|
||||
|
||||
/// An Iterator over the string in Unicode Normalization Form C
|
||||
/// (canonical decomposition followed by canonical composition).
|
||||
#[allow(deprecated)]
|
||||
#[deprecated(reason = "use the crates.io `unicode-normalization` library instead",
|
||||
since = "1.0.0")]
|
||||
#[inline]
|
||||
#[unstable(feature = "unicode",
|
||||
reason = "this functionality may be replaced with a more generic \
|
||||
@ -510,6 +528,9 @@ impl str {
|
||||
|
||||
/// An Iterator over the string in Unicode Normalization Form KC
|
||||
/// (compatibility decomposition followed by canonical composition).
|
||||
#[allow(deprecated)]
|
||||
#[deprecated(reason = "use the crates.io `unicode-normalization` library instead",
|
||||
since = "1.0.0")]
|
||||
#[inline]
|
||||
#[unstable(feature = "unicode",
|
||||
reason = "this functionality may be replaced with a more generic \
|
||||
@ -694,7 +715,7 @@ impl str {
|
||||
/// is skipped if empty.
|
||||
///
|
||||
/// This method can be used for string data that is _terminated_,
|
||||
/// rather than _seperated_ by a pattern.
|
||||
/// rather than _separated_ by a pattern.
|
||||
///
|
||||
/// # Iterator behavior
|
||||
///
|
||||
@ -741,7 +762,7 @@ impl str {
|
||||
/// skipped if empty.
|
||||
///
|
||||
/// This method can be used for string data that is _terminated_,
|
||||
/// rather than _seperated_ by a pattern.
|
||||
/// rather than _separated_ by a pattern.
|
||||
///
|
||||
/// # Iterator behavior
|
||||
///
|
||||
@ -1689,6 +1710,8 @@ impl str {
|
||||
///
|
||||
/// assert_eq!(&gr2[..], b);
|
||||
/// ```
|
||||
#[deprecated(reason = "use the crates.io `unicode-segmentation` library instead",
|
||||
since = "1.0.0")]
|
||||
#[unstable(feature = "unicode",
|
||||
reason = "this functionality may only be provided by libunicode")]
|
||||
pub fn graphemes(&self, is_extended: bool) -> Graphemes {
|
||||
@ -1708,33 +1731,52 @@ impl str {
|
||||
///
|
||||
/// assert_eq!(&gr_inds[..], b);
|
||||
/// ```
|
||||
#[deprecated(reason = "use the crates.io `unicode-segmentation` library instead",
|
||||
since = "1.0.0")]
|
||||
#[unstable(feature = "unicode",
|
||||
reason = "this functionality may only be provided by libunicode")]
|
||||
pub fn grapheme_indices(&self, is_extended: bool) -> GraphemeIndices {
|
||||
UnicodeStr::grapheme_indices(&self[..], is_extended)
|
||||
}
|
||||
|
||||
/// An iterator over the non-empty words of `self`.
|
||||
///
|
||||
/// A 'word' is a subsequence separated by any sequence of whitespace.
|
||||
/// Sequences of whitespace
|
||||
/// are collapsed, so empty "words" are not included.
|
||||
/// An iterator over the non-empty substrings of `self` which contain no whitespace,
|
||||
/// and which are separated by any amount of whitespace.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(str_words)]
|
||||
/// # #![allow(deprecated)]
|
||||
/// let some_words = " Mary had\ta little \n\t lamb";
|
||||
/// let v: Vec<&str> = some_words.words().collect();
|
||||
///
|
||||
/// assert_eq!(v, ["Mary", "had", "a", "little", "lamb"]);
|
||||
/// ```
|
||||
#[deprecated(reason = "words() will be removed. Use split_whitespace() instead",
|
||||
since = "1.1.0")]
|
||||
#[unstable(feature = "str_words",
|
||||
reason = "the precise algorithm to use is unclear")]
|
||||
#[allow(deprecated)]
|
||||
pub fn words(&self) -> Words {
|
||||
UnicodeStr::words(&self[..])
|
||||
}
|
||||
|
||||
/// An iterator over the non-empty substrings of `self` which contain no whitespace,
|
||||
/// and which are separated by any amount of whitespace.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// let some_words = " Mary had\ta little \n\t lamb";
|
||||
/// let v: Vec<&str> = some_words.split_whitespace().collect();
|
||||
///
|
||||
/// assert_eq!(v, ["Mary", "had", "a", "little", "lamb"]);
|
||||
/// ```
|
||||
#[stable(feature = "split_whitespace", since = "1.1.0")]
|
||||
pub fn split_whitespace(&self) -> SplitWhitespace {
|
||||
UnicodeStr::split_whitespace(&self[..])
|
||||
}
|
||||
|
||||
/// Returns a string's displayed width in columns.
|
||||
///
|
||||
/// Control characters have zero width.
|
||||
@ -1748,6 +1790,8 @@ impl str {
|
||||
/// recommends that these
|
||||
/// characters be treated as 1 column (i.e., `is_cjk = false`) if the
|
||||
/// locale is unknown.
|
||||
#[deprecated(reason = "use the crates.io `unicode-width` library instead",
|
||||
since = "1.0.0")]
|
||||
#[unstable(feature = "unicode",
|
||||
reason = "this functionality may only be provided by libunicode")]
|
||||
pub fn width(&self, is_cjk: bool) -> usize {
|
||||
|
||||
@ -7,8 +7,6 @@
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
//
|
||||
// ignore-lexer-test FIXME #15679
|
||||
|
||||
//! An owned, growable string that enforces that its contents are valid UTF-8.
|
||||
|
||||
@ -24,11 +22,12 @@ use core::ops::{self, Deref, Add, Index};
|
||||
use core::ptr;
|
||||
use core::slice;
|
||||
use core::str::pattern::Pattern;
|
||||
use unicode::str as unicode_str;
|
||||
use unicode::str::Utf16Item;
|
||||
use rustc_unicode::str as unicode_str;
|
||||
use rustc_unicode::str::Utf16Item;
|
||||
|
||||
use borrow::{Cow, IntoCow};
|
||||
use str::{self, FromStr, Utf8Error};
|
||||
use range::RangeArgument;
|
||||
use str::{self, FromStr, Utf8Error, Chars};
|
||||
use vec::{DerefVec, Vec, as_vec};
|
||||
|
||||
/// A growable string stored as a UTF-8 encoded buffer.
|
||||
@ -697,6 +696,59 @@ impl String {
|
||||
pub fn clear(&mut self) {
|
||||
self.vec.clear()
|
||||
}
|
||||
|
||||
/// Create a draining iterator that removes the specified range in the string
|
||||
/// and yields the removed chars from start to end. The element range is
|
||||
/// removed even if the iterator is not consumed until the end.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the starting point or end point are not on character boundaries,
|
||||
/// or if they are out of bounds.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(collections_drain)]
|
||||
///
|
||||
/// let mut s = String::from("α is alpha, β is beta");
|
||||
/// let beta_offset = s.find('β').unwrap_or(s.len());
|
||||
///
|
||||
/// // Remove the range up until the β from the string
|
||||
/// let t: String = s.drain(..beta_offset).collect();
|
||||
/// assert_eq!(t, "α is alpha, ");
|
||||
/// assert_eq!(s, "β is beta");
|
||||
///
|
||||
/// // A full range clears the string
|
||||
/// s.drain(..);
|
||||
/// assert_eq!(s, "");
|
||||
/// ```
|
||||
#[unstable(feature = "collections_drain",
|
||||
reason = "recently added, matches RFC")]
|
||||
pub fn drain<R>(&mut self, range: R) -> Drain where R: RangeArgument<usize> {
|
||||
// Memory safety
|
||||
//
|
||||
// The String version of Drain does not have the memory safety issues
|
||||
// of the vector version. The data is just plain bytes.
|
||||
// Because the range removal happens in Drop, if the Drain iterator is leaked,
|
||||
// the removal will not happen.
|
||||
let len = self.len();
|
||||
let start = *range.start().unwrap_or(&0);
|
||||
let end = *range.end().unwrap_or(&len);
|
||||
|
||||
// Take out two simultaneous borrows. The &mut String won't be accessed
|
||||
// until iteration is over, in Drop.
|
||||
let self_ptr = self as *mut _;
|
||||
// slicing does the appropriate bounds checks
|
||||
let chars_iter = self[start..end].chars();
|
||||
|
||||
Drain {
|
||||
start: start,
|
||||
end: end,
|
||||
iter: chars_iter,
|
||||
string: self_ptr,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromUtf8Error {
|
||||
@ -705,7 +757,7 @@ impl FromUtf8Error {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn into_bytes(self) -> Vec<u8> { self.bytes }
|
||||
|
||||
/// Accesss the underlying UTF8-error that was the cause of this error.
|
||||
/// Access the underlying UTF8-error that was the cause of this error.
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn utf8_error(&self) -> Utf8Error { self.error }
|
||||
}
|
||||
@ -1000,6 +1052,7 @@ impl<T: fmt::Display + ?Sized> ToString for T {
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl AsRef<str> for String {
|
||||
#[inline]
|
||||
fn as_ref(&self) -> &str {
|
||||
self
|
||||
}
|
||||
@ -1015,9 +1068,20 @@ impl AsRef<[u8]> for String {
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a> From<&'a str> for String {
|
||||
#[cfg(not(test))]
|
||||
#[inline]
|
||||
fn from(s: &'a str) -> String {
|
||||
s.to_string()
|
||||
String { vec: <[_]>::to_vec(s.as_bytes()) }
|
||||
}
|
||||
|
||||
// HACK(japaric): with cfg(test) the inherent `[T]::to_vec` method, which is
|
||||
// required for this method definition, is not available. Since we don't
|
||||
// require this method for testing purposes, I'll just stub it
|
||||
// NB see the slice::hack module in slice.rs for more information
|
||||
#[inline]
|
||||
#[cfg(test)]
|
||||
fn from(_: &str) -> String {
|
||||
panic!("not available with cfg(test)");
|
||||
}
|
||||
}
|
||||
|
||||
@ -1067,4 +1131,62 @@ impl fmt::Write for String {
|
||||
self.push_str(s);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn write_char(&mut self, c: char) -> fmt::Result {
|
||||
self.push(c);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// A draining iterator for `String`.
|
||||
#[unstable(feature = "collections_drain", reason = "recently added")]
|
||||
pub struct Drain<'a> {
|
||||
/// Will be used as &'a mut String in the destructor
|
||||
string: *mut String,
|
||||
/// Start of part to remove
|
||||
start: usize,
|
||||
/// End of part to remove
|
||||
end: usize,
|
||||
/// Current remaining range to remove
|
||||
iter: Chars<'a>,
|
||||
}
|
||||
|
||||
unsafe impl<'a> Sync for Drain<'a> {}
|
||||
unsafe impl<'a> Send for Drain<'a> {}
|
||||
|
||||
#[unstable(feature = "collections_drain", reason = "recently added")]
|
||||
impl<'a> Drop for Drain<'a> {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
// Use Vec::drain. "Reaffirm" the bounds checks to avoid
|
||||
// panic code being inserted again.
|
||||
let self_vec = (*self.string).as_mut_vec();
|
||||
if self.start <= self.end && self.end <= self_vec.len() {
|
||||
self_vec.drain(self.start..self.end);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "collections_drain", reason = "recently added")]
|
||||
impl<'a> Iterator for Drain<'a> {
|
||||
type Item = char;
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<char> {
|
||||
self.iter.next()
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
self.iter.size_hint()
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "collections_drain", reason = "recently added")]
|
||||
impl<'a> DoubleEndedIterator for Drain<'a> {
|
||||
#[inline]
|
||||
fn next_back(&mut self) -> Option<char> {
|
||||
self.iter.next_back()
|
||||
}
|
||||
}
|
||||
|
||||
@ -15,34 +15,44 @@
|
||||
//!
|
||||
//! # Examples
|
||||
//!
|
||||
//! Explicitly creating a `Vec<T>` with `new()`:
|
||||
//! You can explicitly create a `Vec<T>` with `new()`:
|
||||
//!
|
||||
//! ```
|
||||
//! let xs: Vec<i32> = Vec::new();
|
||||
//! let v: Vec<i32> = Vec::new();
|
||||
//! ```
|
||||
//!
|
||||
//! Using the `vec!` macro:
|
||||
//! ...or by using the `vec!` macro:
|
||||
//!
|
||||
//! ```
|
||||
//! let ys: Vec<i32> = vec![];
|
||||
//! let v: Vec<i32> = vec![];
|
||||
//!
|
||||
//! let zs = vec![1i32, 2, 3, 4, 5];
|
||||
//! let v = vec![1, 2, 3, 4, 5];
|
||||
//!
|
||||
//! let v = vec![0; 10]; // ten zeroes
|
||||
//! ```
|
||||
//!
|
||||
//! Push:
|
||||
//! You can `push` values onto the end of a vector (which will grow the vector as needed):
|
||||
//!
|
||||
//! ```
|
||||
//! let mut xs = vec![1i32, 2];
|
||||
//! let mut v = vec![1, 2];
|
||||
//!
|
||||
//! xs.push(3);
|
||||
//! v.push(3);
|
||||
//! ```
|
||||
//!
|
||||
//! And pop:
|
||||
//! Popping values works in much the same way:
|
||||
//!
|
||||
//! ```
|
||||
//! let mut xs = vec![1i32, 2];
|
||||
//! let mut v = vec![1, 2];
|
||||
//!
|
||||
//! let two = xs.pop();
|
||||
//! let two = v.pop();
|
||||
//! ```
|
||||
//!
|
||||
//! 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;
|
||||
//! ```
|
||||
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
@ -69,6 +79,8 @@ use core::usize;
|
||||
|
||||
use borrow::{Cow, IntoCow};
|
||||
|
||||
use super::range::RangeArgument;
|
||||
|
||||
// FIXME- fix places which assume the max vector allowed has memory usize::MAX.
|
||||
static MAX_MEMORY_SIZE: usize = isize::MAX as usize;
|
||||
|
||||
@ -714,36 +726,61 @@ impl<T> Vec<T> {
|
||||
unsafe { other.set_len(0); }
|
||||
}
|
||||
|
||||
/// Creates a draining iterator that clears the `Vec` and iterates over
|
||||
/// the removed items from start to end.
|
||||
/// Create a draining iterator that removes the specified range in the vector
|
||||
/// and yields the removed items from start to end. The element range is
|
||||
/// removed even if the iterator is not consumed until the end.
|
||||
///
|
||||
/// Note: It is unspecified how many elements are removed from the vector,
|
||||
/// if the `Drain` value is leaked.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the starting point is greater than the end point or if
|
||||
/// the end point is greater than the length of the vector.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(collections)]
|
||||
/// let mut v = vec!["a".to_string(), "b".to_string()];
|
||||
/// for s in v.drain() {
|
||||
/// // s has type String, not &String
|
||||
/// println!("{}", s);
|
||||
/// }
|
||||
/// assert!(v.is_empty());
|
||||
/// # #![feature(collections_drain, collections_range)]
|
||||
///
|
||||
/// // Draining using `..` clears the whole vector.
|
||||
/// let mut v = vec![1, 2, 3];
|
||||
/// let u: Vec<_> = v.drain(..).collect();
|
||||
/// assert_eq!(v, &[]);
|
||||
/// assert_eq!(u, &[1, 2, 3]);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "collections",
|
||||
reason = "matches collection reform specification, waiting for dust to settle")]
|
||||
pub fn drain(&mut self) -> Drain<T> {
|
||||
#[unstable(feature = "collections_drain",
|
||||
reason = "recently added, matches RFC")]
|
||||
pub fn drain<R>(&mut self, range: R) -> Drain<T> where R: RangeArgument<usize> {
|
||||
// Memory safety
|
||||
//
|
||||
// When the Drain is first created, it shortens the length of
|
||||
// the source vector to make sure no uninitalized or moved-from elements
|
||||
// are accessible at all if the Drain's destructor never gets to run.
|
||||
//
|
||||
// Drain will ptr::read out the values to remove.
|
||||
// When finished, remaining tail of the vec is copied back to cover
|
||||
// the hole, and the vector length is restored to the new length.
|
||||
//
|
||||
let len = self.len();
|
||||
let start = *range.start().unwrap_or(&0);
|
||||
let end = *range.end().unwrap_or(&len);
|
||||
assert!(start <= end);
|
||||
assert!(end <= len);
|
||||
|
||||
unsafe {
|
||||
let begin = *self.ptr as *const T;
|
||||
let end = if mem::size_of::<T>() == 0 {
|
||||
(*self.ptr as usize + self.len()) as *const T
|
||||
} else {
|
||||
(*self.ptr).offset(self.len() as isize) as *const T
|
||||
};
|
||||
self.set_len(0);
|
||||
// set self.vec length's to start, to be safe in case Drain is leaked
|
||||
self.set_len(start);
|
||||
// Use the borrow in the IterMut to indicate borrowing behavior of the
|
||||
// whole Drain iterator (like &mut T).
|
||||
let range_slice = slice::from_raw_parts_mut(
|
||||
self.as_mut_ptr().offset(start as isize),
|
||||
end - start);
|
||||
Drain {
|
||||
ptr: begin,
|
||||
end: end,
|
||||
marker: PhantomData,
|
||||
tail_start: end,
|
||||
tail_len: len - end,
|
||||
iter: range_slice.iter_mut(),
|
||||
vec: self as *mut _,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1587,7 +1624,6 @@ impl<T: Ord> Ord for Vec<T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[unsafe_destructor]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T> Drop for Vec<T> {
|
||||
fn drop(&mut self) {
|
||||
@ -1740,6 +1776,11 @@ impl<T> Iterator for IntoIter<T> {
|
||||
let exact = diff / (if size == 0 {1} else {size});
|
||||
(exact, Some(exact))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn count(self) -> usize {
|
||||
self.size_hint().0
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
@ -1769,7 +1810,6 @@ impl<T> DoubleEndedIterator for IntoIter<T> {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T> ExactSizeIterator for IntoIter<T> {}
|
||||
|
||||
#[unsafe_destructor]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T> Drop for IntoIter<T> {
|
||||
fn drop(&mut self) {
|
||||
@ -1783,14 +1823,16 @@ impl<T> Drop for IntoIter<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// An iterator that drains a vector.
|
||||
#[unsafe_no_drop_flag]
|
||||
#[unstable(feature = "collections",
|
||||
reason = "recently added as part of collections reform 2")]
|
||||
pub struct Drain<'a, T:'a> {
|
||||
ptr: *const T,
|
||||
end: *const T,
|
||||
marker: PhantomData<&'a T>,
|
||||
/// A draining iterator for `Vec<T>`.
|
||||
#[unstable(feature = "collections_drain", reason = "recently added")]
|
||||
pub struct Drain<'a, T: 'a> {
|
||||
/// Index of tail to preserve
|
||||
tail_start: usize,
|
||||
/// Length of tail
|
||||
tail_len: usize,
|
||||
/// Current remaining range to remove
|
||||
iter: slice::IterMut<'a, T>,
|
||||
vec: *mut Vec<T>,
|
||||
}
|
||||
|
||||
unsafe impl<'a, T: Sync> Sync for Drain<'a, T> {}
|
||||
@ -1802,34 +1844,15 @@ impl<'a, T> Iterator for Drain<'a, T> {
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<T> {
|
||||
unsafe {
|
||||
if self.ptr == self.end {
|
||||
None
|
||||
} else {
|
||||
if mem::size_of::<T>() == 0 {
|
||||
// purposefully don't use 'ptr.offset' because for
|
||||
// vectors with 0-size elements this would return the
|
||||
// same pointer.
|
||||
self.ptr = mem::transmute(self.ptr as usize + 1);
|
||||
|
||||
// Use a non-null pointer value
|
||||
Some(ptr::read(EMPTY as *mut T))
|
||||
} else {
|
||||
let old = self.ptr;
|
||||
self.ptr = self.ptr.offset(1);
|
||||
|
||||
Some(ptr::read(old))
|
||||
}
|
||||
self.iter.next().map(|elt|
|
||||
unsafe {
|
||||
ptr::read(elt as *const _)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
let diff = (self.end as usize) - (self.ptr as usize);
|
||||
let size = mem::size_of::<T>();
|
||||
let exact = diff / (if size == 0 {1} else {size});
|
||||
(exact, Some(exact))
|
||||
self.iter.size_hint()
|
||||
}
|
||||
}
|
||||
|
||||
@ -1837,41 +1860,39 @@ impl<'a, T> Iterator for Drain<'a, T> {
|
||||
impl<'a, T> DoubleEndedIterator for Drain<'a, T> {
|
||||
#[inline]
|
||||
fn next_back(&mut self) -> Option<T> {
|
||||
unsafe {
|
||||
if self.end == self.ptr {
|
||||
None
|
||||
} else {
|
||||
if mem::size_of::<T>() == 0 {
|
||||
// See above for why 'ptr.offset' isn't used
|
||||
self.end = mem::transmute(self.end as usize - 1);
|
||||
self.iter.next_back().map(|elt|
|
||||
unsafe {
|
||||
ptr::read(elt as *const _)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Use a non-null pointer value
|
||||
Some(ptr::read(EMPTY as *mut T))
|
||||
} else {
|
||||
self.end = self.end.offset(-1);
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a, T> Drop for Drain<'a, T> {
|
||||
fn drop(&mut self) {
|
||||
// exhaust self first
|
||||
while let Some(_) = self.next() { }
|
||||
|
||||
Some(ptr::read(self.end))
|
||||
}
|
||||
if self.tail_len > 0 {
|
||||
unsafe {
|
||||
let source_vec = &mut *self.vec;
|
||||
// memmove back untouched tail, update to new length
|
||||
let start = source_vec.len();
|
||||
let tail = self.tail_start;
|
||||
let src = source_vec.as_ptr().offset(tail as isize);
|
||||
let dst = source_vec.as_mut_ptr().offset(start as isize);
|
||||
ptr::copy(src, dst, self.tail_len);
|
||||
source_vec.set_len(start + self.tail_len);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a, T> ExactSizeIterator for Drain<'a, T> {}
|
||||
|
||||
#[unsafe_destructor]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a, T> Drop for Drain<'a, T> {
|
||||
fn drop(&mut self) {
|
||||
// self.ptr == self.end == mem::POST_DROP_USIZE if drop has already been called,
|
||||
// so we can use #[unsafe_no_drop_flag].
|
||||
|
||||
// destroy the remaining elements
|
||||
for _x in self.by_ref() {}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Conversion from &[T] to &Vec<T>
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@ -1893,7 +1914,6 @@ impl<'a, T> Deref for DerefVec<'a, T> {
|
||||
}
|
||||
|
||||
// Prevent the inner `Vec<T>` from attempting to deallocate memory.
|
||||
#[unsafe_destructor]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a, T> Drop for DerefVec<'a, T> {
|
||||
fn drop(&mut self) {
|
||||
@ -1962,7 +1982,6 @@ struct PartialVecZeroSized<T,U> {
|
||||
marker: PhantomData<::core::cell::Cell<(T,U)>>,
|
||||
}
|
||||
|
||||
#[unsafe_destructor]
|
||||
impl<T,U> Drop for PartialVecNonZeroSized<T,U> {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
@ -1988,7 +2007,6 @@ impl<T,U> Drop for PartialVecNonZeroSized<T,U> {
|
||||
}
|
||||
}
|
||||
|
||||
#[unsafe_destructor]
|
||||
impl<T,U> Drop for PartialVecZeroSized<T,U> {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
|
||||
@ -59,7 +59,6 @@ impl<T: Clone> Clone for VecDeque<T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[unsafe_destructor]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T> Drop for VecDeque<T> {
|
||||
fn drop(&mut self) {
|
||||
@ -1396,6 +1395,42 @@ impl<T> VecDeque<T> {
|
||||
// naive impl
|
||||
self.extend(other.drain());
|
||||
}
|
||||
|
||||
/// Retains only the elements specified by the predicate.
|
||||
///
|
||||
/// 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.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(vec_deque_retain)]
|
||||
/// use std::collections::VecDeque;
|
||||
///
|
||||
/// let mut buf = VecDeque::new();
|
||||
/// buf.extend(1..5);
|
||||
/// buf.retain(|&x| x%2 == 0);
|
||||
///
|
||||
/// let v: Vec<_> = buf.into_iter().collect();
|
||||
/// assert_eq!(&v[..], &[2, 4]);
|
||||
/// ```
|
||||
#[unstable(feature = "vec_deque_retain",
|
||||
reason = "new API, waiting for dust to settle")]
|
||||
pub fn retain<F>(&mut self, mut f: F) where F: FnMut(&T) -> bool {
|
||||
let len = self.len();
|
||||
let mut del = 0;
|
||||
for i in 0..len {
|
||||
if !f(&self[i]) {
|
||||
del += 1;
|
||||
} else if del > 0 {
|
||||
self.swap(i-del, i);
|
||||
}
|
||||
}
|
||||
if del > 0 {
|
||||
self.truncate(len - del);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Clone> VecDeque<T> {
|
||||
@ -1612,7 +1647,6 @@ pub struct Drain<'a, T: 'a> {
|
||||
inner: &'a mut VecDeque<T>,
|
||||
}
|
||||
|
||||
#[unsafe_destructor]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a, T: 'a> Drop for Drain<'a, T> {
|
||||
fn drop(&mut self) {
|
||||
@ -1772,7 +1806,7 @@ impl<T: fmt::Debug> fmt::Debug for VecDeque<T> {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
mod tests {
|
||||
use core::iter::{Iterator, self};
|
||||
use core::option::Option::Some;
|
||||
|
||||
|
||||
@ -367,7 +367,7 @@ impl<V> VecMap<V> {
|
||||
// Move all elements to other
|
||||
swap(self, &mut other);
|
||||
return other
|
||||
} else if at > self.v.len() {
|
||||
} else if at >= self.v.len() {
|
||||
// No elements to copy
|
||||
return other;
|
||||
}
|
||||
@ -418,7 +418,7 @@ impl<V> VecMap<V> {
|
||||
}
|
||||
let filter: fn((usize, Option<V>)) -> Option<(usize, V)> = filter; // coerce to fn ptr
|
||||
|
||||
Drain { iter: self.v.drain().enumerate().filter_map(filter) }
|
||||
Drain { iter: self.v.drain(..).enumerate().filter_map(filter) }
|
||||
}
|
||||
|
||||
/// Returns the number of elements in the map.
|
||||
|
||||
@ -387,6 +387,67 @@ fn test_bit_vec_clone() {
|
||||
assert!(b.contains(&1000));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bit_set_append() {
|
||||
let mut a = BitSet::new();
|
||||
a.insert(2);
|
||||
a.insert(6);
|
||||
|
||||
let mut b = BitSet::new();
|
||||
b.insert(1);
|
||||
b.insert(3);
|
||||
b.insert(6);
|
||||
|
||||
a.append(&mut b);
|
||||
|
||||
assert_eq!(a.len(), 4);
|
||||
assert_eq!(b.len(), 0);
|
||||
assert!(b.capacity() >= 6);
|
||||
|
||||
assert_eq!(a, BitSet::from_bit_vec(BitVec::from_bytes(&[0b01110010])));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bit_set_split_off() {
|
||||
// Split at 0
|
||||
let mut a = BitSet::from_bit_vec(BitVec::from_bytes(&[0b10100000, 0b00010010, 0b10010010,
|
||||
0b00110011, 0b01101011, 0b10101101]));
|
||||
|
||||
let b = a.split_off(0);
|
||||
|
||||
assert_eq!(a.len(), 0);
|
||||
assert_eq!(b.len(), 21);
|
||||
|
||||
assert_eq!(b, BitSet::from_bit_vec(BitVec::from_bytes(&[0b10100000, 0b00010010, 0b10010010,
|
||||
0b00110011, 0b01101011, 0b10101101])));
|
||||
|
||||
// Split behind last element
|
||||
let mut a = BitSet::from_bit_vec(BitVec::from_bytes(&[0b10100000, 0b00010010, 0b10010010,
|
||||
0b00110011, 0b01101011, 0b10101101]));
|
||||
|
||||
let b = a.split_off(50);
|
||||
|
||||
assert_eq!(a.len(), 21);
|
||||
assert_eq!(b.len(), 0);
|
||||
|
||||
assert_eq!(a, BitSet::from_bit_vec(BitVec::from_bytes(&[0b10100000, 0b00010010, 0b10010010,
|
||||
0b00110011, 0b01101011, 0b10101101])));
|
||||
|
||||
// Split at arbitrary element
|
||||
let mut a = BitSet::from_bit_vec(BitVec::from_bytes(&[0b10100000, 0b00010010, 0b10010010,
|
||||
0b00110011, 0b01101011, 0b10101101]));
|
||||
|
||||
let b = a.split_off(34);
|
||||
|
||||
assert_eq!(a.len(), 12);
|
||||
assert_eq!(b.len(), 9);
|
||||
|
||||
assert_eq!(a, BitSet::from_bit_vec(BitVec::from_bytes(&[0b10100000, 0b00010010, 0b10010010,
|
||||
0b00110011, 0b01000000])));
|
||||
assert_eq!(b, BitSet::from_bit_vec(BitVec::from_bytes(&[0, 0, 0, 0,
|
||||
0b00101011, 0b10101101])));
|
||||
}
|
||||
|
||||
mod bench {
|
||||
use std::collections::{BitSet, BitVec};
|
||||
use std::__rand::{Rng, thread_rng, ThreadRng};
|
||||
|
||||
@ -630,6 +630,141 @@ fn test_bit_vec_extend() {
|
||||
0b01001001, 0b10010010, 0b10111101]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bit_vec_append() {
|
||||
// Append to BitVec that holds a multiple of u32::BITS bits
|
||||
let mut a = BitVec::from_bytes(&[0b10100000, 0b00010010, 0b10010010, 0b00110011]);
|
||||
let mut b = BitVec::new();
|
||||
b.push(false);
|
||||
b.push(true);
|
||||
b.push(true);
|
||||
|
||||
a.append(&mut b);
|
||||
|
||||
assert_eq!(a.len(), 35);
|
||||
assert_eq!(b.len(), 0);
|
||||
assert!(b.capacity() >= 3);
|
||||
|
||||
assert!(a.eq_vec(&[true, false, true, false, false, false, false, false,
|
||||
false, false, false, true, false, false, true, false,
|
||||
true, false, false, true, false, false, true, false,
|
||||
false, false, true, true, false, false, true, true,
|
||||
false, true, true]));
|
||||
|
||||
// Append to arbitrary BitVec
|
||||
let mut a = BitVec::new();
|
||||
a.push(true);
|
||||
a.push(false);
|
||||
|
||||
let mut b = BitVec::from_bytes(&[0b10100000, 0b00010010, 0b10010010, 0b00110011, 0b10010101]);
|
||||
|
||||
a.append(&mut b);
|
||||
|
||||
assert_eq!(a.len(), 42);
|
||||
assert_eq!(b.len(), 0);
|
||||
assert!(b.capacity() >= 40);
|
||||
|
||||
assert!(a.eq_vec(&[true, false, true, false, true, false, false, false,
|
||||
false, false, false, false, false, true, false, false,
|
||||
true, false, true, false, false, true, false, false,
|
||||
true, false, false, false, true, true, false, false,
|
||||
true, true, true, false, false, true, false, true,
|
||||
false, true]));
|
||||
|
||||
// Append to empty BitVec
|
||||
let mut a = BitVec::new();
|
||||
let mut b = BitVec::from_bytes(&[0b10100000, 0b00010010, 0b10010010, 0b00110011, 0b10010101]);
|
||||
|
||||
a.append(&mut b);
|
||||
|
||||
assert_eq!(a.len(), 40);
|
||||
assert_eq!(b.len(), 0);
|
||||
assert!(b.capacity() >= 40);
|
||||
|
||||
assert!(a.eq_vec(&[true, false, true, false, false, false, false, false,
|
||||
false, false, false, true, false, false, true, false,
|
||||
true, false, false, true, false, false, true, false,
|
||||
false, false, true, true, false, false, true, true,
|
||||
true, false, false, true, false, true, false, true]));
|
||||
|
||||
// Append empty BitVec
|
||||
let mut a = BitVec::from_bytes(&[0b10100000, 0b00010010, 0b10010010, 0b00110011, 0b10010101]);
|
||||
let mut b = BitVec::new();
|
||||
|
||||
a.append(&mut b);
|
||||
|
||||
assert_eq!(a.len(), 40);
|
||||
assert_eq!(b.len(), 0);
|
||||
|
||||
assert!(a.eq_vec(&[true, false, true, false, false, false, false, false,
|
||||
false, false, false, true, false, false, true, false,
|
||||
true, false, false, true, false, false, true, false,
|
||||
false, false, true, true, false, false, true, true,
|
||||
true, false, false, true, false, true, false, true]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bit_vec_split_off() {
|
||||
// Split at 0
|
||||
let mut a = BitVec::new();
|
||||
a.push(true);
|
||||
a.push(false);
|
||||
a.push(false);
|
||||
a.push(true);
|
||||
|
||||
let b = a.split_off(0);
|
||||
|
||||
assert_eq!(a.len(), 0);
|
||||
assert_eq!(b.len(), 4);
|
||||
|
||||
assert!(b.eq_vec(&[true, false, false, true]));
|
||||
|
||||
// Split at last bit
|
||||
a.truncate(0);
|
||||
a.push(true);
|
||||
a.push(false);
|
||||
a.push(false);
|
||||
a.push(true);
|
||||
|
||||
let b = a.split_off(4);
|
||||
|
||||
assert_eq!(a.len(), 4);
|
||||
assert_eq!(b.len(), 0);
|
||||
|
||||
assert!(a.eq_vec(&[true, false, false, true]));
|
||||
|
||||
// Split at block boundary
|
||||
let mut a = BitVec::from_bytes(&[0b10100000, 0b00010010, 0b10010010, 0b00110011, 0b11110011]);
|
||||
|
||||
let b = a.split_off(32);
|
||||
|
||||
assert_eq!(a.len(), 32);
|
||||
assert_eq!(b.len(), 8);
|
||||
|
||||
assert!(a.eq_vec(&[true, false, true, false, false, false, false, false,
|
||||
false, false, false, true, false, false, true, false,
|
||||
true, false, false, true, false, false, true, false,
|
||||
false, false, true, true, false, false, true, true]));
|
||||
assert!(b.eq_vec(&[true, true, true, true, false, false, true, true]));
|
||||
|
||||
// Don't split at block boundary
|
||||
let mut a = BitVec::from_bytes(&[0b10100000, 0b00010010, 0b10010010, 0b00110011,
|
||||
0b01101011, 0b10101101]);
|
||||
|
||||
let b = a.split_off(13);
|
||||
|
||||
assert_eq!(a.len(), 13);
|
||||
assert_eq!(b.len(), 35);
|
||||
|
||||
assert!(a.eq_vec(&[true, false, true, false, false, false, false, false,
|
||||
false, false, false, true, false]));
|
||||
assert!(b.eq_vec(&[false, true, false, true, false, false, true, false,
|
||||
false, true, false, false, false, true, true, false,
|
||||
false, true, true, false, true, true, false, true,
|
||||
false, true, true, true, false, true, false, true,
|
||||
true, false, true]));
|
||||
}
|
||||
|
||||
mod bench {
|
||||
use std::collections::BitVec;
|
||||
use std::u32;
|
||||
|
||||
@ -12,6 +12,7 @@ use std::collections::BTreeMap;
|
||||
use std::collections::Bound::{Excluded, Included, Unbounded, self};
|
||||
use std::collections::btree_map::Entry::{Occupied, Vacant};
|
||||
use std::iter::range_inclusive;
|
||||
use std::rc::Rc;
|
||||
|
||||
#[test]
|
||||
fn test_basic_large() {
|
||||
@ -198,6 +199,34 @@ fn test_range() {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_borrow() {
|
||||
// make sure these compile -- using the Borrow trait
|
||||
{
|
||||
let mut map = BTreeMap::new();
|
||||
map.insert("0".to_string(), 1);
|
||||
assert_eq!(map["0"], 1);
|
||||
}
|
||||
|
||||
{
|
||||
let mut map = BTreeMap::new();
|
||||
map.insert(Box::new(0), 1);
|
||||
assert_eq!(map[&0], 1);
|
||||
}
|
||||
|
||||
{
|
||||
let mut map = BTreeMap::new();
|
||||
map.insert(Box::new([0, 1]) as Box<[i32]>, 1);
|
||||
assert_eq!(map[&[0, 1][..]], 1);
|
||||
}
|
||||
|
||||
{
|
||||
let mut map = BTreeMap::new();
|
||||
map.insert(Rc::new(0), 1);
|
||||
assert_eq!(map[&0], 1);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_entry(){
|
||||
let xs = [(1, 10), (2, 20), (3, 30), (4, 40), (5, 50), (6, 60)];
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user