Merge branch 'master' into lint-attr-fix
This commit is contained in:
commit
9cfb8b730a
577 changed files with 9617 additions and 5582 deletions
13
.gitignore
vendored
13
.gitignore
vendored
|
|
@ -73,12 +73,13 @@ __pycache__/
|
|||
/obj/
|
||||
/rt/
|
||||
/rustllvm/
|
||||
/src/libunicode/DerivedCoreProperties.txt
|
||||
/src/libunicode/EastAsianWidth.txt
|
||||
/src/libunicode/HangulSyllableType.txt
|
||||
/src/libunicode/PropList.txt
|
||||
/src/libunicode/Scripts.txt
|
||||
/src/libunicode/UnicodeData.txt
|
||||
/src/libstd_unicode/DerivedCoreProperties.txt
|
||||
/src/libstd_unicode/DerivedNormalizationProps.txt
|
||||
/src/libstd_unicode/PropList.txt
|
||||
/src/libstd_unicode/ReadMe.txt
|
||||
/src/libstd_unicode/Scripts.txt
|
||||
/src/libstd_unicode/SpecialCasing.txt
|
||||
/src/libstd_unicode/UnicodeData.txt
|
||||
/stage[0-9]+/
|
||||
/target
|
||||
/test/
|
||||
|
|
|
|||
2
.mailmap
2
.mailmap
|
|
@ -152,7 +152,7 @@ NAKASHIMA, Makoto <makoto.nksm+github@gmail.com>
|
|||
Nathan Wilson <wilnathan@gmail.com>
|
||||
Nathaniel Herman <nherman@post.harvard.edu> Nathaniel Herman <nherman@college.harvard.edu>
|
||||
Neil Pankey <npankey@gmail.com> <neil@wire.im>
|
||||
Nicholas Mazzuca <npmazzuca@gmail.com> Nicholas <npmazzuca@gmail.com>
|
||||
Nicole Mazzuca <npmazzuca@gmail.com> Nicole <npmazzuca@gmail.com>
|
||||
Nick Platt <platt.nicholas@gmail.com>
|
||||
Nif Ward <nif.ward@gmail.com>
|
||||
Oliver Schneider <oliver.schneider@kit.edu> oli-obk <github6541940@oli-obk.de>
|
||||
|
|
|
|||
64
.travis.yml
64
.travis.yml
|
|
@ -13,19 +13,20 @@ osx_image: xcode8.2
|
|||
matrix:
|
||||
include:
|
||||
# Linux builders, all docker images
|
||||
- env: IMAGE=arm-android
|
||||
- env: IMAGE=cross
|
||||
- env: IMAGE=i686-gnu
|
||||
- env: IMAGE=arm-android DEPLOY=1
|
||||
- env: IMAGE=cross DEPLOY=1
|
||||
- env: IMAGE=dist-arm-unknown-linux-gnueabi DEPLOY=1
|
||||
- env: IMAGE=dist-x86_64-unknown-freebsd DEPLOY=1
|
||||
- env: IMAGE=i686-gnu DEPLOY=1
|
||||
- env: IMAGE=i686-gnu-nopt
|
||||
- env: IMAGE=x86_64-freebsd
|
||||
- env: IMAGE=x86_64-gnu
|
||||
- env: IMAGE=x86_64-gnu DEPLOY=1
|
||||
- env: IMAGE=x86_64-gnu-full-bootstrap
|
||||
- env: IMAGE=x86_64-gnu-aux
|
||||
- env: IMAGE=x86_64-gnu-debug
|
||||
- env: IMAGE=x86_64-gnu-nopt
|
||||
- env: IMAGE=x86_64-gnu-make
|
||||
- env: IMAGE=x86_64-gnu-llvm-3.7 ALLOW_PR=1 RUST_BACKTRACE=1
|
||||
- env: IMAGE=x86_64-musl
|
||||
- env: IMAGE=x86_64-musl DEPLOY=1
|
||||
- env: IMAGE=x86_64-gnu-distcheck
|
||||
|
||||
# OSX builders
|
||||
|
|
@ -34,27 +35,44 @@ matrix:
|
|||
RUST_CONFIGURE_ARGS=--build=x86_64-apple-darwin
|
||||
SRC=.
|
||||
os: osx
|
||||
before_script: &osx_before_script >
|
||||
ulimit -c unlimited
|
||||
install: &osx_install_sccache >
|
||||
curl -L https://api.pub.build.mozilla.org/tooltool/sha512/d0025b286468cc5ada83b23d3fafbc936b9f190eaa7d4a981715b18e8e3bf720a7bcee7bfe758cfdeb8268857f6098fd52dcdd8818232692a30ce91039936596 |
|
||||
tar xJf - -C /usr/local/bin --strip-components=1
|
||||
after_failure: &osx_after_failure >
|
||||
echo 'bt all' > cmds;
|
||||
for file in $(ls /cores); do
|
||||
echo core file $file;
|
||||
lldb -c $file `which ld` -b -s cmds;
|
||||
done
|
||||
|
||||
- env: >
|
||||
RUST_CHECK_TARGET=check
|
||||
SCRIPT="./x.py test && ./x.py dist"
|
||||
RUST_CONFIGURE_ARGS=--build=i686-apple-darwin
|
||||
SRC=.
|
||||
DEPLOY=1
|
||||
os: osx
|
||||
before_script: *osx_before_script
|
||||
install: *osx_install_sccache
|
||||
after_failure: *osx_after_failure
|
||||
- env: >
|
||||
RUST_CHECK_TARGET=check
|
||||
RUST_CONFIGURE_ARGS=--build=x86_64-apple-darwin --disable-rustbuild
|
||||
SRC=.
|
||||
os: osx
|
||||
before_script: *osx_before_script
|
||||
install: *osx_install_sccache
|
||||
after_failure: *osx_after_failure
|
||||
- env: >
|
||||
RUST_CHECK_TARGET=
|
||||
RUST_CHECK_TARGET=dist
|
||||
RUST_CONFIGURE_ARGS=--target=aarch64-apple-ios,armv7-apple-ios,armv7s-apple-ios,i386-apple-ios,x86_64-apple-ios
|
||||
SRC=.
|
||||
DEPLOY=1
|
||||
os: osx
|
||||
before_script: *osx_before_script
|
||||
install: *osx_install_sccache
|
||||
after_failure: *osx_after_failure
|
||||
|
||||
env:
|
||||
global:
|
||||
|
|
@ -68,10 +86,10 @@ script:
|
|||
if [ "$ALLOW_PR" = "" ] && [ "$TRAVIS_BRANCH" != "auto" ]; then
|
||||
echo skipping, not a full build;
|
||||
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
||||
git submodule update --init &&
|
||||
travis_retry git submodule update --init &&
|
||||
src/ci/run.sh;
|
||||
else
|
||||
git submodule update --init &&
|
||||
travis_retry git submodule update --init &&
|
||||
src/ci/docker/run.sh $IMAGE;
|
||||
fi
|
||||
|
||||
|
|
@ -90,3 +108,29 @@ notifications:
|
|||
cache:
|
||||
directories:
|
||||
- $HOME/docker
|
||||
|
||||
before_deploy:
|
||||
- mkdir -p deploy/$TRAVIS_COMMIT
|
||||
- >
|
||||
if [ "$TRAVIS_OS_NAME" == "osx" ]; then
|
||||
cp build/dist/*.tar.gz deploy/$TRAVIS_COMMIT &&
|
||||
find "deploy/$TRAVIS_COMMIT" -maxdepth 1 -type f -exec sh -c 'shasum -a 256 -b "{}" > "{}.sha256"' \;;
|
||||
else
|
||||
cp obj/build/dist/*.tar.gz deploy/$TRAVIS_COMMIT &&
|
||||
find "deploy/$TRAVIS_COMMIT" -maxdepth 1 -type f -exec sh -c 'sha256sum -b "{}" > "{}.sha256"' \;;
|
||||
fi
|
||||
|
||||
deploy:
|
||||
- provider: s3
|
||||
bucket: rust-lang-ci
|
||||
skip_cleanup: true
|
||||
local_dir: deploy
|
||||
upload_dir: rustc-builds
|
||||
acl: public_read
|
||||
region: us-east-1
|
||||
access_key_id: AKIAIPQVNYF2T3DTYIWQ
|
||||
secret_access_key:
|
||||
secure: "FBqDqOTeIPMu6v/WYPf4CFSlh9rLRZGKVtpLa5KkyuOhXRTrnEzBduEtS8/FMIxdQImvurhSvxWvqRybMOi4qoVfjMqqpHAI7uBbidbrvAcJoHNsx6BgUNVCIoH6a0UsAjTUtm6/YPIpzbHoLZXPL0GrHPMk6Mu04qVSmcYNWn4="
|
||||
on:
|
||||
branch: auto
|
||||
condition: $DEPLOY = 1
|
||||
|
|
|
|||
|
|
@ -45,6 +45,10 @@ whole, instead of just a few lines inside the test.
|
|||
* `should-fail` indicates that the test should fail; used for "meta testing",
|
||||
where we test the compiletest program itself to check that it will generate
|
||||
errors in appropriate scenarios. This header is ignored for pretty-printer tests.
|
||||
* `gate-test-X` where `X` is a feature marks the test as "gate test" for feature X.
|
||||
Such tests are supposed to ensure that the compiler errors when usage of a gated
|
||||
feature is attempted without the proper `#![feature(X)]` tag.
|
||||
Each unstable lang feature is required to have a gate test.
|
||||
|
||||
## Revisions
|
||||
|
||||
|
|
|
|||
38
appveyor.yml
38
appveyor.yml
|
|
@ -8,10 +8,12 @@ environment:
|
|||
# 32/64 bit MSVC
|
||||
- MSYS_BITS: 64
|
||||
RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc
|
||||
RUST_CHECK_TARGET: check
|
||||
SCRIPT: python x.py test && python x.py dist
|
||||
DEPLOY: 1
|
||||
- MSYS_BITS: 32
|
||||
RUST_CONFIGURE_ARGS: --build=i686-pc-windows-msvc
|
||||
RUST_CHECK_TARGET: check
|
||||
SCRIPT: python x.py test && python x.py dist
|
||||
DEPLOY: 1
|
||||
|
||||
# MSVC makefiles
|
||||
- MSYS_BITS: 64
|
||||
|
|
@ -50,10 +52,11 @@ environment:
|
|||
# too long on appveyor and this is tested by rustbuild below.
|
||||
- MSYS_BITS: 32
|
||||
RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu
|
||||
RUST_CHECK_TARGET: check
|
||||
SCRIPT: python x.py test && python x.py dist
|
||||
MINGW_URL: https://s3.amazonaws.com/rust-lang-ci
|
||||
MINGW_ARCHIVE: i686-4.9.2-release-win32-dwarf-rt_v4-rev4.7z
|
||||
MINGW_DIR: mingw32
|
||||
DEPLOY: 1
|
||||
|
||||
- MSYS_BITS: 32
|
||||
RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu --disable-rustbuild
|
||||
|
|
@ -63,11 +66,12 @@ environment:
|
|||
MINGW_DIR: mingw32
|
||||
|
||||
- MSYS_BITS: 64
|
||||
RUST_CHECK_TARGET: check
|
||||
SCRIPT: python x.py test && python x.py dist
|
||||
RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu
|
||||
MINGW_URL: https://s3.amazonaws.com/rust-lang-ci
|
||||
MINGW_ARCHIVE: x86_64-4.9.2-release-win32-seh-rt_v4-rev4.7z
|
||||
MINGW_DIR: mingw64
|
||||
DEPLOY: 1
|
||||
|
||||
clone_depth: 1
|
||||
build: false
|
||||
|
|
@ -123,6 +127,32 @@ branches:
|
|||
only:
|
||||
- auto
|
||||
|
||||
before_deploy:
|
||||
- ps: |
|
||||
New-Item -Path deploy -ItemType directory
|
||||
Get-ChildItem -Path build\dist -Filter '*.tar.gz' | Move-Item -Destination deploy
|
||||
Get-FileHash .\deploy\* | ForEach-Object {
|
||||
[io.file]::WriteAllText($_.Path + ".sha256", $_.Hash.ToLower() + "`n")
|
||||
}
|
||||
Get-ChildItem -Path deploy | Foreach-Object {
|
||||
Push-AppveyorArtifact $_.FullName -FileName ${env:APPVEYOR_REPO_COMMIT}/$_
|
||||
}
|
||||
|
||||
deploy:
|
||||
- provider: S3
|
||||
skip_cleanup: true
|
||||
access_key_id: AKIAIPQVNYF2T3DTYIWQ
|
||||
secret_access_key:
|
||||
secure: +11jsUNFTQ9dq5Ad1i2+PeUJaXluFJ0zIJAXESE1dFT3Kdjku4/eDdgyjgsB6GnV
|
||||
bucket: rust-lang-ci
|
||||
set_public: true
|
||||
region: us-east-1
|
||||
artifact: /.*\.(tar.gz|sha256)/
|
||||
folder: rustc-builds
|
||||
on:
|
||||
branch: auto
|
||||
DEPLOY: 1
|
||||
|
||||
# init:
|
||||
# - ps: iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
|
||||
# on_finish:
|
||||
|
|
|
|||
25
configure
vendored
25
configure
vendored
|
|
@ -541,6 +541,18 @@ case $CFG_CPUTYPE in
|
|||
CFG_CPUTYPE=x86_64
|
||||
;;
|
||||
|
||||
mips | mips64)
|
||||
if [ "$CFG_CPUTYPE" = "mips64" ]; then
|
||||
CFG_OSTYPE="${CFG_OSTYPE}abi64"
|
||||
fi
|
||||
ENDIAN=$(printf '\1' | od -dAn)
|
||||
if [ "$ENDIAN" -eq 1 ]; then
|
||||
CFG_CPUTYPE="${CFG_CPUTYPE}el"
|
||||
elif [ "$ENDIAN" -ne 256 ]; then
|
||||
err "unknown endianness: $ENDIAN (expecting 1 for little or 256 for big)"
|
||||
fi
|
||||
;;
|
||||
|
||||
BePC)
|
||||
CFG_CPUTYPE=i686
|
||||
;;
|
||||
|
|
@ -647,6 +659,7 @@ opt_nosave debug-assertions 0 "build with debugging assertions"
|
|||
opt_nosave llvm-release-debuginfo 0 "build LLVM with debugger metadata"
|
||||
opt_nosave debuginfo 0 "build with debugger metadata"
|
||||
opt_nosave debuginfo-lines 0 "build with line number debugger metadata"
|
||||
opt_nosave debuginfo-only-std 0 "build only libstd with debugging information"
|
||||
opt_nosave debug-jemalloc 0 "build jemalloc with --enable-debug --enable-fill"
|
||||
|
||||
valopt localstatedir "/var/lib" "local state directory"
|
||||
|
|
@ -733,15 +746,17 @@ case "$CFG_RELEASE_CHANNEL" in
|
|||
nightly )
|
||||
msg "overriding settings for $CFG_RELEASE_CHANNEL"
|
||||
CFG_ENABLE_LLVM_ASSERTIONS=1
|
||||
|
||||
# FIXME(#37364) shouldn't have to disable this on windows-gnu
|
||||
# FIXME(stage0) re-enable this on the next stage0 now that #35566 is
|
||||
# fixed
|
||||
case "$CFG_BUILD" in
|
||||
*-pc-windows-gnu)
|
||||
;;
|
||||
*)
|
||||
CFG_ENABLE_DEBUGINFO_LINES=1
|
||||
CFG_ENABLE_DEBUGINFO_LINES=1
|
||||
CFG_ENABLE_DEBUGINFO_ONLY_STD=1
|
||||
;;
|
||||
esac
|
||||
|
||||
;;
|
||||
beta | stable)
|
||||
msg "overriding settings for $CFG_RELEASE_CHANNEL"
|
||||
|
|
@ -749,7 +764,8 @@ case "$CFG_RELEASE_CHANNEL" in
|
|||
*-pc-windows-gnu)
|
||||
;;
|
||||
*)
|
||||
CFG_ENABLE_DEBUGINFO_LINES=1
|
||||
CFG_ENABLE_DEBUGINFO_LINES=1
|
||||
CFG_ENABLE_DEBUGINFO_ONLY_STD=1
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
|
|
@ -785,6 +801,7 @@ if [ -n "$CFG_ENABLE_DEBUG_ASSERTIONS" ]; then putvar CFG_ENABLE_DEBUG_ASSERTION
|
|||
if [ -n "$CFG_ENABLE_LLVM_RELEASE_DEBUGINFO" ]; then putvar CFG_ENABLE_LLVM_RELEASE_DEBUGINFO; fi
|
||||
if [ -n "$CFG_ENABLE_DEBUGINFO" ]; then putvar CFG_ENABLE_DEBUGINFO; fi
|
||||
if [ -n "$CFG_ENABLE_DEBUGINFO_LINES" ]; then putvar CFG_ENABLE_DEBUGINFO_LINES; fi
|
||||
if [ -n "$CFG_ENABLE_DEBUGINFO_ONLY_STD" ]; then putvar CFG_ENABLE_DEBUGINFO_ONLY_STD; fi
|
||||
if [ -n "$CFG_ENABLE_DEBUG_JEMALLOC" ]; then putvar CFG_ENABLE_DEBUG_JEMALLOC; fi
|
||||
|
||||
step_msg "looking for build programs"
|
||||
|
|
|
|||
|
|
@ -175,7 +175,7 @@ endif
|
|||
# that the snapshot will be generated with a statically linked rustc so we only
|
||||
# have to worry about the distribution of one file (with its native dynamic
|
||||
# dependencies)
|
||||
RUSTFLAGS_STAGE0 += -C prefer-dynamic -C no-stack-check
|
||||
RUSTFLAGS_STAGE0 += -C prefer-dynamic
|
||||
RUSTFLAGS_STAGE1 += -C prefer-dynamic
|
||||
RUST_LIB_FLAGS_ST2 += -C prefer-dynamic
|
||||
RUST_LIB_FLAGS_ST3 += -C prefer-dynamic
|
||||
|
|
|
|||
1
src/Cargo.lock
generated
1
src/Cargo.lock
generated
|
|
@ -569,7 +569,6 @@ dependencies = [
|
|||
"rustc 0.0.0",
|
||||
"rustc_back 0.0.0",
|
||||
"rustc_const_eval 0.0.0",
|
||||
"rustc_const_math 0.0.0",
|
||||
"rustc_data_structures 0.0.0",
|
||||
"rustc_driver 0.0.0",
|
||||
"rustc_errors 0.0.0",
|
||||
|
|
|
|||
|
|
@ -6,18 +6,22 @@ version = "0.0.0"
|
|||
[lib]
|
||||
name = "bootstrap"
|
||||
path = "lib.rs"
|
||||
doctest = false
|
||||
|
||||
[[bin]]
|
||||
name = "bootstrap"
|
||||
path = "bin/main.rs"
|
||||
test = false
|
||||
|
||||
[[bin]]
|
||||
name = "rustc"
|
||||
path = "bin/rustc.rs"
|
||||
test = false
|
||||
|
||||
[[bin]]
|
||||
name = "rustdoc"
|
||||
path = "bin/rustdoc.rs"
|
||||
test = false
|
||||
|
||||
[dependencies]
|
||||
build_helper = { path = "../build_helper" }
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ def download(path, url, probably_big, verbose):
|
|||
option = "-#"
|
||||
else:
|
||||
option = "-s"
|
||||
run(["curl", option, "-Sf", "-o", path, url], verbose=verbose)
|
||||
run(["curl", option, "--retry", "3", "-Sf", "-o", path, url], verbose=verbose)
|
||||
|
||||
|
||||
def verify(path, sha_path, verbose):
|
||||
|
|
|
|||
|
|
@ -457,6 +457,8 @@ fn krate_android(build: &Build,
|
|||
|
||||
let output = output(Command::new("adb").arg("shell").arg(&program));
|
||||
println!("{}", output);
|
||||
|
||||
t!(fs::create_dir_all(build.out.join("tmp")));
|
||||
build.run(Command::new("adb")
|
||||
.arg("pull")
|
||||
.arg(&log)
|
||||
|
|
@ -516,6 +518,7 @@ pub fn android_copy_libs(build: &Build,
|
|||
}
|
||||
|
||||
println!("Android copy libs to emulator ({})", target);
|
||||
build.run(Command::new("adb").arg("wait-for-device"));
|
||||
build.run(Command::new("adb").arg("remount"));
|
||||
build.run(Command::new("adb").args(&["shell", "rm", "-r", ADB_TEST_DIR]));
|
||||
build.run(Command::new("adb").args(&["shell", "mkdir", ADB_TEST_DIR]));
|
||||
|
|
@ -568,3 +571,14 @@ pub fn distcheck(build: &Build) {
|
|||
.arg("check")
|
||||
.current_dir(&dir));
|
||||
}
|
||||
|
||||
/// Test the build system itself
|
||||
pub fn bootstrap(build: &Build) {
|
||||
let mut cmd = Command::new(&build.cargo);
|
||||
cmd.arg("test")
|
||||
.current_dir(build.src.join("src/bootstrap"))
|
||||
.env("CARGO_TARGET_DIR", build.out.join("bootstrap"))
|
||||
.env("RUSTC", &build.rustc);
|
||||
cmd.arg("--").args(&build.flags.cmd.test_args());
|
||||
build.run(&mut cmd);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@
|
|||
//! compiler. This module is also responsible for assembling the sysroot as it
|
||||
//! goes along from the output of the previous stage.
|
||||
|
||||
use std::cmp;
|
||||
use std::collections::HashMap;
|
||||
use std::fs::{self, File};
|
||||
use std::path::{Path, PathBuf};
|
||||
|
|
@ -59,7 +58,7 @@ pub fn std(build: &Build, target: &str, compiler: &Compiler) {
|
|||
}
|
||||
|
||||
build.run(&mut cargo);
|
||||
update_mtime(&libstd_stamp(build, &compiler, target));
|
||||
update_mtime(build, &libstd_stamp(build, &compiler, target));
|
||||
}
|
||||
|
||||
/// Link all libstd rlibs/dylibs into the sysroot location.
|
||||
|
|
@ -145,7 +144,7 @@ pub fn test(build: &Build, target: &str, compiler: &Compiler) {
|
|||
cargo.arg("--manifest-path")
|
||||
.arg(build.src.join("src/rustc/test_shim/Cargo.toml"));
|
||||
build.run(&mut cargo);
|
||||
update_mtime(&libtest_stamp(build, compiler, target));
|
||||
update_mtime(build, &libtest_stamp(build, compiler, target));
|
||||
}
|
||||
|
||||
/// Same as `std_link`, only for libtest
|
||||
|
|
@ -186,9 +185,16 @@ pub fn rustc(build: &Build, target: &str, compiler: &Compiler) {
|
|||
cargo.env("CFG_RELEASE", &build.release)
|
||||
.env("CFG_RELEASE_CHANNEL", &build.config.channel)
|
||||
.env("CFG_VERSION", &build.version)
|
||||
.env("CFG_PREFIX", build.config.prefix.clone().unwrap_or(String::new()))
|
||||
.env("CFG_PREFIX", build.config.prefix.clone().unwrap_or(PathBuf::new()))
|
||||
.env("CFG_LIBDIR_RELATIVE", "lib");
|
||||
|
||||
// If we're not building a compiler with debugging information then remove
|
||||
// these two env vars which would be set otherwise.
|
||||
if build.config.rust_debuginfo_only_std {
|
||||
cargo.env_remove("RUSTC_DEBUGINFO");
|
||||
cargo.env_remove("RUSTC_DEBUGINFO_LINES");
|
||||
}
|
||||
|
||||
if let Some(ref ver_date) = build.ver_date {
|
||||
cargo.env("CFG_VER_DATE", ver_date);
|
||||
}
|
||||
|
|
@ -258,11 +264,6 @@ fn compiler_file(compiler: &Path, file: &str) -> PathBuf {
|
|||
}
|
||||
|
||||
pub fn create_sysroot(build: &Build, compiler: &Compiler) {
|
||||
// nothing to do in stage0
|
||||
if compiler.stage == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
let sysroot = build.sysroot(compiler);
|
||||
let _ = fs::remove_dir_all(&sysroot);
|
||||
t!(fs::create_dir_all(&sysroot));
|
||||
|
|
@ -388,26 +389,39 @@ pub fn tool(build: &Build, stage: u32, host: &str, tool: &str) {
|
|||
}
|
||||
|
||||
/// Updates the mtime of a stamp file if necessary, only changing it if it's
|
||||
/// older than some other file in the same directory.
|
||||
/// older than some other library file in the same directory.
|
||||
///
|
||||
/// We don't know what file Cargo is going to output (because there's a hash in
|
||||
/// the file name) but we know where it's going to put it. We use this helper to
|
||||
/// detect changes to that output file by looking at the modification time for
|
||||
/// all files in a directory and updating the stamp if any are newer.
|
||||
fn update_mtime(path: &Path) {
|
||||
let mut max = None;
|
||||
if let Ok(entries) = path.parent().unwrap().read_dir() {
|
||||
for entry in entries.map(|e| t!(e)) {
|
||||
if t!(entry.file_type()).is_file() {
|
||||
let meta = t!(entry.metadata());
|
||||
let time = FileTime::from_last_modification_time(&meta);
|
||||
max = cmp::max(max, Some(time));
|
||||
}
|
||||
}
|
||||
}
|
||||
///
|
||||
/// Note that we only consider Rust libraries as that's what we're interested in
|
||||
/// propagating changes from. Files like executables are tracked elsewhere.
|
||||
fn update_mtime(build: &Build, path: &Path) {
|
||||
let entries = match path.parent().unwrap().join("deps").read_dir() {
|
||||
Ok(entries) => entries,
|
||||
Err(_) => return,
|
||||
};
|
||||
let files = entries.map(|e| t!(e)).filter(|e| t!(e.file_type()).is_file());
|
||||
let files = files.filter(|e| {
|
||||
let filename = e.file_name();
|
||||
let filename = filename.to_str().unwrap();
|
||||
filename.ends_with(".rlib") ||
|
||||
filename.ends_with(".lib") ||
|
||||
is_dylib(&filename)
|
||||
});
|
||||
let max = files.max_by_key(|entry| {
|
||||
let meta = t!(entry.metadata());
|
||||
FileTime::from_last_modification_time(&meta)
|
||||
});
|
||||
let max = match max {
|
||||
Some(max) => max,
|
||||
None => return,
|
||||
};
|
||||
|
||||
if !max.is_none() && max <= Some(mtime(path)) {
|
||||
return
|
||||
if mtime(&max.path()) > mtime(path) {
|
||||
build.verbose(&format!("updating {:?} as {:?} changed", path, max.path()));
|
||||
t!(File::create(path));
|
||||
}
|
||||
t!(File::create(path));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@ pub struct Config {
|
|||
pub rust_debug_assertions: bool,
|
||||
pub rust_debuginfo: bool,
|
||||
pub rust_debuginfo_lines: bool,
|
||||
pub rust_debuginfo_only_std: bool,
|
||||
pub rust_rpath: bool,
|
||||
pub rustc_default_linker: Option<String>,
|
||||
pub rustc_default_ar: Option<String>,
|
||||
|
|
@ -86,10 +87,10 @@ pub struct Config {
|
|||
pub quiet_tests: bool,
|
||||
// Fallback musl-root for all targets
|
||||
pub musl_root: Option<PathBuf>,
|
||||
pub prefix: Option<String>,
|
||||
pub docdir: Option<String>,
|
||||
pub libdir: Option<String>,
|
||||
pub mandir: Option<String>,
|
||||
pub prefix: Option<PathBuf>,
|
||||
pub docdir: Option<PathBuf>,
|
||||
pub libdir: Option<PathBuf>,
|
||||
pub mandir: Option<PathBuf>,
|
||||
pub codegen_tests: bool,
|
||||
pub nodejs: Option<PathBuf>,
|
||||
pub gdb: Option<PathBuf>,
|
||||
|
|
@ -144,6 +145,9 @@ struct Build {
|
|||
#[derive(RustcDecodable, Default, Clone)]
|
||||
struct Install {
|
||||
prefix: Option<String>,
|
||||
mandir: Option<String>,
|
||||
docdir: Option<String>,
|
||||
libdir: Option<String>,
|
||||
}
|
||||
|
||||
/// TOML representation of how the LLVM build is configured.
|
||||
|
|
@ -179,6 +183,7 @@ struct Rust {
|
|||
debug_assertions: Option<bool>,
|
||||
debuginfo: Option<bool>,
|
||||
debuginfo_lines: Option<bool>,
|
||||
debuginfo_only_std: Option<bool>,
|
||||
debug_jemalloc: Option<bool>,
|
||||
use_jemalloc: Option<bool>,
|
||||
backtrace: Option<bool>,
|
||||
|
|
@ -272,7 +277,10 @@ impl Config {
|
|||
set(&mut config.full_bootstrap, build.full_bootstrap);
|
||||
|
||||
if let Some(ref install) = toml.install {
|
||||
config.prefix = install.prefix.clone();
|
||||
config.prefix = install.prefix.clone().map(PathBuf::from);
|
||||
config.mandir = install.mandir.clone().map(PathBuf::from);
|
||||
config.docdir = install.docdir.clone().map(PathBuf::from);
|
||||
config.libdir = install.libdir.clone().map(PathBuf::from);
|
||||
}
|
||||
|
||||
if let Some(ref llvm) = toml.llvm {
|
||||
|
|
@ -298,6 +306,7 @@ impl Config {
|
|||
set(&mut config.rust_debug_assertions, rust.debug_assertions);
|
||||
set(&mut config.rust_debuginfo, rust.debuginfo);
|
||||
set(&mut config.rust_debuginfo_lines, rust.debuginfo_lines);
|
||||
set(&mut config.rust_debuginfo_only_std, rust.debuginfo_only_std);
|
||||
set(&mut config.rust_optimize, rust.optimize);
|
||||
set(&mut config.rust_optimize_tests, rust.optimize_tests);
|
||||
set(&mut config.rust_debuginfo_tests, rust.debuginfo_tests);
|
||||
|
|
@ -390,6 +399,7 @@ impl Config {
|
|||
("DEBUG_ASSERTIONS", self.rust_debug_assertions),
|
||||
("DEBUGINFO", self.rust_debuginfo),
|
||||
("DEBUGINFO_LINES", self.rust_debuginfo_lines),
|
||||
("DEBUGINFO_ONLY_STD", self.rust_debuginfo_only_std),
|
||||
("JEMALLOC", self.use_jemalloc),
|
||||
("DEBUG_JEMALLOC", self.debug_jemalloc),
|
||||
("RPATH", self.rust_rpath),
|
||||
|
|
@ -459,16 +469,16 @@ impl Config {
|
|||
self.channel = value.to_string();
|
||||
}
|
||||
"CFG_PREFIX" => {
|
||||
self.prefix = Some(value.to_string());
|
||||
self.prefix = Some(PathBuf::from(value));
|
||||
}
|
||||
"CFG_DOCDIR" => {
|
||||
self.docdir = Some(value.to_string());
|
||||
self.docdir = Some(PathBuf::from(value));
|
||||
}
|
||||
"CFG_LIBDIR" => {
|
||||
self.libdir = Some(value.to_string());
|
||||
self.libdir = Some(PathBuf::from(value));
|
||||
}
|
||||
"CFG_MANDIR" => {
|
||||
self.mandir = Some(value.to_string());
|
||||
self.mandir = Some(PathBuf::from(value));
|
||||
}
|
||||
"CFG_LLVM_ROOT" if value.len() > 0 => {
|
||||
let target = self.target_config.entry(self.build.clone())
|
||||
|
|
|
|||
|
|
@ -124,7 +124,16 @@
|
|||
[install]
|
||||
|
||||
# Instead of installing to /usr/local, install to this path instead.
|
||||
#prefix = "/path/to/install"
|
||||
#prefix = "/usr/local"
|
||||
|
||||
# Where to install libraries in `prefix` above
|
||||
#libdir = "lib"
|
||||
|
||||
# Where to install man pages in `prefix` above
|
||||
#mandir = "share/man"
|
||||
|
||||
# Where to install documentation in `prefix` above
|
||||
#docdir = "share/doc/rust"
|
||||
|
||||
# =============================================================================
|
||||
# Options for compiling Rust code itself
|
||||
|
|
@ -149,6 +158,11 @@
|
|||
# Whether or not line number debug information is emitted
|
||||
#debuginfo-lines = false
|
||||
|
||||
# Whether or not to only build debuginfo for the standard library if enabled.
|
||||
# If enabled, this will not compile the compiler with debuginfo, just the
|
||||
# standard library.
|
||||
#debuginfo-only-std = false
|
||||
|
||||
# Whether or not jemalloc is built and enabled
|
||||
#use-jemalloc = true
|
||||
|
||||
|
|
|
|||
|
|
@ -354,22 +354,15 @@ pub fn analysis(build: &Build, compiler: &Compiler, target: &str) {
|
|||
}
|
||||
|
||||
/// Creates the `rust-src` installer component and the plain source tarball
|
||||
pub fn rust_src(build: &Build, host: &str) {
|
||||
pub fn rust_src(build: &Build) {
|
||||
println!("Dist src");
|
||||
|
||||
if host != build.config.build {
|
||||
println!("\tskipping, not a build host");
|
||||
return
|
||||
}
|
||||
|
||||
let plain_name = format!("rustc-{}-src", package_vers(build));
|
||||
let name = format!("rust-src-{}", package_vers(build));
|
||||
let image = tmpdir(build).join(format!("{}-image", name));
|
||||
let _ = fs::remove_dir_all(&image);
|
||||
|
||||
let dst = image.join("lib/rustlib/src");
|
||||
let dst_src = dst.join("rust");
|
||||
let plain_dst_src = dst.join(&plain_name);
|
||||
t!(fs::create_dir_all(&dst_src));
|
||||
|
||||
// This is the set of root paths which will become part of the source package
|
||||
|
|
@ -449,7 +442,11 @@ pub fn rust_src(build: &Build, host: &str) {
|
|||
build.run(&mut cmd);
|
||||
|
||||
// Rename directory, so that root folder of tarball has the correct name
|
||||
t!(fs::rename(&dst_src, &plain_dst_src));
|
||||
let plain_name = format!("rustc-{}-src", package_vers(build));
|
||||
let plain_dst_src = tmpdir(build).join(&plain_name);
|
||||
let _ = fs::remove_dir_all(&plain_dst_src);
|
||||
t!(fs::create_dir_all(&plain_dst_src));
|
||||
cp_r(&dst_src, &plain_dst_src);
|
||||
|
||||
// Create the version file
|
||||
write_file(&plain_dst_src.join("version"), build.version.as_bytes());
|
||||
|
|
@ -458,10 +455,11 @@ pub fn rust_src(build: &Build, host: &str) {
|
|||
let mut cmd = Command::new("tar");
|
||||
cmd.arg("-czf").arg(sanitize_sh(&rust_src_location(build)))
|
||||
.arg(&plain_name)
|
||||
.current_dir(&dst);
|
||||
.current_dir(tmpdir(build));
|
||||
build.run(&mut cmd);
|
||||
|
||||
t!(fs::remove_dir_all(&image));
|
||||
t!(fs::remove_dir_all(&plain_dst_src));
|
||||
}
|
||||
|
||||
fn install(src: &Path, dstdir: &Path, perms: u32) {
|
||||
|
|
|
|||
|
|
@ -57,12 +57,12 @@ pub fn rustbook(build: &Build, target: &str, name: &str) {
|
|||
/// `STAMP` alongw ith providing the various header/footer HTML we've cutomized.
|
||||
///
|
||||
/// In the end, this is just a glorified wrapper around rustdoc!
|
||||
pub fn standalone(build: &Build, stage: u32, target: &str) {
|
||||
println!("Documenting stage{} standalone ({})", stage, target);
|
||||
pub fn standalone(build: &Build, target: &str) {
|
||||
println!("Documenting standalone ({})", target);
|
||||
let out = build.doc_out(target);
|
||||
t!(fs::create_dir_all(&out));
|
||||
|
||||
let compiler = Compiler::new(stage, &build.config.build);
|
||||
let compiler = Compiler::new(0, &build.config.build);
|
||||
|
||||
let favicon = build.src.join("src/doc/favicon.inc");
|
||||
let footer = build.src.join("src/doc/footer.inc");
|
||||
|
|
@ -151,8 +151,25 @@ pub fn std(build: &Build, stage: u32, target: &str) {
|
|||
let mut cargo = build.cargo(&compiler, Mode::Libstd, target, "doc");
|
||||
cargo.arg("--manifest-path")
|
||||
.arg(build.src.join("src/rustc/std_shim/Cargo.toml"))
|
||||
.arg("--features").arg(build.std_features())
|
||||
.arg("-p").arg("std");
|
||||
.arg("--features").arg(build.std_features());
|
||||
|
||||
// We don't want to build docs for internal std dependencies unless
|
||||
// in compiler-docs mode. When not in that mode, we whitelist the crates
|
||||
// for which docs must be built.
|
||||
if build.config.compiler_docs {
|
||||
cargo.arg("-p").arg("std");
|
||||
} else {
|
||||
cargo.arg("--no-deps");
|
||||
for krate in &["alloc", "collections", "core", "std", "std_unicode"] {
|
||||
cargo.arg("-p").arg(krate);
|
||||
// Create all crate output directories first to make sure rustdoc uses
|
||||
// relative links.
|
||||
// FIXME: Cargo should probably do this itself.
|
||||
t!(fs::create_dir_all(out_dir.join(krate)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
build.run(&mut cargo);
|
||||
cp_r(&out_dir, &out)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -67,6 +67,7 @@ pub enum Subcommand {
|
|||
},
|
||||
Clean,
|
||||
Dist {
|
||||
paths: Vec<PathBuf>,
|
||||
install: bool,
|
||||
},
|
||||
}
|
||||
|
|
@ -249,6 +250,7 @@ To learn more about a subcommand, run `./x.py <command> -h`
|
|||
opts.optflag("", "install", "run installer as well");
|
||||
m = parse(&opts);
|
||||
Subcommand::Dist {
|
||||
paths: remaining_as_path(&m),
|
||||
install: m.opt_present("install"),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,9 +13,9 @@
|
|||
//! This module is responsible for installing the standard library,
|
||||
//! compiler, and documentation.
|
||||
|
||||
use std::env;
|
||||
use std::fs;
|
||||
use std::borrow::Cow;
|
||||
use std::path::Path;
|
||||
use std::path::{Path, PathBuf, Component};
|
||||
use std::process::Command;
|
||||
|
||||
use Build;
|
||||
|
|
@ -23,23 +23,35 @@ use dist::{package_vers, sanitize_sh, tmpdir};
|
|||
|
||||
/// Installs everything.
|
||||
pub fn install(build: &Build, stage: u32, host: &str) {
|
||||
let prefix = build.config.prefix.as_ref().clone().map(|x| Path::new(x))
|
||||
.unwrap_or(Path::new("/usr/local"));
|
||||
let docdir = build.config.docdir.as_ref().clone().map(|x| Cow::Borrowed(Path::new(x)))
|
||||
.unwrap_or(Cow::Owned(prefix.join("share/doc/rust")));
|
||||
let libdir = build.config.libdir.as_ref().clone().map(|x| Cow::Borrowed(Path::new(x)))
|
||||
.unwrap_or(Cow::Owned(prefix.join("lib")));
|
||||
let mandir = build.config.mandir.as_ref().clone().map(|x| Cow::Borrowed(Path::new(x)))
|
||||
.unwrap_or(Cow::Owned(prefix.join("share/man")));
|
||||
let prefix_default = PathBuf::from("/usr/local");
|
||||
let docdir_default = PathBuf::from("share/doc/rust");
|
||||
let mandir_default = PathBuf::from("share/man");
|
||||
let libdir_default = PathBuf::from("lib");
|
||||
let prefix = build.config.prefix.as_ref().unwrap_or(&prefix_default);
|
||||
let docdir = build.config.docdir.as_ref().unwrap_or(&docdir_default);
|
||||
let libdir = build.config.libdir.as_ref().unwrap_or(&libdir_default);
|
||||
let mandir = build.config.mandir.as_ref().unwrap_or(&mandir_default);
|
||||
|
||||
let docdir = prefix.join(docdir);
|
||||
let libdir = prefix.join(libdir);
|
||||
let mandir = prefix.join(mandir);
|
||||
|
||||
let destdir = env::var_os("DESTDIR").map(PathBuf::from);
|
||||
|
||||
let prefix = add_destdir(&prefix, &destdir);
|
||||
let docdir = add_destdir(&docdir, &destdir);
|
||||
let libdir = add_destdir(&libdir, &destdir);
|
||||
let mandir = add_destdir(&mandir, &destdir);
|
||||
|
||||
let empty_dir = build.out.join("tmp/empty_dir");
|
||||
t!(fs::create_dir_all(&empty_dir));
|
||||
if build.config.docs {
|
||||
install_sh(&build, "docs", "rust-docs", stage, host, prefix,
|
||||
install_sh(&build, "docs", "rust-docs", stage, host, &prefix,
|
||||
&docdir, &libdir, &mandir, &empty_dir);
|
||||
}
|
||||
install_sh(&build, "std", "rust-std", stage, host, prefix,
|
||||
install_sh(&build, "std", "rust-std", stage, host, &prefix,
|
||||
&docdir, &libdir, &mandir, &empty_dir);
|
||||
install_sh(&build, "rustc", "rustc", stage, host, prefix,
|
||||
install_sh(&build, "rustc", "rustc", stage, host, &prefix,
|
||||
&docdir, &libdir, &mandir, &empty_dir);
|
||||
t!(fs::remove_dir_all(&empty_dir));
|
||||
}
|
||||
|
|
@ -59,3 +71,17 @@ fn install_sh(build: &Build, package: &str, name: &str, stage: u32, host: &str,
|
|||
.arg("--disable-ldconfig");
|
||||
build.run(&mut cmd);
|
||||
}
|
||||
|
||||
fn add_destdir(path: &Path, destdir: &Option<PathBuf>) -> PathBuf {
|
||||
let mut ret = match *destdir {
|
||||
Some(ref dest) => dest.clone(),
|
||||
None => return path.to_path_buf(),
|
||||
};
|
||||
for part in path.components() {
|
||||
match part {
|
||||
Component::Normal(s) => ret.push(s),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
|
|
|||
|
|
@ -316,7 +316,6 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules {
|
|||
"codegen-units");
|
||||
suite("check-incremental", "src/test/incremental", "incremental",
|
||||
"incremental");
|
||||
suite("check-ui", "src/test/ui", "ui", "ui");
|
||||
}
|
||||
|
||||
if build.config.build.contains("msvc") {
|
||||
|
|
@ -363,8 +362,11 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules {
|
|||
});
|
||||
};
|
||||
|
||||
suite("check-ui", "src/test/ui", "ui", "ui");
|
||||
suite("check-rpass-full", "src/test/run-pass-fulldeps",
|
||||
"run-pass", "run-pass-fulldeps");
|
||||
suite("check-rfail-full", "src/test/run-fail-fulldeps",
|
||||
"run-fail", "run-fail-fulldeps");
|
||||
suite("check-cfail-full", "src/test/compile-fail-fulldeps",
|
||||
"compile-fail", "compile-fail-fulldeps");
|
||||
suite("check-rmake", "src/test/run-make", "run-make", "run-make");
|
||||
|
|
@ -459,6 +461,7 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules {
|
|||
.dep(|s| s.name("tool-tidy").stage(0))
|
||||
.default(true)
|
||||
.host(true)
|
||||
.only_build(true)
|
||||
.run(move |s| check::tidy(build, s.target));
|
||||
rules.test("check-error-index", "src/tools/error_index_generator")
|
||||
.dep(|s| s.name("libstd"))
|
||||
|
|
@ -482,6 +485,12 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules {
|
|||
.dep(|s| s.name("libtest"))
|
||||
.run(move |s| check::android_copy_libs(build, &s.compiler(), s.target));
|
||||
|
||||
rules.test("check-bootstrap", "src/bootstrap")
|
||||
.default(true)
|
||||
.host(true)
|
||||
.only_build(true)
|
||||
.run(move |_| check::bootstrap(build));
|
||||
|
||||
// ========================================================================
|
||||
// Build tools
|
||||
//
|
||||
|
|
@ -508,17 +517,32 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules {
|
|||
// ========================================================================
|
||||
// Documentation targets
|
||||
rules.doc("doc-book", "src/doc/book")
|
||||
.dep(move |s| s.name("tool-rustbook").target(&build.config.build).stage(0))
|
||||
.dep(move |s| {
|
||||
s.name("tool-rustbook")
|
||||
.host(&build.config.build)
|
||||
.target(&build.config.build)
|
||||
.stage(0)
|
||||
})
|
||||
.default(build.config.docs)
|
||||
.run(move |s| doc::rustbook(build, s.target, "book"));
|
||||
rules.doc("doc-nomicon", "src/doc/nomicon")
|
||||
.dep(move |s| s.name("tool-rustbook").target(&build.config.build).stage(0))
|
||||
.dep(move |s| {
|
||||
s.name("tool-rustbook")
|
||||
.host(&build.config.build)
|
||||
.target(&build.config.build)
|
||||
.stage(0)
|
||||
})
|
||||
.default(build.config.docs)
|
||||
.run(move |s| doc::rustbook(build, s.target, "nomicon"));
|
||||
rules.doc("doc-standalone", "src/doc")
|
||||
.dep(move |s| s.name("rustc").host(&build.config.build).target(&build.config.build))
|
||||
.dep(move |s| {
|
||||
s.name("rustc")
|
||||
.host(&build.config.build)
|
||||
.target(&build.config.build)
|
||||
.stage(0)
|
||||
})
|
||||
.default(build.config.docs)
|
||||
.run(move |s| doc::standalone(build, s.stage, s.target));
|
||||
.run(move |s| doc::standalone(build, s.target));
|
||||
rules.doc("doc-error-index", "src/tools/error_index_generator")
|
||||
.dep(move |s| s.name("tool-error-index").target(&build.config.build).stage(0))
|
||||
.dep(move |s| s.name("librustc-link").stage(0))
|
||||
|
|
@ -550,6 +574,7 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules {
|
|||
rules.dist("dist-rustc", "src/librustc")
|
||||
.dep(move |s| s.name("rustc").host(&build.config.build))
|
||||
.host(true)
|
||||
.only_host_build(true)
|
||||
.default(true)
|
||||
.run(move |s| dist::rustc(build, s.stage, s.target));
|
||||
rules.dist("dist-std", "src/libstd")
|
||||
|
|
@ -564,9 +589,11 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules {
|
|||
}
|
||||
})
|
||||
.default(true)
|
||||
.only_host_build(true)
|
||||
.run(move |s| dist::std(build, &s.compiler(), s.target));
|
||||
rules.dist("dist-mingw", "path/to/nowhere")
|
||||
.default(true)
|
||||
.only_host_build(true)
|
||||
.run(move |s| {
|
||||
if s.target.contains("pc-windows-gnu") {
|
||||
dist::mingw(build, s.target)
|
||||
|
|
@ -575,16 +602,20 @@ pub fn build_rules<'a>(build: &'a Build) -> Rules {
|
|||
rules.dist("dist-src", "src")
|
||||
.default(true)
|
||||
.host(true)
|
||||
.run(move |s| dist::rust_src(build, s.target));
|
||||
.only_build(true)
|
||||
.only_host_build(true)
|
||||
.run(move |_| dist::rust_src(build));
|
||||
rules.dist("dist-docs", "src/doc")
|
||||
.default(true)
|
||||
.only_host_build(true)
|
||||
.dep(|s| s.name("default:doc"))
|
||||
.run(move |s| dist::docs(build, s.stage, s.target));
|
||||
rules.dist("dist-analysis", "analysis")
|
||||
.dep(|s| s.name("dist-std"))
|
||||
.default(true)
|
||||
.only_host_build(true)
|
||||
.run(move |s| dist::analysis(build, &s.compiler(), s.target));
|
||||
rules.dist("install", "src")
|
||||
rules.dist("install", "path/to/nowhere")
|
||||
.dep(|s| s.name("default:dist"))
|
||||
.run(move |s| install::install(build, s.stage, s.target));
|
||||
|
||||
|
|
@ -671,6 +702,14 @@ struct Rule<'a> {
|
|||
/// only intended for compiler hosts and not for targets that are being
|
||||
/// generated.
|
||||
host: bool,
|
||||
|
||||
/// Whether this rule is only for steps where the host is the build triple,
|
||||
/// not anything in hosts or targets.
|
||||
only_host_build: bool,
|
||||
|
||||
/// Whether this rule is only for the build triple, not anything in hosts or
|
||||
/// targets.
|
||||
only_build: bool,
|
||||
}
|
||||
|
||||
#[derive(PartialEq)]
|
||||
|
|
@ -692,6 +731,8 @@ impl<'a> Rule<'a> {
|
|||
kind: kind,
|
||||
default: false,
|
||||
host: false,
|
||||
only_host_build: false,
|
||||
only_build: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -727,6 +768,16 @@ impl<'a, 'b> RuleBuilder<'a, 'b> {
|
|||
self.rule.host = host;
|
||||
self
|
||||
}
|
||||
|
||||
fn only_build(&mut self, only_build: bool) -> &mut Self {
|
||||
self.rule.only_build = only_build;
|
||||
self
|
||||
}
|
||||
|
||||
fn only_host_build(&mut self, only_host_build: bool) -> &mut Self {
|
||||
self.rule.only_host_build = only_host_build;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b> Drop for RuleBuilder<'a, 'b> {
|
||||
|
|
@ -881,11 +932,11 @@ invalid rule dependency graph detected, was a rule added and maybe typo'd?
|
|||
Subcommand::Doc { ref paths } => (Kind::Doc, &paths[..]),
|
||||
Subcommand::Test { ref paths, test_args: _ } => (Kind::Test, &paths[..]),
|
||||
Subcommand::Bench { ref paths, test_args: _ } => (Kind::Bench, &paths[..]),
|
||||
Subcommand::Dist { install } => {
|
||||
Subcommand::Dist { ref paths, install } => {
|
||||
if install {
|
||||
return vec![self.sbuild.name("install")]
|
||||
} else {
|
||||
(Kind::Dist, &[][..])
|
||||
(Kind::Dist, &paths[..])
|
||||
}
|
||||
}
|
||||
Subcommand::Clean => panic!(),
|
||||
|
|
@ -896,19 +947,12 @@ invalid rule dependency graph detected, was a rule added and maybe typo'd?
|
|||
path.ends_with(rule.path)
|
||||
})
|
||||
}).flat_map(|rule| {
|
||||
let hosts = if self.build.flags.host.len() > 0 {
|
||||
let hosts = if rule.only_host_build || rule.only_build {
|
||||
&self.build.config.host[..1]
|
||||
} else if self.build.flags.host.len() > 0 {
|
||||
&self.build.flags.host
|
||||
} else {
|
||||
if kind == Kind::Dist {
|
||||
// For 'dist' steps we only distribute artifacts built from
|
||||
// the build platform, so only consider that in the hosts
|
||||
// array.
|
||||
// NOTE: This relies on the fact that the build triple is
|
||||
// always placed first, as done in `config.rs`.
|
||||
&self.build.config.host[..1]
|
||||
} else {
|
||||
&self.build.config.host
|
||||
}
|
||||
&self.build.config.host
|
||||
};
|
||||
let targets = if self.build.flags.target.len() > 0 {
|
||||
&self.build.flags.target
|
||||
|
|
@ -928,6 +972,8 @@ invalid rule dependency graph detected, was a rule added and maybe typo'd?
|
|||
&self.build.flags.host[..]
|
||||
} else if self.build.flags.target.len() > 0 {
|
||||
&[]
|
||||
} else if rule.only_build {
|
||||
&self.build.config.host[..1]
|
||||
} else {
|
||||
&self.build.config.host[..]
|
||||
}
|
||||
|
|
@ -955,12 +1001,7 @@ invalid rule dependency graph detected, was a rule added and maybe typo'd?
|
|||
|
||||
// Using `steps` as the top-level targets, make a topological ordering
|
||||
// of what we need to do.
|
||||
let mut order = Vec::new();
|
||||
let mut added = HashSet::new();
|
||||
added.insert(Step::noop());
|
||||
for step in steps.iter().cloned() {
|
||||
self.fill(step, &mut order, &mut added);
|
||||
}
|
||||
let order = self.expand(steps);
|
||||
|
||||
// Print out what we're doing for debugging
|
||||
self.build.verbose("bootstrap build plan:");
|
||||
|
|
@ -979,6 +1020,18 @@ invalid rule dependency graph detected, was a rule added and maybe typo'd?
|
|||
}
|
||||
}
|
||||
|
||||
/// From the top level targets `steps` generate a topological ordering of
|
||||
/// all steps needed to run those steps.
|
||||
fn expand(&self, steps: &[Step<'a>]) -> Vec<Step<'a>> {
|
||||
let mut order = Vec::new();
|
||||
let mut added = HashSet::new();
|
||||
added.insert(Step::noop());
|
||||
for step in steps.iter().cloned() {
|
||||
self.fill(step, &mut order, &mut added);
|
||||
}
|
||||
return order
|
||||
}
|
||||
|
||||
/// Performs topological sort of dependencies rooted at the `step`
|
||||
/// specified, pushing all results onto the `order` vector provided.
|
||||
///
|
||||
|
|
@ -1015,3 +1068,365 @@ invalid rule dependency graph detected, was a rule added and maybe typo'd?
|
|||
order.push(step);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::env;
|
||||
|
||||
use Build;
|
||||
use config::Config;
|
||||
use flags::Flags;
|
||||
|
||||
macro_rules! a {
|
||||
($($a:expr),*) => (vec![$($a.to_string()),*])
|
||||
}
|
||||
|
||||
fn build(args: &[&str],
|
||||
extra_host: &[&str],
|
||||
extra_target: &[&str]) -> Build {
|
||||
let mut args = args.iter().map(|s| s.to_string()).collect::<Vec<_>>();
|
||||
args.push("--build".to_string());
|
||||
args.push("A".to_string());
|
||||
let flags = Flags::parse(&args);
|
||||
|
||||
let mut config = Config::default();
|
||||
config.docs = true;
|
||||
config.build = "A".to_string();
|
||||
config.host = vec![config.build.clone()];
|
||||
config.host.extend(extra_host.iter().map(|s| s.to_string()));
|
||||
config.target = config.host.clone();
|
||||
config.target.extend(extra_target.iter().map(|s| s.to_string()));
|
||||
|
||||
let mut build = Build::new(flags, config);
|
||||
let cwd = env::current_dir().unwrap();
|
||||
build.crates.insert("std_shim".to_string(), ::Crate {
|
||||
name: "std_shim".to_string(),
|
||||
deps: Vec::new(),
|
||||
path: cwd.join("src/std_shim"),
|
||||
doc_step: "doc-std_shim".to_string(),
|
||||
build_step: "build-crate-std_shim".to_string(),
|
||||
test_step: "test-std_shim".to_string(),
|
||||
bench_step: "bench-std_shim".to_string(),
|
||||
});
|
||||
build.crates.insert("test_shim".to_string(), ::Crate {
|
||||
name: "test_shim".to_string(),
|
||||
deps: Vec::new(),
|
||||
path: cwd.join("src/test_shim"),
|
||||
doc_step: "doc-test_shim".to_string(),
|
||||
build_step: "build-crate-test_shim".to_string(),
|
||||
test_step: "test-test_shim".to_string(),
|
||||
bench_step: "bench-test_shim".to_string(),
|
||||
});
|
||||
build.crates.insert("rustc-main".to_string(), ::Crate {
|
||||
name: "rustc-main".to_string(),
|
||||
deps: Vec::new(),
|
||||
path: cwd.join("src/rustc-main"),
|
||||
doc_step: "doc-rustc-main".to_string(),
|
||||
build_step: "build-crate-rustc-main".to_string(),
|
||||
test_step: "test-rustc-main".to_string(),
|
||||
bench_step: "bench-rustc-main".to_string(),
|
||||
});
|
||||
return build
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dist_baseline() {
|
||||
let build = build(&["dist"], &[], &[]);
|
||||
let rules = super::build_rules(&build);
|
||||
let plan = rules.plan();
|
||||
println!("rules: {:#?}", plan);
|
||||
assert!(plan.iter().all(|s| s.stage == 2));
|
||||
assert!(plan.iter().all(|s| s.host == "A" ));
|
||||
assert!(plan.iter().all(|s| s.target == "A" ));
|
||||
|
||||
let step = super::Step {
|
||||
name: "",
|
||||
stage: 2,
|
||||
host: &build.config.build,
|
||||
target: &build.config.build,
|
||||
};
|
||||
|
||||
assert!(plan.contains(&step.name("dist-docs")));
|
||||
assert!(plan.contains(&step.name("dist-mingw")));
|
||||
assert!(plan.contains(&step.name("dist-rustc")));
|
||||
assert!(plan.contains(&step.name("dist-std")));
|
||||
assert!(plan.contains(&step.name("dist-src")));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dist_with_targets() {
|
||||
let build = build(&["dist"], &[], &["B"]);
|
||||
let rules = super::build_rules(&build);
|
||||
let plan = rules.plan();
|
||||
println!("rules: {:#?}", plan);
|
||||
assert!(plan.iter().all(|s| s.stage == 2));
|
||||
assert!(plan.iter().all(|s| s.host == "A" ));
|
||||
|
||||
let step = super::Step {
|
||||
name: "",
|
||||
stage: 2,
|
||||
host: &build.config.build,
|
||||
target: &build.config.build,
|
||||
};
|
||||
|
||||
assert!(plan.contains(&step.name("dist-docs")));
|
||||
assert!(plan.contains(&step.name("dist-mingw")));
|
||||
assert!(plan.contains(&step.name("dist-rustc")));
|
||||
assert!(plan.contains(&step.name("dist-std")));
|
||||
assert!(plan.contains(&step.name("dist-src")));
|
||||
|
||||
assert!(plan.contains(&step.target("B").name("dist-docs")));
|
||||
assert!(plan.contains(&step.target("B").name("dist-mingw")));
|
||||
assert!(!plan.contains(&step.target("B").name("dist-rustc")));
|
||||
assert!(plan.contains(&step.target("B").name("dist-std")));
|
||||
assert!(!plan.contains(&step.target("B").name("dist-src")));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dist_with_hosts() {
|
||||
let build = build(&["dist"], &["B"], &[]);
|
||||
let rules = super::build_rules(&build);
|
||||
let plan = rules.plan();
|
||||
println!("rules: {:#?}", plan);
|
||||
assert!(plan.iter().all(|s| s.stage == 2));
|
||||
|
||||
let step = super::Step {
|
||||
name: "",
|
||||
stage: 2,
|
||||
host: &build.config.build,
|
||||
target: &build.config.build,
|
||||
};
|
||||
|
||||
assert!(!plan.iter().any(|s| s.host == "B"));
|
||||
|
||||
assert!(plan.contains(&step.name("dist-docs")));
|
||||
assert!(plan.contains(&step.name("dist-mingw")));
|
||||
assert!(plan.contains(&step.name("dist-rustc")));
|
||||
assert!(plan.contains(&step.name("dist-std")));
|
||||
assert!(plan.contains(&step.name("dist-src")));
|
||||
|
||||
assert!(plan.contains(&step.target("B").name("dist-docs")));
|
||||
assert!(plan.contains(&step.target("B").name("dist-mingw")));
|
||||
assert!(plan.contains(&step.target("B").name("dist-rustc")));
|
||||
assert!(plan.contains(&step.target("B").name("dist-std")));
|
||||
assert!(!plan.contains(&step.target("B").name("dist-src")));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dist_with_targets_and_hosts() {
|
||||
let build = build(&["dist"], &["B"], &["C"]);
|
||||
let rules = super::build_rules(&build);
|
||||
let plan = rules.plan();
|
||||
println!("rules: {:#?}", plan);
|
||||
assert!(plan.iter().all(|s| s.stage == 2));
|
||||
|
||||
let step = super::Step {
|
||||
name: "",
|
||||
stage: 2,
|
||||
host: &build.config.build,
|
||||
target: &build.config.build,
|
||||
};
|
||||
|
||||
assert!(!plan.iter().any(|s| s.host == "B"));
|
||||
assert!(!plan.iter().any(|s| s.host == "C"));
|
||||
|
||||
assert!(plan.contains(&step.name("dist-docs")));
|
||||
assert!(plan.contains(&step.name("dist-mingw")));
|
||||
assert!(plan.contains(&step.name("dist-rustc")));
|
||||
assert!(plan.contains(&step.name("dist-std")));
|
||||
assert!(plan.contains(&step.name("dist-src")));
|
||||
|
||||
assert!(plan.contains(&step.target("B").name("dist-docs")));
|
||||
assert!(plan.contains(&step.target("B").name("dist-mingw")));
|
||||
assert!(plan.contains(&step.target("B").name("dist-rustc")));
|
||||
assert!(plan.contains(&step.target("B").name("dist-std")));
|
||||
assert!(!plan.contains(&step.target("B").name("dist-src")));
|
||||
|
||||
assert!(plan.contains(&step.target("C").name("dist-docs")));
|
||||
assert!(plan.contains(&step.target("C").name("dist-mingw")));
|
||||
assert!(!plan.contains(&step.target("C").name("dist-rustc")));
|
||||
assert!(plan.contains(&step.target("C").name("dist-std")));
|
||||
assert!(!plan.contains(&step.target("C").name("dist-src")));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dist_target_with_target_flag() {
|
||||
let build = build(&["dist", "--target=C"], &["B"], &["C"]);
|
||||
let rules = super::build_rules(&build);
|
||||
let plan = rules.plan();
|
||||
println!("rules: {:#?}", plan);
|
||||
assert!(plan.iter().all(|s| s.stage == 2));
|
||||
|
||||
let step = super::Step {
|
||||
name: "",
|
||||
stage: 2,
|
||||
host: &build.config.build,
|
||||
target: &build.config.build,
|
||||
};
|
||||
|
||||
assert!(!plan.iter().any(|s| s.target == "A"));
|
||||
assert!(!plan.iter().any(|s| s.target == "B"));
|
||||
assert!(!plan.iter().any(|s| s.host == "B"));
|
||||
assert!(!plan.iter().any(|s| s.host == "C"));
|
||||
|
||||
assert!(plan.contains(&step.target("C").name("dist-docs")));
|
||||
assert!(plan.contains(&step.target("C").name("dist-mingw")));
|
||||
assert!(!plan.contains(&step.target("C").name("dist-rustc")));
|
||||
assert!(plan.contains(&step.target("C").name("dist-std")));
|
||||
assert!(!plan.contains(&step.target("C").name("dist-src")));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dist_host_with_target_flag() {
|
||||
let build = build(&["dist", "--host=B", "--target=B"], &["B"], &["C"]);
|
||||
let rules = super::build_rules(&build);
|
||||
let plan = rules.plan();
|
||||
println!("rules: {:#?}", plan);
|
||||
assert!(plan.iter().all(|s| s.stage == 2));
|
||||
|
||||
let step = super::Step {
|
||||
name: "",
|
||||
stage: 2,
|
||||
host: &build.config.build,
|
||||
target: &build.config.build,
|
||||
};
|
||||
|
||||
assert!(!plan.iter().any(|s| s.target == "A"));
|
||||
assert!(!plan.iter().any(|s| s.target == "C"));
|
||||
assert!(!plan.iter().any(|s| s.host == "B"));
|
||||
assert!(!plan.iter().any(|s| s.host == "C"));
|
||||
|
||||
assert!(plan.contains(&step.target("B").name("dist-docs")));
|
||||
assert!(plan.contains(&step.target("B").name("dist-mingw")));
|
||||
assert!(plan.contains(&step.target("B").name("dist-rustc")));
|
||||
assert!(plan.contains(&step.target("B").name("dist-std")));
|
||||
assert!(plan.contains(&step.target("B").name("dist-src")));
|
||||
|
||||
let all = rules.expand(&plan);
|
||||
println!("all rules: {:#?}", all);
|
||||
assert!(!all.contains(&step.name("rustc")));
|
||||
assert!(!all.contains(&step.name("build-crate-std_shim").stage(1)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn build_default() {
|
||||
let build = build(&["build"], &["B"], &["C"]);
|
||||
let rules = super::build_rules(&build);
|
||||
let plan = rules.plan();
|
||||
println!("rules: {:#?}", plan);
|
||||
assert!(plan.iter().all(|s| s.stage == 2));
|
||||
|
||||
let step = super::Step {
|
||||
name: "",
|
||||
stage: 2,
|
||||
host: &build.config.build,
|
||||
target: &build.config.build,
|
||||
};
|
||||
|
||||
// rustc built for all for of (A, B) x (A, B)
|
||||
assert!(plan.contains(&step.name("librustc")));
|
||||
assert!(plan.contains(&step.target("B").name("librustc")));
|
||||
assert!(plan.contains(&step.host("B").target("A").name("librustc")));
|
||||
assert!(plan.contains(&step.host("B").target("B").name("librustc")));
|
||||
|
||||
// rustc never built for C
|
||||
assert!(!plan.iter().any(|s| {
|
||||
s.name.contains("rustc") && (s.host == "C" || s.target == "C")
|
||||
}));
|
||||
|
||||
// test built for everything
|
||||
assert!(plan.contains(&step.name("libtest")));
|
||||
assert!(plan.contains(&step.target("B").name("libtest")));
|
||||
assert!(plan.contains(&step.host("B").target("A").name("libtest")));
|
||||
assert!(plan.contains(&step.host("B").target("B").name("libtest")));
|
||||
assert!(plan.contains(&step.host("A").target("C").name("libtest")));
|
||||
assert!(plan.contains(&step.host("B").target("C").name("libtest")));
|
||||
|
||||
let all = rules.expand(&plan);
|
||||
println!("all rules: {:#?}", all);
|
||||
assert!(all.contains(&step.name("rustc")));
|
||||
assert!(all.contains(&step.name("libstd")));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn build_filtered() {
|
||||
let build = build(&["build", "--target=C"], &["B"], &["C"]);
|
||||
let rules = super::build_rules(&build);
|
||||
let plan = rules.plan();
|
||||
println!("rules: {:#?}", plan);
|
||||
assert!(plan.iter().all(|s| s.stage == 2));
|
||||
|
||||
assert!(!plan.iter().any(|s| s.name.contains("rustc")));
|
||||
assert!(plan.iter().all(|s| {
|
||||
!s.name.contains("test_shim") || s.target == "C"
|
||||
}));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_default() {
|
||||
let build = build(&["test"], &[], &[]);
|
||||
let rules = super::build_rules(&build);
|
||||
let plan = rules.plan();
|
||||
println!("rules: {:#?}", plan);
|
||||
assert!(plan.iter().all(|s| s.stage == 2));
|
||||
assert!(plan.iter().all(|s| s.host == "A"));
|
||||
assert!(plan.iter().all(|s| s.target == "A"));
|
||||
|
||||
assert!(plan.iter().any(|s| s.name.contains("-ui")));
|
||||
assert!(plan.iter().any(|s| s.name.contains("cfail")));
|
||||
assert!(plan.iter().any(|s| s.name.contains("cfail-full")));
|
||||
assert!(plan.iter().any(|s| s.name.contains("codegen-units")));
|
||||
assert!(plan.iter().any(|s| s.name.contains("debuginfo")));
|
||||
assert!(plan.iter().any(|s| s.name.contains("docs")));
|
||||
assert!(plan.iter().any(|s| s.name.contains("error-index")));
|
||||
assert!(plan.iter().any(|s| s.name.contains("incremental")));
|
||||
assert!(plan.iter().any(|s| s.name.contains("linkchecker")));
|
||||
assert!(plan.iter().any(|s| s.name.contains("mir-opt")));
|
||||
assert!(plan.iter().any(|s| s.name.contains("pfail")));
|
||||
assert!(plan.iter().any(|s| s.name.contains("rfail")));
|
||||
assert!(plan.iter().any(|s| s.name.contains("rfail-full")));
|
||||
assert!(plan.iter().any(|s| s.name.contains("rmake")));
|
||||
assert!(plan.iter().any(|s| s.name.contains("rpass")));
|
||||
assert!(plan.iter().any(|s| s.name.contains("rpass-full")));
|
||||
assert!(plan.iter().any(|s| s.name.contains("rustc-all")));
|
||||
assert!(plan.iter().any(|s| s.name.contains("rustdoc")));
|
||||
assert!(plan.iter().any(|s| s.name.contains("std-all")));
|
||||
assert!(plan.iter().any(|s| s.name.contains("test-all")));
|
||||
assert!(plan.iter().any(|s| s.name.contains("tidy")));
|
||||
assert!(plan.iter().any(|s| s.name.contains("valgrind")));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_with_a_target() {
|
||||
let build = build(&["test", "--target=C"], &[], &["C"]);
|
||||
let rules = super::build_rules(&build);
|
||||
let plan = rules.plan();
|
||||
println!("rules: {:#?}", plan);
|
||||
assert!(plan.iter().all(|s| s.stage == 2));
|
||||
assert!(plan.iter().all(|s| s.host == "A"));
|
||||
assert!(plan.iter().all(|s| s.target == "C"));
|
||||
|
||||
assert!(!plan.iter().any(|s| s.name.contains("-ui")));
|
||||
assert!(plan.iter().any(|s| s.name.contains("cfail")));
|
||||
assert!(!plan.iter().any(|s| s.name.contains("cfail-full")));
|
||||
assert!(plan.iter().any(|s| s.name.contains("codegen-units")));
|
||||
assert!(plan.iter().any(|s| s.name.contains("debuginfo")));
|
||||
assert!(!plan.iter().any(|s| s.name.contains("docs")));
|
||||
assert!(!plan.iter().any(|s| s.name.contains("error-index")));
|
||||
assert!(plan.iter().any(|s| s.name.contains("incremental")));
|
||||
assert!(!plan.iter().any(|s| s.name.contains("linkchecker")));
|
||||
assert!(plan.iter().any(|s| s.name.contains("mir-opt")));
|
||||
assert!(plan.iter().any(|s| s.name.contains("pfail")));
|
||||
assert!(plan.iter().any(|s| s.name.contains("rfail")));
|
||||
assert!(!plan.iter().any(|s| s.name.contains("rfail-full")));
|
||||
assert!(!plan.iter().any(|s| s.name.contains("rmake")));
|
||||
assert!(plan.iter().any(|s| s.name.contains("rpass")));
|
||||
assert!(!plan.iter().any(|s| s.name.contains("rpass-full")));
|
||||
assert!(!plan.iter().any(|s| s.name.contains("rustc-all")));
|
||||
assert!(!plan.iter().any(|s| s.name.contains("rustdoc")));
|
||||
assert!(plan.iter().any(|s| s.name.contains("std-all")));
|
||||
assert!(plan.iter().any(|s| s.name.contains("test-all")));
|
||||
assert!(!plan.iter().any(|s| s.name.contains("tidy")));
|
||||
assert!(plan.iter().any(|s| s.name.contains("valgrind")));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,4 +48,9 @@ ENV RUST_CONFIGURE_ARGS \
|
|||
--armv7-linux-androideabi-ndk=/android/ndk-arm-9 \
|
||||
--i686-linux-android-ndk=/android/ndk-x86-9 \
|
||||
--aarch64-linux-android-ndk=/android/ndk-aarch64
|
||||
ENV XPY_CHECK test --target arm-linux-androideabi
|
||||
|
||||
# Just a smoke test in dist to see if this works for now, we should expand this
|
||||
# to all the targets above eventually.
|
||||
ENV SCRIPT \
|
||||
python2.7 ../x.py test --target arm-linux-androideabi && \
|
||||
python2.7 ../x.py dist --target arm-linux-androideabi
|
||||
|
|
|
|||
|
|
@ -13,5 +13,4 @@ set -ex
|
|||
ANDROID_EMULATOR_FORCE_32BIT=true \
|
||||
nohup nohup emulator @arm-18 -no-window -partition-size 2047 \
|
||||
0<&- &>/dev/null &
|
||||
adb wait-for-device
|
||||
exec "$@"
|
||||
|
|
|
|||
|
|
@ -56,7 +56,12 @@ ENV TARGETS=$TARGETS,wasm32-unknown-emscripten
|
|||
ENV RUST_CONFIGURE_ARGS \
|
||||
--target=$TARGETS \
|
||||
--enable-rustbuild
|
||||
ENV RUST_CHECK_TARGET ""
|
||||
|
||||
# Just a smoke test in dist to see if this works for now, we should expand this
|
||||
# to all the targets above eventually.
|
||||
ENV SCRIPT \
|
||||
python2.7 ../x.py build && \
|
||||
python2.7 ../x.py dist --target wasm32-unknown-emscripten
|
||||
|
||||
ENV AR_s390x_unknown_linux_gnu=s390x-linux-gnu-ar \
|
||||
CC_s390x_unknown_linux_gnu=s390x-linux-gnu-gcc \
|
||||
|
|
|
|||
30
src/ci/docker/dist-arm-unknown-linux-gnueabi/Dockerfile
Normal file
30
src/ci/docker/dist-arm-unknown-linux-gnueabi/Dockerfile
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
FROM ubuntu:16.04
|
||||
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
g++ \
|
||||
make \
|
||||
file \
|
||||
curl \
|
||||
ca-certificates \
|
||||
python2.7 \
|
||||
git \
|
||||
cmake \
|
||||
sudo \
|
||||
gdb \
|
||||
xz-utils \
|
||||
g++-arm-linux-gnueabi
|
||||
|
||||
ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
|
||||
RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
|
||||
tar xJf - -C /usr/local/bin --strip-components=1
|
||||
|
||||
RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
|
||||
dpkg -i dumb-init_*.deb && \
|
||||
rm dumb-init_*.deb
|
||||
ENTRYPOINT ["/usr/bin/dumb-init", "--"]
|
||||
|
||||
ENV RUST_CONFIGURE_ARGS --host=arm-unknown-linux-gnueabi
|
||||
ENV SCRIPT \
|
||||
python2.7 ../x.py dist \
|
||||
--host arm-unknown-linux-gnueabi \
|
||||
--target arm-unknown-linux-gnueabi
|
||||
|
|
@ -28,7 +28,11 @@ RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST |
|
|||
|
||||
ENV \
|
||||
AR_x86_64_unknown_freebsd=x86_64-unknown-freebsd10-ar \
|
||||
CC_x86_64_unknown_freebsd=x86_64-unknown-freebsd10-gcc
|
||||
CC_x86_64_unknown_freebsd=x86_64-unknown-freebsd10-gcc \
|
||||
CXX_x86_64_unknown_freebsd=x86_64-unknown-freebsd10-g++
|
||||
|
||||
ENV RUST_CONFIGURE_ARGS --target=x86_64-unknown-freebsd
|
||||
ENV RUST_CHECK_TARGET ""
|
||||
ENV RUST_CONFIGURE_ARGS --host=x86_64-unknown-freebsd
|
||||
ENV SCRIPT \
|
||||
python2.7 ../x.py dist \
|
||||
--host x86_64-unknown-freebsd \
|
||||
--target x86_64-unknown-freebsd
|
||||
|
|
@ -77,7 +77,7 @@ cd gcc-$GCC
|
|||
mkdir ../gcc-build
|
||||
cd ../gcc-build
|
||||
../gcc-$GCC/configure \
|
||||
--enable-languages=c \
|
||||
--enable-languages=c,c++ \
|
||||
--target=$ARCH-unknown-freebsd10 \
|
||||
--disable-multilib \
|
||||
--disable-nls \
|
||||
|
|
@ -23,4 +23,4 @@ RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-ini
|
|||
ENTRYPOINT ["/usr/bin/dumb-init", "--"]
|
||||
|
||||
ENV RUST_CONFIGURE_ARGS --build=i686-unknown-linux-gnu
|
||||
ENV RUST_CHECK_TARGET check
|
||||
ENV SCRIPT python2.7 ../x.py test && python2.7 ../x.py dist
|
||||
|
|
|
|||
|
|
@ -48,7 +48,5 @@ exec docker \
|
|||
--env CARGO_HOME=/cargo \
|
||||
--env LOCAL_USER_ID=`id -u` \
|
||||
--volume "$HOME/.cargo:/cargo" \
|
||||
--interactive \
|
||||
--tty \
|
||||
rust-ci \
|
||||
/checkout/src/ci/run.sh
|
||||
|
|
|
|||
|
|
@ -26,4 +26,4 @@ ENV RUST_CONFIGURE_ARGS \
|
|||
--build=x86_64-unknown-linux-gnu \
|
||||
--enable-debug \
|
||||
--enable-optimize
|
||||
ENV RUST_CHECK_TARGET ""
|
||||
ENV SCRIPT python2.7 ../x.py build
|
||||
|
|
|
|||
|
|
@ -23,4 +23,4 @@ RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-ini
|
|||
ENTRYPOINT ["/usr/bin/dumb-init", "--"]
|
||||
|
||||
ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu
|
||||
ENV XPY_RUN test distcheck
|
||||
ENV SCRIPT python2.7 ../x.py test distcheck
|
||||
|
|
|
|||
|
|
@ -25,4 +25,4 @@ ENTRYPOINT ["/usr/bin/dumb-init", "--"]
|
|||
ENV RUST_CONFIGURE_ARGS \
|
||||
--build=x86_64-unknown-linux-gnu \
|
||||
--enable-full-bootstrap
|
||||
ENV RUST_CHECK_TARGET ""
|
||||
ENV SCRIPT python2.7 ../x.py build
|
||||
|
|
|
|||
|
|
@ -23,4 +23,4 @@ RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-ini
|
|||
ENTRYPOINT ["/usr/bin/dumb-init", "--"]
|
||||
|
||||
ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu
|
||||
ENV RUST_CHECK_TARGET check
|
||||
ENV SCRIPT python2.7 ../x.py test && python2.7 ../x.py dist
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST |
|
|||
ENV RUST_CONFIGURE_ARGS \
|
||||
--target=x86_64-unknown-linux-musl \
|
||||
--musl-root-x86_64=/musl-x86_64
|
||||
ENV RUST_CHECK_TARGET check-stage2-T-x86_64-unknown-linux-musl-H-x86_64-unknown-linux-gnu
|
||||
ENV PATH=$PATH:/musl-x86_64/bin
|
||||
ENV XPY_CHECK test --target x86_64-unknown-linux-musl
|
||||
ENV SCRIPT \
|
||||
python2.7 ../x.py test --target x86_64-unknown-linux-musl && \
|
||||
python2.7 ../x.py dist --target x86_64-unknown-linux-musl
|
||||
|
|
|
|||
|
|
@ -43,14 +43,10 @@ else
|
|||
ncpus=$(nproc)
|
||||
fi
|
||||
|
||||
if [ ! -z "$XPY_RUN" ]; then
|
||||
exec python2.7 $SRC/x.py $XPY_RUN
|
||||
if [ ! -z "$SCRIPT" ]; then
|
||||
sh -x -c "$SCRIPT"
|
||||
else
|
||||
make -j $ncpus tidy
|
||||
make -j $ncpus
|
||||
if [ ! -z "$XPY_CHECK" ]; then
|
||||
exec python2.7 $SRC/x.py $XPY_CHECK
|
||||
else
|
||||
exec make $RUST_CHECK_TARGET -j $ncpus
|
||||
fi
|
||||
make $RUST_CHECK_TARGET -j $ncpus
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@
|
|||
* [Borrow and AsRef](borrow-and-asref.md)
|
||||
* [Release Channels](release-channels.md)
|
||||
* [Using Rust without the standard library](using-rust-without-the-standard-library.md)
|
||||
* [Procedural Macros (and custom derive)](procedural-macros.md)
|
||||
* [Nightly Rust](nightly-rust.md)
|
||||
* [Compiler Plugins](compiler-plugins.md)
|
||||
* [Inline Assembly](inline-assembly.md)
|
||||
|
|
|
|||
|
|
@ -309,7 +309,7 @@ However it is often desired that the callback is targeted to a special
|
|||
Rust object. This could be the object that represents the wrapper for the
|
||||
respective C object.
|
||||
|
||||
This can be achieved by passing an raw pointer to the object down to the
|
||||
This can be achieved by passing a raw pointer to the object down to the
|
||||
C library. The C library can then include the pointer to the Rust object in
|
||||
the notification. This will allow the callback to unsafely access the
|
||||
referenced Rust object.
|
||||
|
|
|
|||
|
|
@ -16,15 +16,12 @@ and one for deallocation. A freestanding program that uses the `Box`
|
|||
sugar for dynamic allocations via `malloc` and `free`:
|
||||
|
||||
```rust,ignore
|
||||
#![feature(lang_items, box_syntax, start, libc)]
|
||||
#![feature(lang_items, box_syntax, start, libc, core_intrinsics)]
|
||||
#![no_std]
|
||||
use core::intrinsics;
|
||||
|
||||
extern crate libc;
|
||||
|
||||
extern {
|
||||
fn abort() -> !;
|
||||
}
|
||||
|
||||
#[lang = "owned_box"]
|
||||
pub struct Box<T>(*mut T);
|
||||
|
||||
|
|
@ -34,7 +31,7 @@ unsafe fn allocate(size: usize, _align: usize) -> *mut u8 {
|
|||
|
||||
// Check if `malloc` failed:
|
||||
if p as usize == 0 {
|
||||
abort();
|
||||
intrinsics::abort();
|
||||
}
|
||||
|
||||
p
|
||||
|
|
@ -58,7 +55,7 @@ fn main(argc: isize, argv: *const *const u8) -> isize {
|
|||
}
|
||||
|
||||
#[lang = "eh_personality"] extern fn rust_eh_personality() {}
|
||||
#[lang = "panic_fmt"] extern fn rust_begin_panic() -> ! { loop {} }
|
||||
#[lang = "panic_fmt"] extern fn rust_begin_panic() -> ! { unsafe { intrinsics::abort() } }
|
||||
# #[lang = "eh_unwind_resume"] extern fn rust_eh_unwind_resume() {}
|
||||
# #[no_mangle] pub extern fn rust_eh_register_frames () {}
|
||||
# #[no_mangle] pub extern fn rust_eh_unregister_frames () {}
|
||||
|
|
|
|||
|
|
@ -37,9 +37,10 @@ The function marked `#[start]` is passed the command line parameters
|
|||
in the same format as C:
|
||||
|
||||
```rust,ignore
|
||||
#![feature(lang_items)]
|
||||
#![feature(lang_items, core_intrinsics)]
|
||||
#![feature(start)]
|
||||
#![no_std]
|
||||
use core::intrinsics;
|
||||
|
||||
// Pull in the system libc library for what crt0.o likely requires.
|
||||
extern crate libc;
|
||||
|
|
@ -69,7 +70,7 @@ pub extern fn rust_eh_unwind_resume() {
|
|||
pub extern fn rust_begin_panic(_msg: core::fmt::Arguments,
|
||||
_file: &'static str,
|
||||
_line: u32) -> ! {
|
||||
loop {}
|
||||
unsafe { intrinsics::abort() }
|
||||
}
|
||||
```
|
||||
|
||||
|
|
@ -79,10 +80,11 @@ correct ABI and the correct name, which requires overriding the
|
|||
compiler's name mangling too:
|
||||
|
||||
```rust,ignore
|
||||
#![feature(lang_items)]
|
||||
#![feature(lang_items, core_intrinsics)]
|
||||
#![feature(start)]
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
use core::intrinsics;
|
||||
|
||||
// Pull in the system libc library for what crt0.o likely requires.
|
||||
extern crate libc;
|
||||
|
|
@ -112,7 +114,7 @@ pub extern fn rust_eh_unwind_resume() {
|
|||
pub extern fn rust_begin_panic(_msg: core::fmt::Arguments,
|
||||
_file: &'static str,
|
||||
_line: u32) -> ! {
|
||||
loop {}
|
||||
unsafe { intrinsics::abort() }
|
||||
}
|
||||
```
|
||||
|
||||
|
|
|
|||
213
src/doc/book/procedural-macros.md
Normal file
213
src/doc/book/procedural-macros.md
Normal file
|
|
@ -0,0 +1,213 @@
|
|||
% Procedural Macros (and custom Derive)
|
||||
|
||||
As you've seen throughout the rest of the book, Rust provides a mechanism
|
||||
called "derive" that lets you implement traits easily. For example,
|
||||
|
||||
```rust
|
||||
#[derive(Debug)]
|
||||
struct Point {
|
||||
x: i32,
|
||||
y: i32,
|
||||
}
|
||||
```
|
||||
|
||||
is a lot simpler than
|
||||
|
||||
```rust
|
||||
struct Point {
|
||||
x: i32,
|
||||
y: i32,
|
||||
}
|
||||
|
||||
use std::fmt;
|
||||
|
||||
impl fmt::Debug for Point {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "Point {{ x: {}, y: {} }}", self.x, self.y)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Rust includes several traits that you can derive, but it also lets you define
|
||||
your own. We can accomplish this task through a feature of Rust called
|
||||
"procedural macros." Eventually, procedural macros will allow for all sorts of
|
||||
advanced metaprogramming in Rust, but today, they're only for custom derive.
|
||||
|
||||
Let's build a very simple trait, and derive it with custom derive.
|
||||
|
||||
## Hello World
|
||||
|
||||
So the first thing we need to do is start a new crate for our project.
|
||||
|
||||
```bash
|
||||
$ cargo new --bin hello-world
|
||||
```
|
||||
|
||||
All we want is to be able to call `hello_world()` on a derived type. Something
|
||||
like this:
|
||||
|
||||
```rust,ignore
|
||||
#[derive(HelloWorld)]
|
||||
struct Pancakes;
|
||||
|
||||
fn main() {
|
||||
Pancakes::hello_world();
|
||||
}
|
||||
```
|
||||
|
||||
With some kind of nice output, like `Hello, World! My name is Pancakes.`.
|
||||
|
||||
Let's go ahead and write up what we think our macro will look like from a user
|
||||
perspective. In `src/main.rs` we write:
|
||||
|
||||
```rust,ignore
|
||||
#[macro_use]
|
||||
extern crate hello_world_derive;
|
||||
|
||||
trait HelloWorld {
|
||||
fn hello_world();
|
||||
}
|
||||
|
||||
#[derive(HelloWorld)]
|
||||
struct FrenchToast;
|
||||
|
||||
#[derive(HelloWorld)]
|
||||
struct Waffles;
|
||||
|
||||
fn main() {
|
||||
FrenchToast::hello_world();
|
||||
Waffles::hello_world();
|
||||
}
|
||||
```
|
||||
|
||||
Great. So now we just need to actually write the procedural macro. At the
|
||||
moment, procedural macros need to be in their own crate. Eventually, this
|
||||
restriction may be lifted, but for now, it's required. As such, there's a
|
||||
convention; for a crate named `foo`, a custom derive procedural macro is called
|
||||
`foo-derive`. Let's start a new crate called `hello-world-derive` inside our
|
||||
`hello-world` project.
|
||||
|
||||
```bash
|
||||
$ cargo new hello-world-derive
|
||||
```
|
||||
|
||||
To make sure that our `hello-world` crate is able to find this new crate we've
|
||||
created, we'll add it to our toml:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
hello-world-derive = { path = "hello-world-derive" }
|
||||
```
|
||||
|
||||
As for our the source of our `hello-world-derive` crate, here's an example:
|
||||
|
||||
```rust,ignore
|
||||
extern crate proc_macro;
|
||||
extern crate syn;
|
||||
#[macro_use]
|
||||
extern crate quote;
|
||||
|
||||
use proc_macro::TokenStream;
|
||||
|
||||
#[proc_macro_derive(HelloWorld)]
|
||||
pub fn hello_world(input: TokenStream) -> TokenStream {
|
||||
// Construct a string representation of the type definition
|
||||
let s = input.to_string();
|
||||
|
||||
// Parse the string representation
|
||||
let ast = syn::parse_macro_input(&s).unwrap();
|
||||
|
||||
// Build the impl
|
||||
let gen = impl_hello_world(&ast);
|
||||
|
||||
// Return the generated impl
|
||||
gen.parse().unwrap()
|
||||
}
|
||||
```
|
||||
|
||||
So there is a lot going on here. We have introduced two new crates: [`syn`] and
|
||||
[`quote`]. As you may have noticed, `input: TokenSteam` is immediately converted
|
||||
to a `String`. This `String` is a string representation of the Rust code for which
|
||||
we are deriving `HelloWorld` for. At the moment, the only thing you can do with a
|
||||
`TokenStream` is convert it to a string. A richer API will exist in the future.
|
||||
|
||||
So what we really need is to be able to _parse_ Rust code into something
|
||||
usable. This is where `syn` comes to play. `syn` is a crate for parsing Rust
|
||||
code. The other crate we've introduced is `quote`. It's essentially the dual of
|
||||
`syn` as it will make generating Rust code really easy. We could write this
|
||||
stuff on our own, but it's much simpler to use these libraries. Writing a full
|
||||
parser for Rust code is no simple task.
|
||||
|
||||
[`syn`]: https://crates.io/crates/syn
|
||||
[`quote`]: https://crates.io/crates/quote
|
||||
|
||||
The comments seem to give us a pretty good idea of our overall strategy. We
|
||||
are going to take a `String` of the Rust code for the type we are deriving, parse
|
||||
it using `syn`, construct the implementation of `hello_world` (using `quote`),
|
||||
then pass it back to Rust compiler.
|
||||
|
||||
One last note: you'll see some `unwrap()`s there. If you want to provide an
|
||||
error for a procedural macro, then you should `panic!` with the error message.
|
||||
In this case, we're keeping it as simple as possible.
|
||||
|
||||
Great, so let's write `impl_hello_world(&ast)`.
|
||||
|
||||
```rust,ignore
|
||||
fn impl_hello_world(ast: &syn::MacroInput) -> quote::Tokens {
|
||||
let name = &ast.ident;
|
||||
quote! {
|
||||
impl HelloWorld for #name {
|
||||
fn hello_world() {
|
||||
println!("Hello, World! My name is {}", stringify!(#name));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
So this is where quotes comes in. The `ast` argument is a struct that gives us
|
||||
a representation of our type (which can be either a `struct` or an `enum`).
|
||||
Check out the [docs](https://docs.rs/syn/0.10.5/syn/struct.MacroInput.html),
|
||||
there is some useful information there. We are able to get the name of the
|
||||
type using `ast.ident`. The `quote!` macro let's us write up the Rust code
|
||||
that we wish to return and convert it into `Tokens`. `quote!` let's us use some
|
||||
really cool templating mechanics; we simply write `#name` and `quote!` will
|
||||
replace it with the variable named `name`. You can even do some repetition
|
||||
similar to regular macros work. You should check out the
|
||||
[docs](https://docs.rs/quote) for a good introduction.
|
||||
|
||||
So I think that's it. Oh, well, we do need to add dependencies for `syn` and
|
||||
`quote` in the `cargo.toml` for `hello-world-derive`.
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
syn = "0.10.5"
|
||||
quote = "0.3.10"
|
||||
```
|
||||
|
||||
That should be it. Let's try to compile `hello-world`.
|
||||
|
||||
```bash
|
||||
error: the `#[proc_macro_derive]` attribute is only usable with crates of the `proc-macro` crate type
|
||||
--> hello-world-derive/src/lib.rs:8:3
|
||||
|
|
||||
8 | #[proc_macro_derive(HelloWorld)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
```
|
||||
|
||||
Oh, so it appears that we need to declare that our `hello-world-derive` crate is
|
||||
a `proc-macro` crate type. How do we do this? Like this:
|
||||
|
||||
```toml
|
||||
[lib]
|
||||
proc-macro = true
|
||||
```
|
||||
|
||||
Ok so now, let's compile `hello-world`. Executing `cargo run` now yields:
|
||||
|
||||
```bash
|
||||
Hello, World! My name is FrenchToast
|
||||
Hello, World! My name is Waffles
|
||||
```
|
||||
|
||||
We've done it!
|
||||
|
|
@ -163,8 +163,8 @@ let hachi = &dog[0..2];
|
|||
with this error:
|
||||
|
||||
```text
|
||||
thread 'main' panicked at 'index 0 and/or 2 in `忠犬ハチ公` do not lie on
|
||||
character boundary'
|
||||
thread 'main' panicked at 'byte index 2 is not a char boundary; it is inside '忠'
|
||||
(bytes 0..3) of `忠犬ハチ公`'
|
||||
```
|
||||
|
||||
## Concatenation
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ Coercion is allowed between the following types:
|
|||
* `&T` to `*const T`
|
||||
* `&mut T` to `*mut T`
|
||||
* Unsizing: `T` to `U` if `T` implements `CoerceUnsized<U>`
|
||||
* Deref coercion: Expression `&x` of type `&T` to `&*x` of type `&U` if `T` derefs to `U` (i.e. `T: Deref<Target=U>`)
|
||||
|
||||
`CoerceUnsized<Pointer<U>> for Pointer<T> where T: Unsize<U>` is implemented
|
||||
for all pointer types (including smart pointers like Box and Rc). Unsize is
|
||||
|
|
@ -27,8 +28,9 @@ only implemented automatically, and enables the following transformations:
|
|||
* `Foo<..., T, ...>` => `Foo<..., U, ...>` where:
|
||||
* `T: Unsize<U>`
|
||||
* `Foo` is a struct
|
||||
* Only the last field of `Foo` has type `T`
|
||||
* Only the last field of `Foo` has type involving `T`
|
||||
* `T` is not part of the type of any other fields
|
||||
* `Bar<T>: Unsize<Bar<U>>`, if the last field of `Foo` has type `Bar<T>`
|
||||
|
||||
Coercions occur at a *coercion site*. Any location that is explicitly typed
|
||||
will cause a coercion to its type. If inference is necessary, the coercion will
|
||||
|
|
|
|||
|
|
@ -125,7 +125,7 @@ is that some Drop implementations will not access borrowed data even
|
|||
though their type gives them the capability for such access.
|
||||
|
||||
For example, this variant of the above `Inspector` example will never
|
||||
accessed borrowed data:
|
||||
access borrowed data:
|
||||
|
||||
```rust,ignore
|
||||
struct Inspector<'a>(&'a u8, &'static str);
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ lifetime can be regarded as `'static`.
|
|||
|
||||
Almost no reference is `'static`, so this is probably wrong. `transmute` and
|
||||
`transmute_copy` are the two other primary offenders. One should endeavor to
|
||||
bound an unbounded lifetime as quick as possible, especially across function
|
||||
bound an unbounded lifetime as quickly as possible, especially across function
|
||||
boundaries.
|
||||
|
||||
Given a function, any output lifetimes that don't derive from inputs are
|
||||
|
|
|
|||
|
|
@ -555,26 +555,24 @@ mod a {
|
|||
# fn main() {}
|
||||
```
|
||||
|
||||
# Syntax extensions
|
||||
# Macros
|
||||
|
||||
A number of minor features of Rust are not central enough to have their own
|
||||
syntax, and yet are not implementable as functions. Instead, they are given
|
||||
names, and invoked through a consistent syntax: `some_extension!(...)`.
|
||||
|
||||
Users of `rustc` can define new syntax extensions in two ways:
|
||||
|
||||
* [Compiler plugins][plugin] can include arbitrary Rust code that
|
||||
manipulates syntax trees at compile time. Note that the interface
|
||||
for compiler plugins is considered highly unstable.
|
||||
Users of `rustc` can define new macros in two ways:
|
||||
|
||||
* [Macros](book/macros.html) define new syntax in a higher-level,
|
||||
declarative way.
|
||||
* [Procedural Macros][procedural macros] can be used to implement custom derive.
|
||||
|
||||
And one unstable way: [compiler plugins][plugin].
|
||||
|
||||
## Macros
|
||||
|
||||
`macro_rules` allows users to define syntax extension in a declarative way. We
|
||||
call such extensions "macros by example" or simply "macros" — to be distinguished
|
||||
from the "procedural macros" defined in [compiler plugins][plugin].
|
||||
call such extensions "macros by example" or simply "macros".
|
||||
|
||||
Currently, macros can expand to expressions, statements, items, or patterns.
|
||||
|
||||
|
|
@ -652,6 +650,28 @@ Rust syntax is restricted in two ways:
|
|||
|
||||
[RFC 550]: https://github.com/rust-lang/rfcs/blob/master/text/0550-macro-future-proofing.md
|
||||
|
||||
## Procedrual Macros
|
||||
|
||||
"Procedrual macros" are the second way to implement a macro. For now, the only
|
||||
thing they can be used for is to implement derive on your own types. See
|
||||
[the book][procedural macros] for a tutorial.
|
||||
|
||||
Procedural macros involve a few different parts of the language and its
|
||||
standard libraries. First is the `proc_macro` crate, included with Rust,
|
||||
that defines an interface for building a procedrual macro. The
|
||||
`#[proc_macro_derive(Foo)]` attribute is used to mark the the deriving
|
||||
function. This function must have the type signature:
|
||||
|
||||
```rust,ignore
|
||||
use proc_macro::TokenStream;
|
||||
|
||||
#[proc_macro_derive(Hello)]
|
||||
pub fn hello_world(input: TokenStream) -> TokenStream
|
||||
```
|
||||
|
||||
Finally, procedural macros must be in their own crate, with the `proc-macro`
|
||||
crate type.
|
||||
|
||||
# Crates and source files
|
||||
|
||||
Although Rust, like any other language, can be implemented by an interpreter as
|
||||
|
|
@ -2319,6 +2339,9 @@ impl<T: PartialEq> PartialEq for Foo<T> {
|
|||
}
|
||||
```
|
||||
|
||||
You can implement `derive` for your own type through [procedural
|
||||
macros](#procedural-macros).
|
||||
|
||||
### Compiler Features
|
||||
|
||||
Certain aspects of Rust may be implemented in the compiler, but they're not
|
||||
|
|
@ -4122,6 +4145,16 @@ be ignored in favor of only building the artifacts specified by command line.
|
|||
in dynamic libraries. This form of output is used to produce statically linked
|
||||
executables as well as `staticlib` outputs.
|
||||
|
||||
* `--crate-type=proc-macro`, `#[crate_type = "proc-macro"]` - The output
|
||||
produced is not specified, but if a `-L` path is provided to it then the
|
||||
compiler will recognize the output artifacts as a macro and it can be loaded
|
||||
for a program. If a crate is compiled with the `proc-macro` crate type it
|
||||
will forbid exporting any items in the crate other than those functions
|
||||
tagged `#[proc_macro_derive]` and those functions must also be placed at the
|
||||
crate root. Finally, the compiler will automatically set the
|
||||
`cfg(proc_macro)` annotation whenever any crate type of a compilation is the
|
||||
`proc-macro` crate type.
|
||||
|
||||
Note that these outputs are stackable in the sense that if multiple are
|
||||
specified, then the compiler will produce each form of output at once without
|
||||
having to recompile. However, this only applies for outputs specified by the
|
||||
|
|
@ -4299,3 +4332,4 @@ that have since been removed):
|
|||
|
||||
[ffi]: book/ffi.html
|
||||
[plugin]: book/compiler-plugins.html
|
||||
[procedural macros]: book/procedural-macros.html
|
||||
|
|
|
|||
|
|
@ -23,10 +23,7 @@
|
|||
# Since this should not require frequent updates, we just store this
|
||||
# out-of-line and check the unicode.rs file into git.
|
||||
|
||||
import fileinput, re, os, sys, operator
|
||||
|
||||
bytes_old = 0
|
||||
bytes_new = 0
|
||||
import fileinput, re, os, sys, operator, math
|
||||
|
||||
preamble = '''// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
|
|
@ -362,7 +359,23 @@ fn trie_lookup_range_table(c: char, r: &'static BoolTrie) -> bool {
|
|||
let leaf = r.r5[((child as usize) << 6) + ((c >> 6) & 0x3f)];
|
||||
trie_range_leaf(c, r.r6[leaf as usize])
|
||||
}
|
||||
}\n
|
||||
}
|
||||
|
||||
pub struct SmallBoolTrie {
|
||||
r1: &'static [u8], // first level
|
||||
r2: &'static [u64], // leaves
|
||||
}
|
||||
|
||||
impl SmallBoolTrie {
|
||||
fn lookup(&self, c: char) -> bool {
|
||||
let c = c as usize;
|
||||
match self.r1.get(c >> 6) {
|
||||
Some(&child) => trie_range_leaf(c, self.r2[child as usize]),
|
||||
None => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
""")
|
||||
|
||||
def compute_trie(rawdata, chunksize):
|
||||
|
|
@ -379,8 +392,6 @@ def compute_trie(rawdata, chunksize):
|
|||
return (root, child_data)
|
||||
|
||||
def emit_bool_trie(f, name, t_data, is_pub=True):
|
||||
global bytes_old, bytes_new
|
||||
bytes_old += 8 * len(t_data)
|
||||
CHUNK = 64
|
||||
rawdata = [False] * 0x110000
|
||||
for (lo, hi) in t_data:
|
||||
|
|
@ -433,15 +444,50 @@ def emit_bool_trie(f, name, t_data, is_pub=True):
|
|||
f.write("\n ],\n")
|
||||
|
||||
f.write(" };\n\n")
|
||||
bytes_new += 256 + 992 + 256 + 8 * len(r3) + len(r5) + 8 * len(r6)
|
||||
|
||||
def emit_small_bool_trie(f, name, t_data, is_pub=True):
|
||||
last_chunk = max(int(hi / 64) for (lo, hi) in t_data)
|
||||
n_chunks = last_chunk + 1
|
||||
chunks = [0] * n_chunks
|
||||
for (lo, hi) in t_data:
|
||||
for cp in range(lo, hi + 1):
|
||||
if int(cp / 64) >= len(chunks):
|
||||
print(cp, int(cp / 64), len(chunks), lo, hi)
|
||||
chunks[int(cp / 64)] |= 1 << (cp & 63)
|
||||
|
||||
pub_string = ""
|
||||
if is_pub:
|
||||
pub_string = "pub "
|
||||
f.write(" %sconst %s: &'static super::SmallBoolTrie = &super::SmallBoolTrie {\n"
|
||||
% (pub_string, name))
|
||||
|
||||
(r1, r2) = compute_trie(chunks, 1)
|
||||
|
||||
f.write(" r1: &[\n")
|
||||
data = ','.join(str(node) for node in r1)
|
||||
format_table_content(f, data, 12)
|
||||
f.write("\n ],\n")
|
||||
|
||||
f.write(" r2: &[\n")
|
||||
data = ','.join('0x%016x' % node for node in r2)
|
||||
format_table_content(f, data, 12)
|
||||
f.write("\n ],\n")
|
||||
|
||||
f.write(" };\n\n")
|
||||
|
||||
def emit_property_module(f, mod, tbl, emit):
|
||||
f.write("pub mod %s {\n" % mod)
|
||||
for cat in sorted(emit):
|
||||
emit_bool_trie(f, "%s_table" % cat, tbl[cat])
|
||||
f.write(" pub fn %s(c: char) -> bool {\n" % cat)
|
||||
f.write(" super::trie_lookup_range_table(c, %s_table)\n" % cat)
|
||||
f.write(" }\n\n")
|
||||
if cat in ["Cc", "White_Space", "Pattern_White_Space"]:
|
||||
emit_small_bool_trie(f, "%s_table" % cat, tbl[cat])
|
||||
f.write(" pub fn %s(c: char) -> bool {\n" % cat)
|
||||
f.write(" %s_table.lookup(c)\n" % cat)
|
||||
f.write(" }\n\n")
|
||||
else:
|
||||
emit_bool_trie(f, "%s_table" % cat, tbl[cat])
|
||||
f.write(" pub fn %s(c: char) -> bool {\n" % cat)
|
||||
f.write(" super::trie_lookup_range_table(c, %s_table)\n" % cat)
|
||||
f.write(" }\n\n")
|
||||
f.write("}\n\n")
|
||||
|
||||
def emit_conversions_module(f, to_upper, to_lower, to_title):
|
||||
|
|
@ -543,4 +589,3 @@ pub const UNICODE_VERSION: (u64, u64, u64) = (%s, %s, %s);
|
|||
# normalizations and conversions module
|
||||
emit_norm_module(rf, canon_decomp, compat_decomp, combines, norm_props)
|
||||
emit_conversions_module(rf, to_upper, to_lower, to_title)
|
||||
#print 'bytes before = %d, bytes after = %d' % (bytes_old, bytes_new)
|
||||
|
|
|
|||
|
|
@ -708,7 +708,7 @@ impl<T: ?Sized> Arc<T> {
|
|||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: ?Sized> Drop for Arc<T> {
|
||||
unsafe impl<#[may_dangle] T: ?Sized> Drop for Arc<T> {
|
||||
/// Drops the `Arc`.
|
||||
///
|
||||
/// This will decrement the strong reference count. If the strong reference
|
||||
|
|
@ -736,7 +736,6 @@ impl<T: ?Sized> Drop for Arc<T> {
|
|||
/// drop(foo); // Doesn't print anything
|
||||
/// drop(foo2); // Prints "dropped!"
|
||||
/// ```
|
||||
#[unsafe_destructor_blind_to_params]
|
||||
#[inline]
|
||||
fn drop(&mut self) {
|
||||
// Because `fetch_sub` is already atomic, we do not need to synchronize
|
||||
|
|
|
|||
|
|
@ -587,7 +587,7 @@ impl<I: FusedIterator + ?Sized> FusedIterator for Box<I> {}
|
|||
/// ```
|
||||
#[rustc_paren_sugar]
|
||||
#[unstable(feature = "fnbox",
|
||||
reason = "will be deprecated if and when Box<FnOnce> becomes usable", issue = "28796")]
|
||||
reason = "will be deprecated if and when `Box<FnOnce>` becomes usable", issue = "28796")]
|
||||
pub trait FnBox<A> {
|
||||
type Output;
|
||||
|
||||
|
|
@ -595,7 +595,7 @@ pub trait FnBox<A> {
|
|||
}
|
||||
|
||||
#[unstable(feature = "fnbox",
|
||||
reason = "will be deprecated if and when Box<FnOnce> becomes usable", issue = "28796")]
|
||||
reason = "will be deprecated if and when `Box<FnOnce>` becomes usable", issue = "28796")]
|
||||
impl<A, F> FnBox<A> for F
|
||||
where F: FnOnce<A>
|
||||
{
|
||||
|
|
@ -607,7 +607,7 @@ impl<A, F> FnBox<A> for F
|
|||
}
|
||||
|
||||
#[unstable(feature = "fnbox",
|
||||
reason = "will be deprecated if and when Box<FnOnce> becomes usable", issue = "28796")]
|
||||
reason = "will be deprecated if and when `Box<FnOnce>` becomes usable", issue = "28796")]
|
||||
impl<'a, A, R> FnOnce<A> for Box<FnBox<A, Output = R> + 'a> {
|
||||
type Output = R;
|
||||
|
||||
|
|
@ -617,7 +617,7 @@ impl<'a, A, R> FnOnce<A> for Box<FnBox<A, Output = R> + 'a> {
|
|||
}
|
||||
|
||||
#[unstable(feature = "fnbox",
|
||||
reason = "will be deprecated if and when Box<FnOnce> becomes usable", issue = "28796")]
|
||||
reason = "will be deprecated if and when `Box<FnOnce>` becomes usable", issue = "28796")]
|
||||
impl<'a, A, R> FnOnce<A> for Box<FnBox<A, Output = R> + Send + 'a> {
|
||||
type Output = R;
|
||||
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@
|
|||
test(no_crate_inject, attr(allow(unused_variables), deny(warnings))))]
|
||||
#![no_std]
|
||||
#![needs_allocator]
|
||||
#![cfg_attr(not(stage0), deny(warnings))]
|
||||
#![deny(warnings)]
|
||||
|
||||
#![feature(allocator)]
|
||||
#![feature(box_syntax)]
|
||||
|
|
@ -79,9 +79,10 @@
|
|||
#![feature(const_fn)]
|
||||
#![feature(core_intrinsics)]
|
||||
#![feature(custom_attribute)]
|
||||
#![feature(dropck_parametricity)]
|
||||
#![feature(dropck_eyepatch)]
|
||||
#![cfg_attr(not(test), feature(exact_size_is_empty))]
|
||||
#![feature(fundamental)]
|
||||
#![feature(generic_param_attrs)]
|
||||
#![feature(lang_items)]
|
||||
#![feature(needs_allocator)]
|
||||
#![feature(optin_builtin_traits)]
|
||||
|
|
|
|||
|
|
@ -539,8 +539,7 @@ impl<T> RawVec<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T> Drop for RawVec<T> {
|
||||
#[unsafe_destructor_blind_to_params]
|
||||
unsafe impl<#[may_dangle] T> Drop for RawVec<T> {
|
||||
/// Frees the memory owned by the RawVec *without* trying to Drop its contents.
|
||||
fn drop(&mut self) {
|
||||
let elem_size = mem::size_of::<T>();
|
||||
|
|
|
|||
|
|
@ -644,7 +644,7 @@ impl<T: ?Sized> Deref for Rc<T> {
|
|||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: ?Sized> Drop for Rc<T> {
|
||||
unsafe impl<#[may_dangle] T: ?Sized> Drop for Rc<T> {
|
||||
/// Drops the `Rc`.
|
||||
///
|
||||
/// This will decrement the strong reference count. If the strong reference
|
||||
|
|
@ -672,7 +672,6 @@ impl<T: ?Sized> Drop for Rc<T> {
|
|||
/// drop(foo); // Doesn't print anything
|
||||
/// drop(foo2); // Prints "dropped!"
|
||||
/// ```
|
||||
#[unsafe_destructor_blind_to_params]
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
let ptr = *self.ptr;
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
reason = "this library is unlikely to be stabilized in its current \
|
||||
form or name",
|
||||
issue = "27783")]
|
||||
#![cfg_attr(not(stage0), deny(warnings))]
|
||||
#![deny(warnings)]
|
||||
#![feature(allocator)]
|
||||
#![feature(libc)]
|
||||
#![feature(staged_api)]
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
#![crate_type = "rlib"]
|
||||
#![no_std]
|
||||
#![allocator]
|
||||
#![cfg_attr(not(stage0), deny(warnings))]
|
||||
#![deny(warnings)]
|
||||
#![unstable(feature = "alloc_system",
|
||||
reason = "this library is unlikely to be stabilized in its current \
|
||||
form or name",
|
||||
|
|
|
|||
|
|
@ -26,14 +26,14 @@
|
|||
html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
|
||||
html_root_url = "https://doc.rust-lang.org/nightly/",
|
||||
test(no_crate_inject, attr(deny(warnings))))]
|
||||
#![cfg_attr(not(stage0), deny(warnings))]
|
||||
#![deny(warnings)]
|
||||
|
||||
#![feature(alloc)]
|
||||
#![feature(core_intrinsics)]
|
||||
#![feature(dropck_eyepatch)]
|
||||
#![feature(heap_api)]
|
||||
#![feature(heap_api)]
|
||||
#![feature(generic_param_attrs)]
|
||||
#![feature(staged_api)]
|
||||
#![feature(dropck_parametricity)]
|
||||
#![cfg_attr(test, feature(test))]
|
||||
|
||||
#![allow(deprecated)]
|
||||
|
|
@ -258,8 +258,7 @@ impl<T> TypedArena<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T> Drop for TypedArena<T> {
|
||||
#[unsafe_destructor_blind_to_params]
|
||||
unsafe impl<#[may_dangle] T> Drop for TypedArena<T> {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
// Determine how much was filled.
|
||||
|
|
|
|||
|
|
@ -153,8 +153,7 @@
|
|||
|
||||
use core::ops::{Deref, DerefMut};
|
||||
use core::iter::{FromIterator, FusedIterator};
|
||||
use core::mem::swap;
|
||||
use core::mem::size_of;
|
||||
use core::mem::{swap, size_of};
|
||||
use core::ptr;
|
||||
use core::fmt;
|
||||
|
||||
|
|
@ -226,12 +225,15 @@ pub struct BinaryHeap<T> {
|
|||
#[stable(feature = "binary_heap_peek_mut", since = "1.12.0")]
|
||||
pub struct PeekMut<'a, T: 'a + Ord> {
|
||||
heap: &'a mut BinaryHeap<T>,
|
||||
sift: bool,
|
||||
}
|
||||
|
||||
#[stable(feature = "binary_heap_peek_mut", since = "1.12.0")]
|
||||
impl<'a, T: Ord> Drop for PeekMut<'a, T> {
|
||||
fn drop(&mut self) {
|
||||
self.heap.sift_down(0);
|
||||
if self.sift {
|
||||
self.heap.sift_down(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -250,6 +252,16 @@ impl<'a, T: Ord> DerefMut for PeekMut<'a, T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Ord> PeekMut<'a, T> {
|
||||
/// Removes the peeked value from the heap and returns it.
|
||||
#[unstable(feature = "binary_heap_peek_mut_pop", issue = "38863")]
|
||||
pub fn pop(mut this: PeekMut<'a, T>) -> T {
|
||||
let value = this.heap.pop().unwrap();
|
||||
this.sift = false;
|
||||
value
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: Clone> Clone for BinaryHeap<T> {
|
||||
fn clone(&self) -> Self {
|
||||
|
|
@ -385,7 +397,10 @@ impl<T: Ord> BinaryHeap<T> {
|
|||
if self.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(PeekMut { heap: self })
|
||||
Some(PeekMut {
|
||||
heap: self,
|
||||
sift: true,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -137,8 +137,7 @@ pub struct BTreeMap<K, V> {
|
|||
}
|
||||
|
||||
#[stable(feature = "btree_drop", since = "1.7.0")]
|
||||
impl<K, V> Drop for BTreeMap<K, V> {
|
||||
#[unsafe_destructor_blind_to_params]
|
||||
unsafe impl<#[may_dangle] K, #[may_dangle] V> Drop for BTreeMap<K, V> {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
for _ in ptr::read(self).into_iter() {
|
||||
|
|
@ -1991,11 +1990,11 @@ impl<'a, K: Ord, V> Entry<'a, K, V> {
|
|||
/// use std::collections::BTreeMap;
|
||||
///
|
||||
/// let mut map: BTreeMap<&str, String> = BTreeMap::new();
|
||||
/// let s = "hoho".to_owned();
|
||||
/// let s = "hoho".to_string();
|
||||
///
|
||||
/// map.entry("poneyland").or_insert_with(|| s);
|
||||
///
|
||||
/// assert_eq!(map["poneyland"], "hoho".to_owned());
|
||||
/// assert_eq!(map["poneyland"], "hoho".to_string());
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn or_insert_with<F: FnOnce() -> V>(self, default: F) -> &'a mut V {
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@
|
|||
test(no_crate_inject, attr(allow(unused_variables), deny(warnings))))]
|
||||
|
||||
#![cfg_attr(test, allow(deprecated))] // rand
|
||||
#![cfg_attr(not(stage0), deny(warnings))]
|
||||
#![deny(warnings)]
|
||||
|
||||
#![feature(alloc)]
|
||||
#![feature(allow_internal_unstable)]
|
||||
|
|
@ -35,16 +35,18 @@
|
|||
#![feature(box_syntax)]
|
||||
#![cfg_attr(not(test), feature(char_escape_debug))]
|
||||
#![feature(core_intrinsics)]
|
||||
#![feature(dropck_parametricity)]
|
||||
#![feature(dropck_eyepatch)]
|
||||
#![feature(exact_size_is_empty)]
|
||||
#![feature(fmt_internals)]
|
||||
#![feature(fused)]
|
||||
#![feature(generic_param_attrs)]
|
||||
#![feature(heap_api)]
|
||||
#![feature(inclusive_range)]
|
||||
#![feature(lang_items)]
|
||||
#![feature(nonzero)]
|
||||
#![feature(pattern)]
|
||||
#![feature(placement_in)]
|
||||
#![feature(placement_in_syntax)]
|
||||
#![feature(placement_new_protocol)]
|
||||
#![feature(shared)]
|
||||
#![feature(slice_get_slice)]
|
||||
|
|
|
|||
|
|
@ -726,8 +726,7 @@ impl<T> LinkedList<T> {
|
|||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T> Drop for LinkedList<T> {
|
||||
#[unsafe_destructor_blind_to_params]
|
||||
unsafe impl<#[may_dangle] T> Drop for LinkedList<T> {
|
||||
fn drop(&mut self) {
|
||||
while let Some(_) = self.pop_front_node() {}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -423,7 +423,7 @@ impl<T> [T] {
|
|||
core_slice::SliceExt::get_unchecked_mut(self, index)
|
||||
}
|
||||
|
||||
/// Returns an raw pointer to the slice's buffer.
|
||||
/// Returns a raw pointer to the slice's buffer.
|
||||
///
|
||||
/// The caller must ensure that the slice outlives the pointer this
|
||||
/// function returns, or else it will end up pointing to garbage.
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ use core::hash::{self, Hash};
|
|||
use core::intrinsics::{arith_offset, assume};
|
||||
use core::iter::{FromIterator, FusedIterator, TrustedLen};
|
||||
use core::mem;
|
||||
use core::ops::{Index, IndexMut};
|
||||
use core::ops::{InPlace, Index, IndexMut, Place, Placer};
|
||||
use core::ops;
|
||||
use core::ptr;
|
||||
use core::ptr::Shared;
|
||||
|
|
@ -370,7 +370,8 @@ impl<T> Vec<T> {
|
|||
/// * `capacity` needs to be the capacity that the pointer was allocated with.
|
||||
///
|
||||
/// Violating these may cause problems like corrupting the allocator's
|
||||
/// internal datastructures.
|
||||
/// internal datastructures. For example it is **not** safe
|
||||
/// to build a `Vec<u8>` from a pointer to a C `char` array and a `size_t`.
|
||||
///
|
||||
/// The ownership of `ptr` is effectively transferred to the
|
||||
/// `Vec<T>` which may then deallocate, reallocate or change the
|
||||
|
|
@ -1246,6 +1247,29 @@ impl<T: Clone> Vec<T> {
|
|||
pub fn extend_from_slice(&mut self, other: &[T]) {
|
||||
self.spec_extend(other.iter())
|
||||
}
|
||||
|
||||
/// Returns a place for insertion at the back of the `Vec`.
|
||||
///
|
||||
/// Using this method with placement syntax is equivalent to [`push`](#method.push),
|
||||
/// but may be more efficient.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(collection_placement)]
|
||||
/// #![feature(placement_in_syntax)]
|
||||
///
|
||||
/// let mut vec = vec![1, 2];
|
||||
/// vec.place_back() <- 3;
|
||||
/// vec.place_back() <- 4;
|
||||
/// assert_eq!(&vec, &[1, 2, 3, 4]);
|
||||
/// ```
|
||||
#[unstable(feature = "collection_placement",
|
||||
reason = "placement protocol is subject to change",
|
||||
issue = "30172")]
|
||||
pub fn place_back(&mut self) -> PlaceBack<T> {
|
||||
PlaceBack { vec: self }
|
||||
}
|
||||
}
|
||||
|
||||
// Set the length of the vec when the `SetLenOnDrop` value goes out of scope.
|
||||
|
|
@ -1763,8 +1787,7 @@ impl<T: Ord> Ord for Vec<T> {
|
|||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T> Drop for Vec<T> {
|
||||
#[unsafe_destructor_blind_to_params]
|
||||
unsafe impl<#[may_dangle] T> Drop for Vec<T> {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
// use drop for [T]
|
||||
|
|
@ -2033,8 +2056,7 @@ impl<T: Clone> Clone for IntoIter<T> {
|
|||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T> Drop for IntoIter<T> {
|
||||
#[unsafe_destructor_blind_to_params]
|
||||
unsafe impl<#[may_dangle] T> Drop for IntoIter<T> {
|
||||
fn drop(&mut self) {
|
||||
// destroy the remaining elements
|
||||
for _x in self.by_ref() {}
|
||||
|
|
@ -2119,3 +2141,52 @@ impl<'a, T> ExactSizeIterator for Drain<'a, T> {
|
|||
|
||||
#[unstable(feature = "fused", issue = "35602")]
|
||||
impl<'a, T> FusedIterator for Drain<'a, T> {}
|
||||
|
||||
/// A place for insertion at the back of a `Vec`.
|
||||
///
|
||||
/// See [`Vec::place_back`](struct.Vec.html#method.place_back) for details.
|
||||
#[must_use = "places do nothing unless written to with `<-` syntax"]
|
||||
#[unstable(feature = "collection_placement",
|
||||
reason = "struct name and placement protocol are subject to change",
|
||||
issue = "30172")]
|
||||
pub struct PlaceBack<'a, T: 'a> {
|
||||
vec: &'a mut Vec<T>,
|
||||
}
|
||||
|
||||
#[unstable(feature = "collection_placement",
|
||||
reason = "placement protocol is subject to change",
|
||||
issue = "30172")]
|
||||
impl<'a, T> Placer<T> for PlaceBack<'a, T> {
|
||||
type Place = PlaceBack<'a, T>;
|
||||
|
||||
fn make_place(self) -> Self {
|
||||
// This will panic or abort if we would allocate > isize::MAX bytes
|
||||
// or if the length increment would overflow for zero-sized types.
|
||||
if self.vec.len == self.vec.buf.cap() {
|
||||
self.vec.buf.double();
|
||||
}
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "collection_placement",
|
||||
reason = "placement protocol is subject to change",
|
||||
issue = "30172")]
|
||||
impl<'a, T> Place<T> for PlaceBack<'a, T> {
|
||||
fn pointer(&mut self) -> *mut T {
|
||||
unsafe { self.vec.as_mut_ptr().offset(self.vec.len as isize) }
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "collection_placement",
|
||||
reason = "placement protocol is subject to change",
|
||||
issue = "30172")]
|
||||
impl<'a, T> InPlace<T> for PlaceBack<'a, T> {
|
||||
type Owner = &'a mut T;
|
||||
|
||||
unsafe fn finalize(mut self) -> &'a mut T {
|
||||
let ptr = self.pointer();
|
||||
self.vec.len += 1;
|
||||
&mut *ptr
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -69,8 +69,7 @@ impl<T: Clone> Clone for VecDeque<T> {
|
|||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T> Drop for VecDeque<T> {
|
||||
#[unsafe_destructor_blind_to_params]
|
||||
unsafe impl<#[may_dangle] T> Drop for VecDeque<T> {
|
||||
fn drop(&mut self) {
|
||||
let (front, back) = self.as_mut_slices();
|
||||
unsafe {
|
||||
|
|
@ -1228,9 +1227,8 @@ impl<T> VecDeque<T> {
|
|||
self.pop_front()
|
||||
}
|
||||
|
||||
/// Inserts an element at `index` within the `VecDeque`. Whichever
|
||||
/// end is closer to the insertion point will be moved to make room,
|
||||
/// and all the affected elements will be moved to new positions.
|
||||
/// Inserts an element at `index` within the `VecDeque`, shifting all elements with indices
|
||||
/// greater than or equal to `index` towards the back.
|
||||
///
|
||||
/// Element at index 0 is the front of the queue.
|
||||
///
|
||||
|
|
@ -1239,14 +1237,19 @@ impl<T> VecDeque<T> {
|
|||
/// Panics if `index` is greater than `VecDeque`'s length
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::VecDeque;
|
||||
///
|
||||
/// let mut buf = VecDeque::new();
|
||||
/// buf.push_back(10);
|
||||
/// buf.push_back(12);
|
||||
/// buf.insert(1, 11);
|
||||
/// assert_eq!(Some(&11), buf.get(1));
|
||||
/// let mut vec_deque = VecDeque::new();
|
||||
/// vec_deque.push_back('a');
|
||||
/// vec_deque.push_back('b');
|
||||
/// vec_deque.push_back('c');
|
||||
///
|
||||
/// vec_deque.insert(1, 'd');
|
||||
///
|
||||
/// let vec = vec_deque.into_iter().collect::<Vec<_>>();
|
||||
/// assert_eq!(vec, ['a', 'd', 'b', 'c']);
|
||||
/// ```
|
||||
#[stable(feature = "deque_extras_15", since = "1.5.0")]
|
||||
pub fn insert(&mut self, index: usize, value: T) {
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
// except according to those terms.
|
||||
|
||||
use std::collections::BinaryHeap;
|
||||
use std::collections::binary_heap::Drain;
|
||||
use std::collections::binary_heap::{Drain, PeekMut};
|
||||
|
||||
#[test]
|
||||
fn test_iterator() {
|
||||
|
|
@ -94,6 +94,19 @@ fn test_peek_mut() {
|
|||
assert_eq!(heap.peek(), Some(&9));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_peek_mut_pop() {
|
||||
let data = vec![2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1];
|
||||
let mut heap = BinaryHeap::from(data);
|
||||
assert_eq!(heap.peek(), Some(&10));
|
||||
{
|
||||
let mut top = heap.peek_mut().unwrap();
|
||||
*top -= 2;
|
||||
assert_eq!(PeekMut::pop(top), 8);
|
||||
}
|
||||
assert_eq!(heap.peek(), Some(&9));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_push() {
|
||||
let mut heap = BinaryHeap::from(vec![2, 4, 9]);
|
||||
|
|
|
|||
|
|
@ -11,8 +11,10 @@
|
|||
#![deny(warnings)]
|
||||
|
||||
#![feature(binary_heap_extras)]
|
||||
#![feature(binary_heap_peek_mut_pop)]
|
||||
#![feature(box_syntax)]
|
||||
#![feature(btree_range)]
|
||||
#![feature(collection_placement)]
|
||||
#![feature(collections)]
|
||||
#![feature(collections_bound)]
|
||||
#![feature(const_fn)]
|
||||
|
|
@ -20,6 +22,7 @@
|
|||
#![feature(enumset)]
|
||||
#![feature(exact_size_is_empty)]
|
||||
#![feature(pattern)]
|
||||
#![feature(placement_in_syntax)]
|
||||
#![feature(rand)]
|
||||
#![feature(repeat_str)]
|
||||
#![feature(step_by)]
|
||||
|
|
|
|||
|
|
@ -383,17 +383,29 @@ tempus vel, gravida nec quam.";
|
|||
|
||||
// check the panic includes the prefix of the sliced string
|
||||
#[test]
|
||||
#[should_panic(expected="Lorem ipsum dolor sit amet")]
|
||||
#[should_panic(expected="byte index 1024 is out of bounds of `Lorem ipsum dolor sit amet")]
|
||||
fn test_slice_fail_truncated_1() {
|
||||
&LOREM_PARAGRAPH[..1024];
|
||||
}
|
||||
// check the truncation in the panic message
|
||||
#[test]
|
||||
#[should_panic(expected="luctus, im`[...] do not lie on character boundary")]
|
||||
#[should_panic(expected="luctus, im`[...]")]
|
||||
fn test_slice_fail_truncated_2() {
|
||||
&LOREM_PARAGRAPH[..1024];
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected="byte index 4 is not a char boundary; it is inside 'α' (bytes 3..5) of")]
|
||||
fn test_slice_fail_boundary_1() {
|
||||
&"abcαβγ"[4..];
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected="byte index 6 is not a char boundary; it is inside 'β' (bytes 5..7) of")]
|
||||
fn test_slice_fail_boundary_2() {
|
||||
&"abcαβγ"[2..6];
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_slice_from() {
|
||||
assert_eq!(&"abcd"[0..], "abcd");
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ use std::ascii::AsciiExt;
|
|||
use std::borrow::Cow;
|
||||
use std::iter::{FromIterator, repeat};
|
||||
use std::mem::size_of;
|
||||
use std::panic;
|
||||
use std::vec::{Drain, IntoIter};
|
||||
|
||||
use test::Bencher;
|
||||
|
|
@ -615,6 +616,24 @@ fn assert_covariance() {
|
|||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_placement() {
|
||||
let mut vec = vec![1];
|
||||
assert_eq!(vec.place_back() <- 2, &2);
|
||||
assert_eq!(vec.len(), 2);
|
||||
assert_eq!(vec.place_back() <- 3, &3);
|
||||
assert_eq!(vec.len(), 3);
|
||||
assert_eq!(&vec, &[1, 2, 3]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_placement_panic() {
|
||||
let mut vec = vec![1, 2, 3];
|
||||
fn mkpanic() -> usize { panic!() }
|
||||
let _ = panic::catch_unwind(panic::AssertUnwindSafe(|| { vec.place_back() <- mkpanic(); }));
|
||||
assert_eq!(vec.len(), 3);
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_new(b: &mut Bencher) {
|
||||
b.iter(|| {
|
||||
|
|
|
|||
|
|
@ -192,14 +192,12 @@ fn main() {
|
|||
|
||||
if !target.contains("ios") {
|
||||
sources.extend(&["absvti2.c",
|
||||
"addtf3.c",
|
||||
"addvti3.c",
|
||||
"ashlti3.c",
|
||||
"ashrti3.c",
|
||||
"clzti2.c",
|
||||
"cmpti2.c",
|
||||
"ctzti2.c",
|
||||
"divtf3.c",
|
||||
"divti3.c",
|
||||
"ffsti2.c",
|
||||
"fixdfti.c",
|
||||
|
|
@ -216,17 +214,13 @@ fn main() {
|
|||
"floatuntixf.c",
|
||||
"lshrti3.c",
|
||||
"modti3.c",
|
||||
"multf3.c",
|
||||
"multi3.c",
|
||||
"mulvti3.c",
|
||||
"negti2.c",
|
||||
"negvti2.c",
|
||||
"parityti2.c",
|
||||
"popcountti2.c",
|
||||
"powitf2.c",
|
||||
"subtf3.c",
|
||||
"subvti3.c",
|
||||
"trampoline_setup.c",
|
||||
"ucmpti2.c",
|
||||
"udivmodti4.c",
|
||||
"udivti3.c",
|
||||
|
|
@ -242,10 +236,6 @@ fn main() {
|
|||
"atomic_thread_fence.c"]);
|
||||
}
|
||||
|
||||
if !target.contains("redox") && !target.contains("windows") {
|
||||
sources.extend(&["emutls.c"]);
|
||||
}
|
||||
|
||||
if target.contains("msvc") {
|
||||
if target.contains("x86_64") {
|
||||
sources.extend(&["x86_64/floatdidf.c", "x86_64/floatdisf.c", "x86_64/floatdixf.c"]);
|
||||
|
|
|
|||
|
|
@ -101,7 +101,7 @@ pub trait Any: 'static {
|
|||
///
|
||||
/// fn main() {
|
||||
/// assert_eq!(is_string(&0), false);
|
||||
/// assert_eq!(is_string(&"cookie monster".to_owned()), true);
|
||||
/// assert_eq!(is_string(&"cookie monster".to_string()), true);
|
||||
/// }
|
||||
/// ```
|
||||
#[unstable(feature = "get_type_id",
|
||||
|
|
@ -154,7 +154,7 @@ impl Any {
|
|||
///
|
||||
/// fn main() {
|
||||
/// is_string(&0);
|
||||
/// is_string(&"cookie monster".to_owned());
|
||||
/// is_string(&"cookie monster".to_string());
|
||||
/// }
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
|
@ -188,7 +188,7 @@ impl Any {
|
|||
///
|
||||
/// fn main() {
|
||||
/// print_if_string(&0);
|
||||
/// print_if_string(&"cookie monster".to_owned());
|
||||
/// print_if_string(&"cookie monster".to_string());
|
||||
/// }
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
|
@ -219,7 +219,7 @@ impl Any {
|
|||
///
|
||||
/// fn main() {
|
||||
/// let mut x = 10u32;
|
||||
/// let mut s = "starlord".to_owned();
|
||||
/// let mut s = "starlord".to_string();
|
||||
///
|
||||
/// modify_if_u32(&mut x);
|
||||
/// modify_if_u32(&mut s);
|
||||
|
|
@ -259,7 +259,7 @@ impl Any+Send {
|
|||
///
|
||||
/// fn main() {
|
||||
/// is_string(&0);
|
||||
/// is_string(&"cookie monster".to_owned());
|
||||
/// is_string(&"cookie monster".to_string());
|
||||
/// }
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
|
@ -285,7 +285,7 @@ impl Any+Send {
|
|||
///
|
||||
/// fn main() {
|
||||
/// print_if_string(&0);
|
||||
/// print_if_string(&"cookie monster".to_owned());
|
||||
/// print_if_string(&"cookie monster".to_string());
|
||||
/// }
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
|
@ -309,7 +309,7 @@ impl Any+Send {
|
|||
///
|
||||
/// fn main() {
|
||||
/// let mut x = 10u32;
|
||||
/// let mut s = "starlord".to_owned();
|
||||
/// let mut s = "starlord".to_string();
|
||||
///
|
||||
/// modify_if_u32(&mut x);
|
||||
/// modify_if_u32(&mut s);
|
||||
|
|
@ -359,7 +359,7 @@ impl TypeId {
|
|||
///
|
||||
/// fn main() {
|
||||
/// assert_eq!(is_string(&0), false);
|
||||
/// assert_eq!(is_string(&"cookie monster".to_owned()), true);
|
||||
/// assert_eq!(is_string(&"cookie monster".to_string()), true);
|
||||
/// }
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
use char_private::is_printable;
|
||||
use convert::TryFrom;
|
||||
use fmt;
|
||||
use fmt::{self, Write};
|
||||
use slice;
|
||||
use iter::FusedIterator;
|
||||
use mem::transmute;
|
||||
|
|
@ -588,6 +588,16 @@ impl ExactSizeIterator for EscapeUnicode {
|
|||
#[unstable(feature = "fused", issue = "35602")]
|
||||
impl FusedIterator for EscapeUnicode {}
|
||||
|
||||
#[stable(feature = "char_struct_display", since = "1.17.0")]
|
||||
impl fmt::Display for EscapeUnicode {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
for c in self.clone() {
|
||||
f.write_char(c)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// An iterator that yields the literal escape code of a `char`.
|
||||
///
|
||||
/// This `struct` is created by the [`escape_default()`] method on [`char`]. See
|
||||
|
|
@ -691,6 +701,16 @@ impl ExactSizeIterator for EscapeDefault {
|
|||
#[unstable(feature = "fused", issue = "35602")]
|
||||
impl FusedIterator for EscapeDefault {}
|
||||
|
||||
#[stable(feature = "char_struct_display", since = "1.17.0")]
|
||||
impl fmt::Display for EscapeDefault {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
for c in self.clone() {
|
||||
f.write_char(c)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// An iterator that yields the literal escape code of a `char`.
|
||||
///
|
||||
/// This `struct` is created by the [`escape_debug()`] method on [`char`]. See its
|
||||
|
|
@ -715,6 +735,13 @@ impl ExactSizeIterator for EscapeDebug { }
|
|||
#[unstable(feature = "fused", issue = "35602")]
|
||||
impl FusedIterator for EscapeDebug {}
|
||||
|
||||
#[stable(feature = "char_struct_display", since = "1.17.0")]
|
||||
impl fmt::Display for EscapeDebug {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt::Display::fmt(&self.0, f)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// An iterator over an iterator of bytes of the characters the bytes represent
|
||||
|
|
|
|||
|
|
@ -1156,10 +1156,58 @@ extern "rust-intrinsic" {
|
|||
/// Returns the number of bits set in an integer type `T`
|
||||
pub fn ctpop<T>(x: T) -> T;
|
||||
|
||||
/// Returns the number of leading bits unset in an integer type `T`
|
||||
/// Returns the number of leading unset bits (zeroes) in an integer type `T`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(core_intrinsics)]
|
||||
///
|
||||
/// use std::intrinsics::ctlz;
|
||||
///
|
||||
/// let x = 0b0001_1100_u8;
|
||||
/// let num_leading = unsafe { ctlz(x) };
|
||||
/// assert_eq!(num_leading, 3);
|
||||
/// ```
|
||||
///
|
||||
/// An `x` with value `0` will return the bit width of `T`.
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(core_intrinsics)]
|
||||
///
|
||||
/// use std::intrinsics::ctlz;
|
||||
///
|
||||
/// let x = 0u16;
|
||||
/// let num_leading = unsafe { ctlz(x) };
|
||||
/// assert_eq!(num_leading, 16);
|
||||
/// ```
|
||||
pub fn ctlz<T>(x: T) -> T;
|
||||
|
||||
/// Returns the number of trailing bits unset in an integer type `T`
|
||||
/// Returns the number of trailing unset bits (zeroes) in an integer type `T`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(core_intrinsics)]
|
||||
///
|
||||
/// use std::intrinsics::cttz;
|
||||
///
|
||||
/// let x = 0b0011_1000_u8;
|
||||
/// let num_trailing = unsafe { cttz(x) };
|
||||
/// assert_eq!(num_trailing, 3);
|
||||
/// ```
|
||||
///
|
||||
/// An `x` with value `0` will return the bit width of `T`:
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(core_intrinsics)]
|
||||
///
|
||||
/// use std::intrinsics::cttz;
|
||||
///
|
||||
/// let x = 0u16;
|
||||
/// let num_trailing = unsafe { cttz(x) };
|
||||
/// assert_eq!(num_trailing, 16);
|
||||
/// ```
|
||||
pub fn cttz<T>(x: T) -> T;
|
||||
|
||||
/// Reverses the bytes in an integer type `T`.
|
||||
|
|
|
|||
|
|
@ -1612,7 +1612,7 @@ pub trait Iterator {
|
|||
|
||||
/// Returns the maximum element of an iterator.
|
||||
///
|
||||
/// If the two elements are equally maximum, the latest element is
|
||||
/// If several elements are equally maximum, the last element is
|
||||
/// returned.
|
||||
///
|
||||
/// # Examples
|
||||
|
|
@ -1638,7 +1638,7 @@ pub trait Iterator {
|
|||
|
||||
/// Returns the minimum element of an iterator.
|
||||
///
|
||||
/// If the two elements are equally minimum, the first element is
|
||||
/// If several elements are equally minimum, the first element is
|
||||
/// returned.
|
||||
///
|
||||
/// # Examples
|
||||
|
|
@ -1665,8 +1665,8 @@ pub trait Iterator {
|
|||
/// Returns the element that gives the maximum value from the
|
||||
/// specified function.
|
||||
///
|
||||
/// Returns the rightmost element if the comparison determines two elements
|
||||
/// to be equally maximum.
|
||||
/// If several elements are equally maximum, the last element is
|
||||
/// returned.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -1690,8 +1690,8 @@ pub trait Iterator {
|
|||
/// Returns the element that gives the maximum value with respect to the
|
||||
/// specified comparison function.
|
||||
///
|
||||
/// Returns the rightmost element if the comparison determines two elements
|
||||
/// to be equally maximum.
|
||||
/// If several elements are equally maximum, the last element is
|
||||
/// returned.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -1715,8 +1715,8 @@ pub trait Iterator {
|
|||
/// Returns the element that gives the minimum value from the
|
||||
/// specified function.
|
||||
///
|
||||
/// Returns the latest element if the comparison determines two elements
|
||||
/// to be equally minimum.
|
||||
/// If several elements are equally minimum, the first element is
|
||||
/// returned.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -1739,8 +1739,8 @@ pub trait Iterator {
|
|||
/// Returns the element that gives the minimum value with respect to the
|
||||
/// specified comparison function.
|
||||
///
|
||||
/// Returns the latest element if the comparison determines two elements
|
||||
/// to be equally minimum.
|
||||
/// If several elements are equally minimum, the first element is
|
||||
/// returned.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
|
|||
|
|
@ -260,7 +260,10 @@ impl<I: Iterator> IntoIterator for I {
|
|||
///
|
||||
/// Iterators produce a series of values, and collections can also be thought
|
||||
/// of as a series of values. The `Extend` trait bridges this gap, allowing you
|
||||
/// to extend a collection by including the contents of that iterator.
|
||||
/// to extend a collection by including the contents of that iterator. When
|
||||
/// extending a collection with an already existing key, that entry is updated
|
||||
/// or, in the case of collections that permit multiple entries with equal
|
||||
/// keys, that entry is inserted.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -670,6 +673,87 @@ macro_rules! float_sum_product {
|
|||
integer_sum_product! { i8 i16 i32 i64 isize u8 u16 u32 u64 usize }
|
||||
float_sum_product! { f32 f64 }
|
||||
|
||||
/// An iterator adapter that produces output as long as the underlying
|
||||
/// iterator produces `Result::Ok` values.
|
||||
///
|
||||
/// If an error is encountered, the iterator stops and the error is
|
||||
/// stored. The error may be recovered later via `reconstruct`.
|
||||
struct ResultShunt<I, E> {
|
||||
iter: I,
|
||||
error: Option<E>,
|
||||
}
|
||||
|
||||
impl<I, T, E> ResultShunt<I, E>
|
||||
where I: Iterator<Item = Result<T, E>>
|
||||
{
|
||||
/// Process the given iterator as if it yielded a `T` instead of a
|
||||
/// `Result<T, _>`. Any errors will stop the inner iterator and
|
||||
/// the overall result will be an error.
|
||||
pub fn process<F, U>(iter: I, mut f: F) -> Result<U, E>
|
||||
where F: FnMut(&mut Self) -> U
|
||||
{
|
||||
let mut shunt = ResultShunt::new(iter);
|
||||
let value = f(shunt.by_ref());
|
||||
shunt.reconstruct(value)
|
||||
}
|
||||
|
||||
fn new(iter: I) -> Self {
|
||||
ResultShunt {
|
||||
iter: iter,
|
||||
error: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Consume the adapter and rebuild a `Result` value. This should
|
||||
/// *always* be called, otherwise any potential error would be
|
||||
/// lost.
|
||||
fn reconstruct<U>(self, val: U) -> Result<U, E> {
|
||||
match self.error {
|
||||
None => Ok(val),
|
||||
Some(e) => Err(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<I, T, E> Iterator for ResultShunt<I, E>
|
||||
where I: Iterator<Item = Result<T, E>>
|
||||
{
|
||||
type Item = T;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
match self.iter.next() {
|
||||
Some(Ok(v)) => Some(v),
|
||||
Some(Err(e)) => {
|
||||
self.error = Some(e);
|
||||
None
|
||||
}
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "iter_arith_traits_result", since="1.16.0")]
|
||||
impl<T, U, E> Sum<Result<U, E>> for Result<T, E>
|
||||
where T: Sum<U>,
|
||||
{
|
||||
fn sum<I>(iter: I) -> Result<T, E>
|
||||
where I: Iterator<Item = Result<U, E>>,
|
||||
{
|
||||
ResultShunt::process(iter, |i| i.sum())
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "iter_arith_traits_result", since="1.16.0")]
|
||||
impl<T, U, E> Product<Result<U, E>> for Result<T, E>
|
||||
where T: Product<U>,
|
||||
{
|
||||
fn product<I>(iter: I) -> Result<T, E>
|
||||
where I: Iterator<Item = Result<U, E>>,
|
||||
{
|
||||
ResultShunt::process(iter, |i| i.product())
|
||||
}
|
||||
}
|
||||
|
||||
/// An iterator that always continues to yield `None` when exhausted.
|
||||
///
|
||||
/// Calling next on a fused iterator that has returned `None` once is guaranteed
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@
|
|||
#![no_core]
|
||||
#![deny(missing_docs)]
|
||||
#![deny(missing_debug_implementations)]
|
||||
#![cfg_attr(not(stage0), deny(warnings))]
|
||||
#![deny(warnings)]
|
||||
|
||||
#![feature(allow_internal_unstable)]
|
||||
#![feature(asm)]
|
||||
|
|
|
|||
|
|
@ -404,10 +404,11 @@ macro_rules! write {
|
|||
/// use std::io::Write;
|
||||
///
|
||||
/// let mut w = Vec::new();
|
||||
/// writeln!(&mut w).unwrap();
|
||||
/// writeln!(&mut w, "test").unwrap();
|
||||
/// writeln!(&mut w, "formatted {}", "arguments").unwrap();
|
||||
///
|
||||
/// assert_eq!(&w[..], "test\nformatted arguments\n".as_bytes());
|
||||
/// assert_eq!(&w[..], "\ntest\nformatted arguments\n".as_bytes());
|
||||
/// ```
|
||||
///
|
||||
/// A module can import both `std::fmt::Write` and `std::io::Write` and call `write!` on objects
|
||||
|
|
@ -427,6 +428,9 @@ macro_rules! write {
|
|||
#[macro_export]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
macro_rules! writeln {
|
||||
($dst:expr) => (
|
||||
write!($dst, "\n")
|
||||
);
|
||||
($dst:expr, $fmt:expr) => (
|
||||
write!($dst, concat!($fmt, "\n"))
|
||||
);
|
||||
|
|
|
|||
|
|
@ -100,13 +100,26 @@ pub trait Sized {
|
|||
///
|
||||
/// All implementations of `Unsize` are provided automatically by the compiler.
|
||||
///
|
||||
/// `Unsize` is implemented for:
|
||||
///
|
||||
/// - `[T; N]` is `Unsize<[T]>`
|
||||
/// - `T` is `Unsize<Trait>` when `T: Trait`
|
||||
/// - `Foo<..., T, ...>` is `Unsize<Foo<..., U, ...>>` if:
|
||||
/// - `T: Unsize<U>`
|
||||
/// - Foo is a struct
|
||||
/// - Only the last field of `Foo` has a type involving `T`
|
||||
/// - `T` is not part of the type of any other fields
|
||||
/// - `Bar<T>: Unsize<Bar<U>>`, if the last field of `Foo` has type `Bar<T>`
|
||||
///
|
||||
/// `Unsize` is used along with [`ops::CoerceUnsized`][coerceunsized] to allow
|
||||
/// "user-defined" containers such as [`rc::Rc`][rc] to contain dynamically-sized
|
||||
/// types. See the [DST coercion RFC][RFC982] for more details.
|
||||
/// types. See the [DST coercion RFC][RFC982] and [the nomicon entry on coercion][nomicon-coerce]
|
||||
/// for more details.
|
||||
///
|
||||
/// [coerceunsized]: ../ops/trait.CoerceUnsized.html
|
||||
/// [rc]: ../../std/rc/struct.Rc.html
|
||||
/// [RFC982]: https://github.com/rust-lang/rfcs/blob/master/text/0982-dst-coercion.md
|
||||
|
||||
#[unstable(feature = "unsize", issue = "27732")]
|
||||
#[lang="unsize"]
|
||||
pub trait Unsize<T: ?Sized> {
|
||||
|
|
@ -234,12 +247,10 @@ pub trait Unsize<T: ?Sized> {
|
|||
/// Generalizing the latter case, any type implementing [`Drop`] can't be `Copy`, because it's
|
||||
/// managing some resource besides its own [`size_of::<T>()`] bytes.
|
||||
///
|
||||
/// If you try to implement `Copy` on a struct or enum containing non-`Copy` data, you will get a
|
||||
/// compile-time error. Specifically, with structs you'll get [E0204] and with enums you'll get
|
||||
/// [E0205].
|
||||
/// If you try to implement `Copy` on a struct or enum containing non-`Copy` data, you will get
|
||||
/// the error [E0204].
|
||||
///
|
||||
/// [E0204]: ../../error-index.html#E0204
|
||||
/// [E0205]: ../../error-index.html#E0205
|
||||
///
|
||||
/// ## When *should* my type be `Copy`?
|
||||
///
|
||||
|
|
|
|||
|
|
@ -14,4 +14,4 @@
|
|||
|
||||
#![unstable(feature = "i128", issue="35118")]
|
||||
|
||||
int_module! { i128 }
|
||||
int_module! { i128, #[unstable(feature = "i128", issue="35118")] }
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// Copyright 2012-2017 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
|
|
@ -10,13 +10,14 @@
|
|||
|
||||
#![doc(hidden)]
|
||||
|
||||
macro_rules! int_module { ($T:ident) => (
|
||||
|
||||
/// The smallest value that can be represented by this integer type.
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub const MIN: $T = $T::min_value();
|
||||
/// The largest value that can be represented by this integer type.
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub const MAX: $T = $T::max_value();
|
||||
|
||||
) }
|
||||
macro_rules! int_module {
|
||||
($T:ident) => (int_module!($T, #[stable(feature = "rust1", since = "1.0.0")]););
|
||||
($T:ident, $($attr: tt)*) => (
|
||||
/// The smallest value that can be represented by this integer type.
|
||||
$($attr)*
|
||||
pub const MIN: $T = $T::min_value();
|
||||
/// The largest value that can be represented by this integer type.
|
||||
$($attr)*
|
||||
pub const MAX: $T = $T::max_value();
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,4 +13,4 @@
|
|||
//! *[See also the `u128` primitive type](../../std/primitive.u128.html).*
|
||||
|
||||
#![unstable(feature = "i128", issue="35118")]
|
||||
uint_module! { u128 }
|
||||
uint_module! { u128, #[unstable(feature = "i128", issue="35118")] }
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// Copyright 2012-2017 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
|
|
@ -10,13 +10,14 @@
|
|||
|
||||
#![doc(hidden)]
|
||||
|
||||
macro_rules! uint_module { ($T:ident) => (
|
||||
|
||||
/// The smallest value that can be represented by this integer type.
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub const MIN: $T = $T::min_value();
|
||||
/// The largest value that can be represented by this integer type.
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub const MAX: $T = $T::max_value();
|
||||
|
||||
) }
|
||||
macro_rules! uint_module {
|
||||
($T:ident) => (uint_module!($T, #[stable(feature = "rust1", since = "1.0.0")]););
|
||||
($T:ident, $($attr: tt)*) => (
|
||||
/// The smallest value that can be represented by this integer type.
|
||||
$($attr)*
|
||||
pub const MIN: $T = $T::min_value();
|
||||
/// The largest value that can be represented by this integer type.
|
||||
$($attr)*
|
||||
pub const MAX: $T = $T::max_value();
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2710,6 +2710,35 @@ mod impls {
|
|||
|
||||
/// Trait that indicates that this is a pointer or a wrapper for one,
|
||||
/// where unsizing can be performed on the pointee.
|
||||
///
|
||||
/// See the [DST coercion RfC][dst-coerce] and [the nomicon entry on coercion][nomicon-coerce]
|
||||
/// for more details.
|
||||
///
|
||||
/// For builtin pointer types, pointers to `T` will coerce to pointers to `U` if `T: Unsize<U>`
|
||||
/// by converting from a thin pointer to a fat pointer.
|
||||
///
|
||||
/// For custom types, the coercion here works by coercing `Foo<T>` to `Foo<U>`
|
||||
/// provided an impl of `CoerceUnsized<Foo<U>> for Foo<T>` exists.
|
||||
/// Such an impl can only be written if `Foo<T>` has only a single non-phantomdata
|
||||
/// field involving `T`. If the type of that field is `Bar<T>`, an implementation
|
||||
/// of `CoerceUnsized<Bar<U>> for Bar<T>` must exist. The coercion will work by
|
||||
/// by coercing the `Bar<T>` field into `Bar<U>` and filling in the rest of the fields
|
||||
/// from `Foo<T>` to create a `Foo<U>`. This will effectively drill down to a pointer
|
||||
/// field and coerce that.
|
||||
///
|
||||
/// Generally, for smart pointers you will implement
|
||||
/// `CoerceUnsized<Ptr<U>> for Ptr<T> where T: Unsize<U>, U: ?Sized`, with an
|
||||
/// optional `?Sized` bound on `T` itself. For wrapper types that directly embed `T`
|
||||
/// like `Cell<T>` and `RefCell<T>`, you
|
||||
/// can directly implement `CoerceUnsized<Wrap<U>> for Wrap<T> where T: CoerceUnsized<U>`.
|
||||
/// This will let coercions of types like `Cell<Box<T>>` work.
|
||||
///
|
||||
/// [`Unsize`][unsize] is used to mark types which can be coerced to DSTs if behind
|
||||
/// pointers. It is implemented automatically by the compiler.
|
||||
///
|
||||
/// [dst-coerce]: https://github.com/rust-lang/rfcs/blob/master/text/0982-dst-coercion.md
|
||||
/// [unsize]: ../marker/trait.Unsize.html
|
||||
/// [nomicon-coerce]: ../../nomicon/coercions.html
|
||||
#[unstable(feature = "coerce_unsized", issue = "27732")]
|
||||
#[lang="coerce_unsized"]
|
||||
pub trait CoerceUnsized<T> {
|
||||
|
|
|
|||
|
|
@ -74,7 +74,10 @@ pub const fn null_mut<T>() -> *mut T { 0 as *mut T }
|
|||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This is only unsafe because it accepts a raw pointer.
|
||||
/// This function copies the memory through the raw pointers passed to it
|
||||
/// as arguments.
|
||||
///
|
||||
/// Ensure that these pointers are valid before calling `swap`.
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub unsafe fn swap<T>(x: *mut T, y: *mut T) {
|
||||
|
|
|
|||
|
|
@ -798,6 +798,31 @@ impl<T: fmt::Debug, E> Result<T, E> {
|
|||
Err(e) => e,
|
||||
}
|
||||
}
|
||||
|
||||
/// Unwraps a result, yielding the content of an `Err`.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the value is an `Ok`, with a panic message including the
|
||||
/// passed message, and the content of the `Ok`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Basic usage:
|
||||
///
|
||||
/// ```{.should_panic}
|
||||
/// # #![feature(result_expect_err)]
|
||||
/// let x: Result<u32, &str> = Ok(10);
|
||||
/// x.expect_err("Testing expect_err"); // panics with `Testing expect_err: 10`
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "result_expect_err", issue = "39041")]
|
||||
pub fn expect_err(self, msg: &str) -> E {
|
||||
match self {
|
||||
Ok(t) => unwrap_failed(msg, t),
|
||||
Err(e) => e,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Default, E> Result<T, E> {
|
||||
|
|
|
|||
|
|
@ -1232,10 +1232,15 @@ fn contains_nonascii(x: usize) -> bool {
|
|||
/// invalid sequence.
|
||||
#[inline(always)]
|
||||
fn run_utf8_validation(v: &[u8]) -> Result<(), Utf8Error> {
|
||||
let mut offset = 0;
|
||||
let mut index = 0;
|
||||
let len = v.len();
|
||||
while offset < len {
|
||||
let old_offset = offset;
|
||||
|
||||
let usize_bytes = mem::size_of::<usize>();
|
||||
let ascii_block_size = 2 * usize_bytes;
|
||||
let blocks_end = if len >= ascii_block_size { len - ascii_block_size + 1 } else { 0 };
|
||||
|
||||
while index < len {
|
||||
let old_offset = index;
|
||||
macro_rules! err { () => {{
|
||||
return Err(Utf8Error {
|
||||
valid_up_to: old_offset
|
||||
|
|
@ -1243,15 +1248,15 @@ fn run_utf8_validation(v: &[u8]) -> Result<(), Utf8Error> {
|
|||
}}}
|
||||
|
||||
macro_rules! next { () => {{
|
||||
offset += 1;
|
||||
index += 1;
|
||||
// we needed data, but there was none: error!
|
||||
if offset >= len {
|
||||
if index >= len {
|
||||
err!()
|
||||
}
|
||||
v[offset]
|
||||
v[index]
|
||||
}}}
|
||||
|
||||
let first = v[offset];
|
||||
let first = v[index];
|
||||
if first >= 128 {
|
||||
let w = UTF8_CHAR_WIDTH[first as usize];
|
||||
let second = next!();
|
||||
|
|
@ -1294,38 +1299,32 @@ fn run_utf8_validation(v: &[u8]) -> Result<(), Utf8Error> {
|
|||
}
|
||||
_ => err!()
|
||||
}
|
||||
offset += 1;
|
||||
index += 1;
|
||||
} else {
|
||||
// Ascii case, try to skip forward quickly.
|
||||
// When the pointer is aligned, read 2 words of data per iteration
|
||||
// until we find a word containing a non-ascii byte.
|
||||
let usize_bytes = mem::size_of::<usize>();
|
||||
let bytes_per_iteration = 2 * usize_bytes;
|
||||
let ptr = v.as_ptr();
|
||||
let align = (ptr as usize + offset) & (usize_bytes - 1);
|
||||
let align = (ptr as usize + index) & (usize_bytes - 1);
|
||||
if align == 0 {
|
||||
if len >= bytes_per_iteration {
|
||||
while offset <= len - bytes_per_iteration {
|
||||
unsafe {
|
||||
let u = *(ptr.offset(offset as isize) as *const usize);
|
||||
let v = *(ptr.offset((offset + usize_bytes) as isize) as *const usize);
|
||||
|
||||
// break if there is a nonascii byte
|
||||
let zu = contains_nonascii(u);
|
||||
let zv = contains_nonascii(v);
|
||||
if zu || zv {
|
||||
break;
|
||||
}
|
||||
while index < blocks_end {
|
||||
unsafe {
|
||||
let block = ptr.offset(index as isize) as *const usize;
|
||||
// break if there is a nonascii byte
|
||||
let zu = contains_nonascii(*block);
|
||||
let zv = contains_nonascii(*block.offset(1));
|
||||
if zu | zv {
|
||||
break;
|
||||
}
|
||||
offset += bytes_per_iteration;
|
||||
}
|
||||
index += ascii_block_size;
|
||||
}
|
||||
// step from the point where the wordwise loop stopped
|
||||
while offset < len && v[offset] < 128 {
|
||||
offset += 1;
|
||||
while index < len && v[index] < 128 {
|
||||
index += 1;
|
||||
}
|
||||
} else {
|
||||
offset += 1;
|
||||
index += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1746,13 +1745,31 @@ fn truncate_to_char_boundary(s: &str, mut max: usize) -> (bool, &str) {
|
|||
#[cold]
|
||||
fn slice_error_fail(s: &str, begin: usize, end: usize) -> ! {
|
||||
const MAX_DISPLAY_LENGTH: usize = 256;
|
||||
let (truncated, s) = truncate_to_char_boundary(s, MAX_DISPLAY_LENGTH);
|
||||
let (truncated, s_trunc) = truncate_to_char_boundary(s, MAX_DISPLAY_LENGTH);
|
||||
let ellipsis = if truncated { "[...]" } else { "" };
|
||||
|
||||
// 1. out of bounds
|
||||
if begin > s.len() || end > s.len() {
|
||||
let oob_index = if begin > s.len() { begin } else { end };
|
||||
panic!("byte index {} is out of bounds of `{}`{}", oob_index, s_trunc, ellipsis);
|
||||
}
|
||||
|
||||
// 2. begin <= end
|
||||
assert!(begin <= end, "begin <= end ({} <= {}) when slicing `{}`{}",
|
||||
begin, end, s, ellipsis);
|
||||
panic!("index {} and/or {} in `{}`{} do not lie on character boundary",
|
||||
begin, end, s, ellipsis);
|
||||
begin, end, s_trunc, ellipsis);
|
||||
|
||||
// 3. character boundary
|
||||
let index = if !s.is_char_boundary(begin) { begin } else { end };
|
||||
// find the character
|
||||
let mut char_start = index;
|
||||
while !s.is_char_boundary(char_start) {
|
||||
char_start -= 1;
|
||||
}
|
||||
// `char_start` must be less than len and a char boundary
|
||||
let ch = s[char_start..].chars().next().unwrap();
|
||||
let char_range = char_start .. char_start + ch.len_utf8();
|
||||
panic!("byte index {} is not a char boundary; it is inside {:?} (bytes {:?}) of `{}`{}",
|
||||
index, ch, char_range, s_trunc, ellipsis);
|
||||
}
|
||||
|
||||
#[stable(feature = "core", since = "1.6.0")]
|
||||
|
|
|
|||
|
|
@ -75,47 +75,53 @@ fn test_to_digit() {
|
|||
|
||||
#[test]
|
||||
fn test_to_lowercase() {
|
||||
fn lower(c: char) -> Vec<char> {
|
||||
c.to_lowercase().collect()
|
||||
fn lower(c: char) -> String {
|
||||
let iter: String = c.to_lowercase().collect();
|
||||
let disp: String = c.to_lowercase().to_string();
|
||||
assert_eq!(iter, disp);
|
||||
iter
|
||||
}
|
||||
assert_eq!(lower('A'), ['a']);
|
||||
assert_eq!(lower('Ö'), ['ö']);
|
||||
assert_eq!(lower('ß'), ['ß']);
|
||||
assert_eq!(lower('Ü'), ['ü']);
|
||||
assert_eq!(lower('💩'), ['💩']);
|
||||
assert_eq!(lower('Σ'), ['σ']);
|
||||
assert_eq!(lower('Τ'), ['τ']);
|
||||
assert_eq!(lower('Ι'), ['ι']);
|
||||
assert_eq!(lower('Γ'), ['γ']);
|
||||
assert_eq!(lower('Μ'), ['μ']);
|
||||
assert_eq!(lower('Α'), ['α']);
|
||||
assert_eq!(lower('Σ'), ['σ']);
|
||||
assert_eq!(lower('Dž'), ['dž']);
|
||||
assert_eq!(lower('fi'), ['fi']);
|
||||
assert_eq!(lower('İ'), ['i', '\u{307}']);
|
||||
assert_eq!(lower('A'), "a");
|
||||
assert_eq!(lower('Ö'), "ö");
|
||||
assert_eq!(lower('ß'), "ß");
|
||||
assert_eq!(lower('Ü'), "ü");
|
||||
assert_eq!(lower('💩'), "💩");
|
||||
assert_eq!(lower('Σ'), "σ");
|
||||
assert_eq!(lower('Τ'), "τ");
|
||||
assert_eq!(lower('Ι'), "ι");
|
||||
assert_eq!(lower('Γ'), "γ");
|
||||
assert_eq!(lower('Μ'), "μ");
|
||||
assert_eq!(lower('Α'), "α");
|
||||
assert_eq!(lower('Σ'), "σ");
|
||||
assert_eq!(lower('Dž'), "dž");
|
||||
assert_eq!(lower('fi'), "fi");
|
||||
assert_eq!(lower('İ'), "i\u{307}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_to_uppercase() {
|
||||
fn upper(c: char) -> Vec<char> {
|
||||
c.to_uppercase().collect()
|
||||
fn upper(c: char) -> String {
|
||||
let iter: String = c.to_uppercase().collect();
|
||||
let disp: String = c.to_uppercase().to_string();
|
||||
assert_eq!(iter, disp);
|
||||
iter
|
||||
}
|
||||
assert_eq!(upper('a'), ['A']);
|
||||
assert_eq!(upper('ö'), ['Ö']);
|
||||
assert_eq!(upper('ß'), ['S', 'S']); // not ẞ: Latin capital letter sharp s
|
||||
assert_eq!(upper('ü'), ['Ü']);
|
||||
assert_eq!(upper('💩'), ['💩']);
|
||||
assert_eq!(upper('a'), "A");
|
||||
assert_eq!(upper('ö'), "Ö");
|
||||
assert_eq!(upper('ß'), "SS"); // not ẞ: Latin capital letter sharp s
|
||||
assert_eq!(upper('ü'), "Ü");
|
||||
assert_eq!(upper('💩'), "💩");
|
||||
|
||||
assert_eq!(upper('σ'), ['Σ']);
|
||||
assert_eq!(upper('τ'), ['Τ']);
|
||||
assert_eq!(upper('ι'), ['Ι']);
|
||||
assert_eq!(upper('γ'), ['Γ']);
|
||||
assert_eq!(upper('μ'), ['Μ']);
|
||||
assert_eq!(upper('α'), ['Α']);
|
||||
assert_eq!(upper('ς'), ['Σ']);
|
||||
assert_eq!(upper('Dž'), ['DŽ']);
|
||||
assert_eq!(upper('fi'), ['F', 'I']);
|
||||
assert_eq!(upper('ᾀ'), ['Ἀ', 'Ι']);
|
||||
assert_eq!(upper('σ'), "Σ");
|
||||
assert_eq!(upper('τ'), "Τ");
|
||||
assert_eq!(upper('ι'), "Ι");
|
||||
assert_eq!(upper('γ'), "Γ");
|
||||
assert_eq!(upper('μ'), "Μ");
|
||||
assert_eq!(upper('α'), "Α");
|
||||
assert_eq!(upper('ς'), "Σ");
|
||||
assert_eq!(upper('Dž'), "DŽ");
|
||||
assert_eq!(upper('fi'), "FI");
|
||||
assert_eq!(upper('ᾀ'), "ἈΙ");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -144,107 +150,75 @@ fn test_is_digit() {
|
|||
#[test]
|
||||
fn test_escape_debug() {
|
||||
fn string(c: char) -> String {
|
||||
c.escape_debug().collect()
|
||||
let iter: String = c.escape_debug().collect();
|
||||
let disp: String = c.escape_debug().to_string();
|
||||
assert_eq!(iter, disp);
|
||||
iter
|
||||
}
|
||||
let s = string('\n');
|
||||
assert_eq!(s, "\\n");
|
||||
let s = string('\r');
|
||||
assert_eq!(s, "\\r");
|
||||
let s = string('\'');
|
||||
assert_eq!(s, "\\'");
|
||||
let s = string('"');
|
||||
assert_eq!(s, "\\\"");
|
||||
let s = string(' ');
|
||||
assert_eq!(s, " ");
|
||||
let s = string('a');
|
||||
assert_eq!(s, "a");
|
||||
let s = string('~');
|
||||
assert_eq!(s, "~");
|
||||
let s = string('é');
|
||||
assert_eq!(s, "é");
|
||||
let s = string('文');
|
||||
assert_eq!(s, "文");
|
||||
let s = string('\x00');
|
||||
assert_eq!(s, "\\u{0}");
|
||||
let s = string('\x1f');
|
||||
assert_eq!(s, "\\u{1f}");
|
||||
let s = string('\x7f');
|
||||
assert_eq!(s, "\\u{7f}");
|
||||
let s = string('\u{80}');
|
||||
assert_eq!(s, "\\u{80}");
|
||||
let s = string('\u{ff}');
|
||||
assert_eq!(s, "\u{ff}");
|
||||
let s = string('\u{11b}');
|
||||
assert_eq!(s, "\u{11b}");
|
||||
let s = string('\u{1d4b6}');
|
||||
assert_eq!(s, "\u{1d4b6}");
|
||||
let s = string('\u{200b}'); // zero width space
|
||||
assert_eq!(s, "\\u{200b}");
|
||||
let s = string('\u{e000}'); // private use 1
|
||||
assert_eq!(s, "\\u{e000}");
|
||||
let s = string('\u{100000}'); // private use 2
|
||||
assert_eq!(s, "\\u{100000}");
|
||||
assert_eq!(string('\n'), "\\n");
|
||||
assert_eq!(string('\r'), "\\r");
|
||||
assert_eq!(string('\''), "\\'");
|
||||
assert_eq!(string('"'), "\\\"");
|
||||
assert_eq!(string(' '), " ");
|
||||
assert_eq!(string('a'), "a");
|
||||
assert_eq!(string('~'), "~");
|
||||
assert_eq!(string('é'), "é");
|
||||
assert_eq!(string('文'), "文");
|
||||
assert_eq!(string('\x00'), "\\u{0}");
|
||||
assert_eq!(string('\x1f'), "\\u{1f}");
|
||||
assert_eq!(string('\x7f'), "\\u{7f}");
|
||||
assert_eq!(string('\u{80}'), "\\u{80}");
|
||||
assert_eq!(string('\u{ff}'), "\u{ff}");
|
||||
assert_eq!(string('\u{11b}'), "\u{11b}");
|
||||
assert_eq!(string('\u{1d4b6}'), "\u{1d4b6}");
|
||||
assert_eq!(string('\u{200b}'),"\\u{200b}"); // zero width space
|
||||
assert_eq!(string('\u{e000}'), "\\u{e000}"); // private use 1
|
||||
assert_eq!(string('\u{100000}'), "\\u{100000}"); // private use 2
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_escape_default() {
|
||||
fn string(c: char) -> String {
|
||||
c.escape_default().collect()
|
||||
let iter: String = c.escape_default().collect();
|
||||
let disp: String = c.escape_default().to_string();
|
||||
assert_eq!(iter, disp);
|
||||
iter
|
||||
}
|
||||
let s = string('\n');
|
||||
assert_eq!(s, "\\n");
|
||||
let s = string('\r');
|
||||
assert_eq!(s, "\\r");
|
||||
let s = string('\'');
|
||||
assert_eq!(s, "\\'");
|
||||
let s = string('"');
|
||||
assert_eq!(s, "\\\"");
|
||||
let s = string(' ');
|
||||
assert_eq!(s, " ");
|
||||
let s = string('a');
|
||||
assert_eq!(s, "a");
|
||||
let s = string('~');
|
||||
assert_eq!(s, "~");
|
||||
let s = string('é');
|
||||
assert_eq!(s, "\\u{e9}");
|
||||
let s = string('\x00');
|
||||
assert_eq!(s, "\\u{0}");
|
||||
let s = string('\x1f');
|
||||
assert_eq!(s, "\\u{1f}");
|
||||
let s = string('\x7f');
|
||||
assert_eq!(s, "\\u{7f}");
|
||||
let s = string('\u{80}');
|
||||
assert_eq!(s, "\\u{80}");
|
||||
let s = string('\u{ff}');
|
||||
assert_eq!(s, "\\u{ff}");
|
||||
let s = string('\u{11b}');
|
||||
assert_eq!(s, "\\u{11b}");
|
||||
let s = string('\u{1d4b6}');
|
||||
assert_eq!(s, "\\u{1d4b6}");
|
||||
let s = string('\u{200b}'); // zero width space
|
||||
assert_eq!(s, "\\u{200b}");
|
||||
let s = string('\u{e000}'); // private use 1
|
||||
assert_eq!(s, "\\u{e000}");
|
||||
let s = string('\u{100000}'); // private use 2
|
||||
assert_eq!(s, "\\u{100000}");
|
||||
assert_eq!(string('\n'), "\\n");
|
||||
assert_eq!(string('\r'), "\\r");
|
||||
assert_eq!(string('\''), "\\'");
|
||||
assert_eq!(string('"'), "\\\"");
|
||||
assert_eq!(string(' '), " ");
|
||||
assert_eq!(string('a'), "a");
|
||||
assert_eq!(string('~'), "~");
|
||||
assert_eq!(string('é'), "\\u{e9}");
|
||||
assert_eq!(string('\x00'), "\\u{0}");
|
||||
assert_eq!(string('\x1f'), "\\u{1f}");
|
||||
assert_eq!(string('\x7f'), "\\u{7f}");
|
||||
assert_eq!(string('\u{80}'), "\\u{80}");
|
||||
assert_eq!(string('\u{ff}'), "\\u{ff}");
|
||||
assert_eq!(string('\u{11b}'), "\\u{11b}");
|
||||
assert_eq!(string('\u{1d4b6}'), "\\u{1d4b6}");
|
||||
assert_eq!(string('\u{200b}'), "\\u{200b}"); // zero width space
|
||||
assert_eq!(string('\u{e000}'), "\\u{e000}"); // private use 1
|
||||
assert_eq!(string('\u{100000}'), "\\u{100000}"); // private use 2
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_escape_unicode() {
|
||||
fn string(c: char) -> String { c.escape_unicode().collect() }
|
||||
fn string(c: char) -> String {
|
||||
let iter: String = c.escape_unicode().collect();
|
||||
let disp: String = c.escape_unicode().to_string();
|
||||
assert_eq!(iter, disp);
|
||||
iter
|
||||
}
|
||||
|
||||
let s = string('\x00');
|
||||
assert_eq!(s, "\\u{0}");
|
||||
let s = string('\n');
|
||||
assert_eq!(s, "\\u{a}");
|
||||
let s = string(' ');
|
||||
assert_eq!(s, "\\u{20}");
|
||||
let s = string('a');
|
||||
assert_eq!(s, "\\u{61}");
|
||||
let s = string('\u{11b}');
|
||||
assert_eq!(s, "\\u{11b}");
|
||||
let s = string('\u{1d4b6}');
|
||||
assert_eq!(s, "\\u{1d4b6}");
|
||||
assert_eq!(string('\x00'), "\\u{0}");
|
||||
assert_eq!(string('\n'), "\\u{a}");
|
||||
assert_eq!(string(' '), "\\u{20}");
|
||||
assert_eq!(string('a'), "\\u{61}");
|
||||
assert_eq!(string('\u{11b}'), "\\u{11b}");
|
||||
assert_eq!(string('\u{1d4b6}'), "\\u{1d4b6}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
|||
|
|
@ -614,6 +614,14 @@ fn test_iterator_sum() {
|
|||
assert_eq!(v[..0].iter().cloned().sum::<i32>(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_iterator_sum_result() {
|
||||
let v: &[Result<i32, ()>] = &[Ok(1), Ok(2), Ok(3), Ok(4)];
|
||||
assert_eq!(v.iter().cloned().sum::<Result<i32, _>>(), Ok(10));
|
||||
let v: &[Result<i32, ()>] = &[Ok(1), Err(()), Ok(3), Ok(4)];
|
||||
assert_eq!(v.iter().cloned().sum::<Result<i32, _>>(), Err(()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_iterator_product() {
|
||||
let v: &[i32] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
|
||||
|
|
@ -622,6 +630,14 @@ fn test_iterator_product() {
|
|||
assert_eq!(v[..0].iter().cloned().product::<i32>(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_iterator_product_result() {
|
||||
let v: &[Result<i32, ()>] = &[Ok(1), Ok(2), Ok(3), Ok(4)];
|
||||
assert_eq!(v.iter().cloned().product::<Result<i32, _>>(), Ok(24));
|
||||
let v: &[Result<i32, ()>] = &[Ok(1), Err(()), Ok(3), Ok(4)];
|
||||
assert_eq!(v.iter().cloned().product::<Result<i32, _>>(), Err(()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_iterator_max() {
|
||||
let v: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
#![feature(nonzero)]
|
||||
#![feature(rand)]
|
||||
#![feature(raw)]
|
||||
#![feature(result_expect_err)]
|
||||
#![feature(sip_hash_13)]
|
||||
#![feature(slice_patterns)]
|
||||
#![feature(step_by)]
|
||||
|
|
|
|||
|
|
@ -151,6 +151,19 @@ pub fn test_expect_err() {
|
|||
err.expect("Got expected error");
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
pub fn test_expect_err_err() {
|
||||
let ok: Result<&'static str, isize> = Err(100);
|
||||
assert_eq!(ok.expect_err("Unexpected ok"), 100);
|
||||
}
|
||||
#[test]
|
||||
#[should_panic(expected="Got expected ok: \"All good\"")]
|
||||
pub fn test_expect_err_ok() {
|
||||
let err: Result<&'static str, isize> = Ok("All good");
|
||||
err.expect_err("Got expected ok");
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_iter() {
|
||||
let ok: Result<isize, &'static str> = Ok(100);
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@
|
|||
html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
|
||||
html_root_url = "https://doc.rust-lang.org/nightly/",
|
||||
test(attr(deny(warnings))))]
|
||||
#![cfg_attr(not(stage0), deny(warnings))]
|
||||
#![deny(warnings)]
|
||||
|
||||
#![feature(libc)]
|
||||
#![feature(staged_api)]
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@
|
|||
html_root_url = "https://doc.rust-lang.org/nightly/",
|
||||
html_playground_url = "https://play.rust-lang.org/",
|
||||
test(attr(deny(warnings))))]
|
||||
#![cfg_attr(not(stage0), deny(warnings))]
|
||||
#![deny(warnings)]
|
||||
|
||||
#![feature(staged_api)]
|
||||
#![feature(unicode)]
|
||||
|
|
|
|||
|
|
@ -90,6 +90,7 @@
|
|||
test(attr(deny(warnings))))]
|
||||
|
||||
#![deny(missing_docs)]
|
||||
#![deny(warnings)]
|
||||
#![feature(staged_api)]
|
||||
|
||||
use self::Name::*;
|
||||
|
|
@ -968,7 +969,6 @@ fn test_split_within() {
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use super::Fail::*;
|
||||
|
||||
use std::result::Result::{Err, Ok};
|
||||
use std::result;
|
||||
|
|
|
|||
|
|
@ -292,7 +292,7 @@
|
|||
html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
|
||||
html_root_url = "https://doc.rust-lang.org/nightly/",
|
||||
test(attr(allow(unused_variables), deny(warnings))))]
|
||||
#![cfg_attr(not(stage0), deny(warnings))]
|
||||
#![deny(warnings)]
|
||||
|
||||
#![feature(str_escape)]
|
||||
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit 98589876259e19f13eab81b033ced95bbb6deca0
|
||||
Subproject commit 7d57bdcdbb56540f37afe5a934ce12d33a6ca7fc
|
||||
|
|
@ -168,7 +168,7 @@
|
|||
html_playground_url = "https://play.rust-lang.org/",
|
||||
test(attr(deny(warnings))))]
|
||||
#![deny(missing_docs)]
|
||||
#![cfg_attr(not(stage0), deny(warnings))]
|
||||
#![deny(warnings)]
|
||||
|
||||
#![feature(staged_api)]
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@
|
|||
html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
|
||||
html_root_url = "https://doc.rust-lang.org/nightly/",
|
||||
issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/")]
|
||||
#![cfg_attr(not(stage0), deny(warnings))]
|
||||
#![deny(warnings)]
|
||||
|
||||
#![feature(staged_api)]
|
||||
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@
|
|||
html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
|
||||
html_root_url = "https://doc.rust-lang.org/nightly/",
|
||||
issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/")]
|
||||
#![cfg_attr(not(stage0), deny(warnings))]
|
||||
#![deny(warnings)]
|
||||
|
||||
#![feature(alloc)]
|
||||
#![feature(core_intrinsics)]
|
||||
|
|
|
|||
|
|
@ -15,22 +15,19 @@
|
|||
//! Currently the primary use of this crate is to provide the ability to define
|
||||
//! new custom derive modes through `#[proc_macro_derive]`.
|
||||
//!
|
||||
//! Added recently as part of [RFC 1681] this crate is currently *unstable* and
|
||||
//! requires the `#![feature(proc_macro_lib)]` directive to use.
|
||||
//!
|
||||
//! [RFC 1681]: https://github.com/rust-lang/rfcs/blob/master/text/1681-macros-1.1.md
|
||||
//!
|
||||
//! Note that this crate is intentionally very bare-bones currently. The main
|
||||
//! type, `TokenStream`, only supports `fmt::Display` and `FromStr`
|
||||
//! implementations, indicating that it can only go to and come from a string.
|
||||
//! This functionality is intended to be expanded over time as more surface
|
||||
//! area for macro authors is stabilized.
|
||||
//!
|
||||
//! See [the book](../../book/procedural-macros.html) for more.
|
||||
|
||||
#![crate_name = "proc_macro"]
|
||||
#![unstable(feature = "proc_macro_lib", issue = "27812")]
|
||||
#![stable(feature = "proc_macro_lib", since = "1.15.0")]
|
||||
#![crate_type = "rlib"]
|
||||
#![crate_type = "dylib"]
|
||||
#![cfg_attr(not(stage0), deny(warnings))]
|
||||
#![deny(warnings)]
|
||||
#![deny(missing_docs)]
|
||||
|
||||
#![feature(rustc_private)]
|
||||
|
|
@ -55,12 +52,14 @@ use syntax::ptr::P;
|
|||
///
|
||||
/// The API of this type is intentionally bare-bones, but it'll be expanded over
|
||||
/// time!
|
||||
#[stable(feature = "proc_macro_lib", since = "1.15.0")]
|
||||
pub struct TokenStream {
|
||||
inner: Vec<P<ast::Item>>,
|
||||
}
|
||||
|
||||
/// Error returned from `TokenStream::from_str`.
|
||||
#[derive(Debug)]
|
||||
#[stable(feature = "proc_macro_lib", since = "1.15.0")]
|
||||
pub struct LexError {
|
||||
_inner: (),
|
||||
}
|
||||
|
|
@ -131,6 +130,7 @@ pub mod __internal {
|
|||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "proc_macro_lib", since = "1.15.0")]
|
||||
impl FromStr for TokenStream {
|
||||
type Err = LexError;
|
||||
|
||||
|
|
@ -154,6 +154,7 @@ impl FromStr for TokenStream {
|
|||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "proc_macro_lib", since = "1.15.0")]
|
||||
impl fmt::Display for TokenStream {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
for item in self.inner.iter() {
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@
|
|||
#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
|
||||
html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
|
||||
html_root_url = "https://doc.rust-lang.org/nightly/")]
|
||||
#![cfg_attr(not(stage0), deny(warnings))]
|
||||
#![deny(warnings)]
|
||||
|
||||
#![feature(staged_api)]
|
||||
#![feature(rustc_diagnostic_macros)]
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@
|
|||
#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
|
||||
html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
|
||||
html_root_url = "https://doc.rust-lang.org/nightly/")]
|
||||
#![cfg_attr(not(stage0), deny(warnings))]
|
||||
#![deny(warnings)]
|
||||
|
||||
#![feature(staged_api)]
|
||||
#![feature(rustc_private)]
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@
|
|||
html_root_url = "https://doc.rust-lang.org/nightly/",
|
||||
html_playground_url = "https://play.rust-lang.org/",
|
||||
test(attr(deny(warnings))))]
|
||||
#![cfg_attr(not(stage0), deny(warnings))]
|
||||
#![deny(warnings)]
|
||||
#![no_std]
|
||||
#![unstable(feature = "rand",
|
||||
reason = "use `rand` from crates.io",
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ use hir::{self, PatKind};
|
|||
|
||||
struct CFGBuilder<'a, 'tcx: 'a> {
|
||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
tables: &'a ty::Tables<'tcx>,
|
||||
graph: CFGGraph,
|
||||
fn_exit: CFGIndex,
|
||||
loop_scopes: Vec<LoopScope>,
|
||||
|
|
@ -42,10 +43,23 @@ pub fn construct<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||
let fn_exit = graph.add_node(CFGNodeData::Exit);
|
||||
let body_exit;
|
||||
|
||||
// Find the function this expression is from.
|
||||
let mut node_id = body.id;
|
||||
loop {
|
||||
let node = tcx.map.get(node_id);
|
||||
if hir::map::blocks::FnLikeNode::from_node(node).is_some() {
|
||||
break;
|
||||
}
|
||||
let parent = tcx.map.get_parent_node(node_id);
|
||||
assert!(node_id != parent);
|
||||
node_id = parent;
|
||||
}
|
||||
|
||||
let mut cfg_builder = CFGBuilder {
|
||||
tcx: tcx,
|
||||
tables: tcx.item_tables(tcx.map.local_def_id(node_id)),
|
||||
graph: graph,
|
||||
fn_exit: fn_exit,
|
||||
tcx: tcx,
|
||||
loop_scopes: Vec::new()
|
||||
};
|
||||
body_exit = cfg_builder.expr(body, entry);
|
||||
|
|
@ -310,11 +324,11 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
|
|||
}
|
||||
|
||||
hir::ExprIndex(ref l, ref r) |
|
||||
hir::ExprBinary(_, ref l, ref r) if self.tcx.tables().is_method_call(expr.id) => {
|
||||
hir::ExprBinary(_, ref l, ref r) if self.tables.is_method_call(expr.id) => {
|
||||
self.call(expr, pred, &l, Some(&**r).into_iter())
|
||||
}
|
||||
|
||||
hir::ExprUnary(_, ref e) if self.tcx.tables().is_method_call(expr.id) => {
|
||||
hir::ExprUnary(_, ref e) if self.tables.is_method_call(expr.id) => {
|
||||
self.call(expr, pred, &e, None::<hir::Expr>.iter())
|
||||
}
|
||||
|
||||
|
|
@ -368,9 +382,9 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
|
|||
func_or_rcvr: &hir::Expr,
|
||||
args: I) -> CFGIndex {
|
||||
let method_call = ty::MethodCall::expr(call_expr.id);
|
||||
let fn_ty = match self.tcx.tables().method_map.get(&method_call) {
|
||||
let fn_ty = match self.tables.method_map.get(&method_call) {
|
||||
Some(method) => method.ty,
|
||||
None => self.tcx.tables().expr_ty_adjusted(func_or_rcvr)
|
||||
None => self.tables.expr_ty_adjusted(func_or_rcvr)
|
||||
};
|
||||
|
||||
let func_or_rcvr_exit = self.expr(func_or_rcvr, pred);
|
||||
|
|
|
|||
|
|
@ -113,6 +113,7 @@ pub enum DepNode<D: Clone + Debug> {
|
|||
SizedConstraint(D),
|
||||
AssociatedItemDefIds(D),
|
||||
InherentImpls(D),
|
||||
Tables(D),
|
||||
|
||||
// The set of impls for a given trait. Ultimately, it would be
|
||||
// nice to get more fine-grained here (e.g., to include a
|
||||
|
|
@ -162,6 +163,7 @@ impl<D: Clone + Debug> DepNode<D> {
|
|||
ItemSignature,
|
||||
AssociatedItemDefIds,
|
||||
InherentImpls,
|
||||
Tables,
|
||||
TraitImpls,
|
||||
ReprHints,
|
||||
}
|
||||
|
|
@ -230,6 +232,7 @@ impl<D: Clone + Debug> DepNode<D> {
|
|||
SizedConstraint(ref d) => op(d).map(SizedConstraint),
|
||||
AssociatedItemDefIds(ref d) => op(d).map(AssociatedItemDefIds),
|
||||
InherentImpls(ref d) => op(d).map(InherentImpls),
|
||||
Tables(ref d) => op(d).map(Tables),
|
||||
TraitImpls(ref d) => op(d).map(TraitImpls),
|
||||
TraitItems(ref d) => op(d).map(TraitItems),
|
||||
ReprHints(ref d) => op(d).map(ReprHints),
|
||||
|
|
|
|||
|
|
@ -45,15 +45,6 @@ pub struct FnLikeNode<'a> { node: map::Node<'a> }
|
|||
/// corresponds to some FnLikeNode.
|
||||
pub trait MaybeFnLike { fn is_fn_like(&self) -> bool; }
|
||||
|
||||
/// Components shared by fn-like things (fn items, methods, closures).
|
||||
pub struct FnParts<'a> {
|
||||
pub decl: &'a FnDecl,
|
||||
pub body: ast::BodyId,
|
||||
pub kind: FnKind<'a>,
|
||||
pub span: Span,
|
||||
pub id: NodeId,
|
||||
}
|
||||
|
||||
impl MaybeFnLike for ast::Item {
|
||||
fn is_fn_like(&self) -> bool {
|
||||
match self.node { ast::ItemFn(..) => true, _ => false, }
|
||||
|
|
@ -165,16 +156,6 @@ impl<'a> FnLikeNode<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn to_fn_parts(self) -> FnParts<'a> {
|
||||
FnParts {
|
||||
decl: self.decl(),
|
||||
body: self.body(),
|
||||
kind: self.kind(),
|
||||
span: self.span(),
|
||||
id: self.id(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn body(self) -> ast::BodyId {
|
||||
self.handle(|i: ItemFnParts<'a>| i.body,
|
||||
|_, _, _: &'a ast::MethodSig, _, body: ast::BodyId, _, _| body,
|
||||
|
|
|
|||
|
|
@ -23,10 +23,6 @@ pub struct NodeCollector<'ast> {
|
|||
pub(super) map: Vec<MapEntry<'ast>>,
|
||||
/// The parent of this node
|
||||
pub parent_node: NodeId,
|
||||
/// If true, completely ignore nested items. We set this when loading
|
||||
/// HIR from metadata, since in that case we only want the HIR for
|
||||
/// one specific item (and not the ones nested inside of it).
|
||||
pub ignore_nested_items: bool
|
||||
}
|
||||
|
||||
impl<'ast> NodeCollector<'ast> {
|
||||
|
|
@ -35,30 +31,12 @@ impl<'ast> NodeCollector<'ast> {
|
|||
krate: krate,
|
||||
map: vec![],
|
||||
parent_node: CRATE_NODE_ID,
|
||||
ignore_nested_items: false
|
||||
};
|
||||
collector.insert_entry(CRATE_NODE_ID, RootCrate);
|
||||
|
||||
collector
|
||||
}
|
||||
|
||||
pub(super) fn extend(krate: &'ast Crate,
|
||||
parent: &'ast InlinedItem,
|
||||
parent_node: NodeId,
|
||||
map: Vec<MapEntry<'ast>>)
|
||||
-> NodeCollector<'ast> {
|
||||
let mut collector = NodeCollector {
|
||||
krate: krate,
|
||||
map: map,
|
||||
parent_node: parent_node,
|
||||
ignore_nested_items: true
|
||||
};
|
||||
|
||||
collector.insert_entry(parent_node, RootInlinedParent(parent));
|
||||
|
||||
collector
|
||||
}
|
||||
|
||||
fn insert_entry(&mut self, id: NodeId, entry: MapEntry<'ast>) {
|
||||
debug!("ast_map: {:?} => {:?}", id, entry);
|
||||
let len = self.map.len();
|
||||
|
|
@ -92,27 +70,19 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> {
|
|||
|
||||
fn visit_nested_item(&mut self, item: ItemId) {
|
||||
debug!("visit_nested_item: {:?}", item);
|
||||
if !self.ignore_nested_items {
|
||||
self.visit_item(self.krate.item(item.id))
|
||||
}
|
||||
self.visit_item(self.krate.item(item.id));
|
||||
}
|
||||
|
||||
fn visit_nested_trait_item(&mut self, item_id: TraitItemId) {
|
||||
if !self.ignore_nested_items {
|
||||
self.visit_trait_item(self.krate.trait_item(item_id))
|
||||
}
|
||||
self.visit_trait_item(self.krate.trait_item(item_id));
|
||||
}
|
||||
|
||||
fn visit_nested_impl_item(&mut self, item_id: ImplItemId) {
|
||||
if !self.ignore_nested_items {
|
||||
self.visit_impl_item(self.krate.impl_item(item_id))
|
||||
}
|
||||
self.visit_impl_item(self.krate.impl_item(item_id));
|
||||
}
|
||||
|
||||
fn visit_nested_body(&mut self, id: BodyId) {
|
||||
if !self.ignore_nested_items {
|
||||
self.visit_body(self.krate.body(id))
|
||||
}
|
||||
self.visit_body(self.krate.body(id));
|
||||
}
|
||||
|
||||
fn visit_item(&mut self, i: &'ast Item) {
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue