Merge branch 'master' into lint-attr-fix

This commit is contained in:
comex 2017-01-14 18:04:27 -05:00
commit 9cfb8b730a
577 changed files with 9617 additions and 5582 deletions

13
.gitignore vendored
View file

@ -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/

View file

@ -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>

View file

@ -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

View file

@ -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

View file

@ -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
View file

@ -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"

View file

@ -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
View file

@ -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",

View file

@ -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" }

View file

@ -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):

View file

@ -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);
}

View file

@ -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));
}

View file

@ -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())

View file

@ -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

View file

@ -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) {

View file

@ -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)
}

View file

@ -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"),
}
}

View file

@ -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
}

View file

@ -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")));
}
}

View file

@ -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

View file

@ -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 "$@"

View file

@ -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 \

View 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

View file

@ -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

View file

@ -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 \

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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.

View file

@ -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 () {}

View file

@ -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() }
}
```

View 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!

View file

@ -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

View file

@ -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

View file

@ -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);

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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

View file

@ -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;

View file

@ -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)]

View file

@ -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>();

View file

@ -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;

View file

@ -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)]

View file

@ -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",

View file

@ -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.

View file

@ -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,
})
}
}

View file

@ -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 {

View file

@ -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)]

View file

@ -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() {}
}

View file

@ -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.

View file

@ -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
}
}

View file

@ -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) {

View file

@ -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]);

View file

@ -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)]

View file

@ -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");

View file

@ -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(|| {

View file

@ -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"]);

View file

@ -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")]

View file

@ -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

View file

@ -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`.

View file

@ -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
///

View file

@ -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

View file

@ -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)]

View file

@ -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"))
);

View file

@ -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`?
///

View file

@ -14,4 +14,4 @@
#![unstable(feature = "i128", issue="35118")]
int_module! { i128 }
int_module! { i128, #[unstable(feature = "i128", issue="35118")] }

View file

@ -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();
)
}

View file

@ -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")] }

View file

@ -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();
)
}

View file

@ -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> {

View file

@ -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) {

View file

@ -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> {

View file

@ -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")]

View file

@ -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'), "");
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]

View file

@ -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];

View file

@ -23,6 +23,7 @@
#![feature(nonzero)]
#![feature(rand)]
#![feature(raw)]
#![feature(result_expect_err)]
#![feature(sip_hash_13)]
#![feature(slice_patterns)]
#![feature(step_by)]

View file

@ -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);

View file

@ -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)]

View file

@ -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)]

View file

@ -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;

View file

@ -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

View file

@ -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)]

View file

@ -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)]

View file

@ -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)]

View file

@ -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() {

View file

@ -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)]

View file

@ -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)]

View file

@ -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",

View file

@ -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);

View file

@ -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),

View file

@ -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,

View file

@ -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